From 8b0b1939cfd9a74fa4edd7235b9e1444919b8ae2 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Fri, 25 Jul 2025 01:24:23 +0300 Subject: [PATCH] GL: Respect minimum UBO alignment requirement (#794) * GL: Respect minimum UBO alignment requirement * Use glBindBufferRange for UBOs * Fix fragment shadergen UBO bindings * Nit --- include/renderer_gl/gl_driver.hpp | 4 ++++ include/renderer_gl/renderer_gl.hpp | 3 +++ src/core/renderer_gl/renderer_gl.cpp | 32 ++++++++++++++++++++-------- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/include/renderer_gl/gl_driver.hpp b/include/renderer_gl/gl_driver.hpp index 4a0b3727..dfb78ffe 100644 --- a/include/renderer_gl/gl_driver.hpp +++ b/include/renderer_gl/gl_driver.hpp @@ -1,4 +1,5 @@ #pragma once +#include "opengl.hpp" // Information about our OpenGL/OpenGL ES driver that we should keep track of // Stuff like whether specific extensions are supported, and potentially things like OpenGL context information @@ -8,6 +9,9 @@ namespace OpenGL { bool supportsExtFbFetch = false; bool supportsArmFbFetch = false; + // Minimum alignment for UBO offsets. Fetched by the OpenGL renderer using glGetIntegerV. + GLuint uboAlignment = 16; + bool supportFbFetch() const { return supportsExtFbFetch || supportsArmFbFetch; } }; } // namespace OpenGL \ No newline at end of file diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp index f5eaea84..4708fdee 100644 --- a/include/renderer_gl/renderer_gl.hpp +++ b/include/renderer_gl/renderer_gl.hpp @@ -101,6 +101,9 @@ class RendererGL final : public Renderer { std::unique_ptr hwVertexBuffer; std::unique_ptr hwIndexBuffer; + // Current offset for our hw shader uniform UBO + u32 hwShaderUniformUBOOffset = 0; + // Cache of fixed attribute values so that we don't do any duplicate updates std::array, 16> fixedAttrValues; diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 35a99bc4..8ab7f1df 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -2,6 +2,7 @@ #include +#include #include #include @@ -179,6 +180,10 @@ void RendererGL::initGraphicsContextInternal() { driverInfo.supportsExtFbFetch = (GLAD_GL_EXT_shader_framebuffer_fetch != 0); driverInfo.supportsArmFbFetch = (GLAD_GL_ARM_shader_framebuffer_fetch != 0); + // UBOs have an alignment requirement we have to respect + glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, reinterpret_cast(&driverInfo.uboAlignment)); + driverInfo.uboAlignment = std::max(driverInfo.uboAlignment, 16); + // Initialize the default vertex shader used with shadergen std::string defaultShadergenVSSource = fragShaderGen.getDefaultVertexShader(); defaultShadergenVs.create({defaultShadergenVSSource.c_str(), defaultShadergenVSSource.size()}, OpenGL::Vertex); @@ -930,11 +935,6 @@ OpenGL::Program& RendererGL::getSpecializedShader() { glUniformBlockBinding(program.handle(), vertexUBOIndex, vsUBOBlockBinding); } } - glBindBufferBase(GL_UNIFORM_BUFFER, fsUBOBlockBinding, shadergenFragmentUBO->GetGLBufferId()); - - if (usingAcceleratedShader) { - glBindBufferBase(GL_UNIFORM_BUFFER, vsUBOBlockBinding, hwShaderUniformUBO->GetGLBufferId()); - } // Upload uniform data to our shader's UBO PICA::FragmentUniforms uniforms; @@ -1020,10 +1020,21 @@ OpenGL::Program& RendererGL::getSpecializedShader() { // Upload fragment uniforms to UBO shadergenFragmentUBO->Bind(); - auto mapRes = shadergenFragmentUBO->Map(4, sizeof(PICA::FragmentUniforms)); - std::memcpy(mapRes.pointer, &uniforms, sizeof(PICA::FragmentUniforms)); + auto uboRes = shadergenFragmentUBO->Map(driverInfo.uboAlignment, sizeof(PICA::FragmentUniforms)); + std::memcpy(uboRes.pointer, &uniforms, sizeof(PICA::FragmentUniforms)); shadergenFragmentUBO->Unmap(sizeof(PICA::FragmentUniforms)); + // Bind our UBOs + glBindBufferRange( + GL_UNIFORM_BUFFER, fsUBOBlockBinding, shadergenFragmentUBO->GetGLBufferId(), uboRes.buffer_offset, sizeof(PICA::FragmentUniforms) + ); + + if (usingAcceleratedShader) { + glBindBufferRange( + GL_UNIFORM_BUFFER, vsUBOBlockBinding, hwShaderUniformUBO->GetGLBufferId(), hwShaderUniformUBOOffset, PICAShader::totalUniformSize() + ); + } + return program; } @@ -1074,11 +1085,14 @@ bool RendererGL::prepareForDraw(ShaderUnit& shaderUnit, PICA::DrawAcceleration* generatedVertexShader = &(*shader); hwShaderUniformUBO->Bind(); + // Upload shader uniforms to our UBO if (shaderUnit.vs.uniformsDirty) { shaderUnit.vs.uniformsDirty = false; - auto mapRes = hwShaderUniformUBO->Map(4, PICAShader::totalUniformSize()); - std::memcpy(mapRes.pointer, shaderUnit.vs.getUniformPointer(), PICAShader::totalUniformSize()); + auto uboRes = hwShaderUniformUBO->Map(driverInfo.uboAlignment, PICAShader::totalUniformSize()); + std::memcpy(uboRes.pointer, shaderUnit.vs.getUniformPointer(), PICAShader::totalUniformSize()); hwShaderUniformUBO->Unmap(PICAShader::totalUniformSize()); + + hwShaderUniformUBOOffset = uboRes.buffer_offset; } performIndexedRender = accel->indexed;