Parcourir la source

FragShader: Use an UBO instead of several individual uniforms

Subv il y a 10 ans
Parent
commit
823ce62f2f

+ 29 - 4
src/video_core/renderer_opengl/gl_rasterizer.cpp

@@ -46,14 +46,21 @@ void RasterizerOpenGL::InitObjects() {
         state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
         state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
     }
     }
 
 
-    // Generate VBO and VAO
+    // Generate VBO, VAO and UBO
     vertex_buffer.Create();
     vertex_buffer.Create();
     vertex_array.Create();
     vertex_array.Create();
+    uniform_buffer.Create();
 
 
     state.draw.vertex_array = vertex_array.handle;
     state.draw.vertex_array = vertex_array.handle;
     state.draw.vertex_buffer = vertex_buffer.handle;
     state.draw.vertex_buffer = vertex_buffer.handle;
+    state.draw.uniform_buffer = uniform_buffer.handle;
     state.Apply();
     state.Apply();
 
 
+    // Bind the UBO to binding point 0
+    glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniform_buffer.handle);
+
+    uniform_block_data.dirty = true;
+
     // Set vertex attributes
     // Set vertex attributes
     glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position));
     glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position));
     glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION);
     glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION);
@@ -148,6 +155,11 @@ void RasterizerOpenGL::DrawTriangles() {
         state.draw.shader_dirty = false;
         state.draw.shader_dirty = false;
     }
     }
 
 
+    if (uniform_block_data.dirty) {
+        glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data, GL_STATIC_DRAW);
+        uniform_block_data.dirty = false;
+    }
+
     glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW);
     glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW);
     glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size());
     glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size());
 
 
@@ -485,6 +497,9 @@ void RasterizerOpenGL::SetShader() {
         glUniform1i(PicaShader::Uniform::Texture2, 2);
         glUniform1i(PicaShader::Uniform::Texture2, 2);
 
 
         current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get();
         current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get();
+
+        unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data");
+        glUniformBlockBinding(current_shader->shader.handle, block_index, 0);
     }
     }
 
 
     // Update uniforms
     // Update uniforms
@@ -615,7 +630,10 @@ void RasterizerOpenGL::SyncBlendColor() {
 
 
 void RasterizerOpenGL::SyncAlphaTest() {
 void RasterizerOpenGL::SyncAlphaTest() {
     const auto& regs = Pica::g_state.regs;
     const auto& regs = Pica::g_state.regs;
-    glUniform1i(PicaShader::Uniform::AlphaTestRef, regs.output_merger.alpha_test.ref);
+    if (regs.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) {
+        uniform_block_data.data.alphatest_ref = regs.output_merger.alpha_test.ref;
+        uniform_block_data.dirty = true;
+    }
 }
 }
 
 
 void RasterizerOpenGL::SyncLogicOp() {
 void RasterizerOpenGL::SyncLogicOp() {
@@ -647,12 +665,18 @@ void RasterizerOpenGL::SyncDepthTest() {
 
 
 void RasterizerOpenGL::SyncCombinerColor() {
 void RasterizerOpenGL::SyncCombinerColor() {
     auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw);
     auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw);
-    glUniform4fv(PicaShader::Uniform::TevCombinerBufferColor, 1, combiner_color.data());
+    if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) {
+        uniform_block_data.data.tev_combiner_buffer_color = combiner_color;
+        uniform_block_data.dirty = true;
+    }
 }
 }
 
 
 void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevStageConfig& tev_stage) {
 void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevStageConfig& tev_stage) {
     auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color);
     auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color);
-    glUniform4fv(PicaShader::Uniform::TevConstColors + stage_index, 1, const_color.data());
+    if (const_color != uniform_block_data.data.const_color[stage_index]) {
+        uniform_block_data.data.const_color[stage_index] = const_color;
+        uniform_block_data.dirty = true;
+    }
 }
 }
 
 
 void RasterizerOpenGL::SyncDrawState() {
 void RasterizerOpenGL::SyncDrawState() {
@@ -683,6 +707,7 @@ void RasterizerOpenGL::SyncDrawState() {
         }
         }
     }
     }
 
 
+    state.draw.uniform_buffer = uniform_buffer.handle;
     state.Apply();
     state.Apply();
 }
 }
 
 

+ 21 - 6
src/video_core/renderer_opengl/gl_rasterizer.h

@@ -141,12 +141,9 @@ public:
 
 
         /// Fragment shader uniforms
         /// Fragment shader uniforms
         enum Uniform : GLuint {
         enum Uniform : GLuint {
-            AlphaTestRef = 0,
-            TevConstColors = 1,
-            Texture0 = 7,
-            Texture1 = 8,
-            Texture2 = 9,
-            TevCombinerBufferColor = 10,
+            Texture0 = 0,
+            Texture1 = 1,
+            Texture2 = 2,
         };
         };
     };
     };
 
 
@@ -216,6 +213,18 @@ private:
         GLfloat tex_coord2[2];
         GLfloat tex_coord2[2];
     };
     };
 
 
+    /// Uniform structure for the Uniform Buffer Object, all members must be 16-byte aligned
+    struct UniformData {
+        // A vec4 color for each of the six tev stages
+        std::array<GLfloat, 4> const_color[6];
+        std::array<GLfloat, 4> tev_combiner_buffer_color;
+        GLint alphatest_ref;
+        INSERT_PADDING_BYTES(12);
+    };
+
+    static_assert(sizeof(UniformData) == 0x80, "The size of the UniformData structure has changed, update the structure in the shader");
+    static_assert(sizeof(UniformData) < 16000, "UniformData structure must be less than 16kb as per the OpenGL spec");
+
     /// Reconfigure the OpenGL color texture to use the given format and dimensions
     /// Reconfigure the OpenGL color texture to use the given format and dimensions
     void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height);
     void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height);
 
 
@@ -298,7 +307,13 @@ private:
     std::unordered_map<PicaShaderConfig, std::unique_ptr<PicaShader>> shader_cache;
     std::unordered_map<PicaShaderConfig, std::unique_ptr<PicaShader>> shader_cache;
     const PicaShader* current_shader = nullptr;
     const PicaShader* current_shader = nullptr;
 
 
+    struct {
+        UniformData data;
+        bool dirty;
+    } uniform_block_data;
+
     OGLVertexArray vertex_array;
     OGLVertexArray vertex_array;
     OGLBuffer vertex_buffer;
     OGLBuffer vertex_buffer;
+    OGLBuffer uniform_buffer;
     OGLFramebuffer framebuffer;
     OGLFramebuffer framebuffer;
 };
 };

+ 7 - 3
src/video_core/renderer_opengl/gl_shader_gen.cpp

@@ -329,13 +329,17 @@ in vec4 primary_color;
 in vec2 texcoord[3];
 in vec2 texcoord[3];
 
 
 out vec4 color;
 out vec4 color;
+
+layout (std140) uniform shader_data {
+    vec4 const_color[NUM_TEV_STAGES];
+    vec4 tev_combiner_buffer_color;
+    int alphatest_ref;
+};
+
 )";
 )";
 
 
     using Uniform = RasterizerOpenGL::PicaShader::Uniform;
     using Uniform = RasterizerOpenGL::PicaShader::Uniform;
-    out += "layout(location = " + std::to_string((int)Uniform::AlphaTestRef) + ") uniform int alphatest_ref;\n";
-    out += "layout(location = " + std::to_string((int)Uniform::TevConstColors) + ") uniform vec4 const_color[NUM_TEV_STAGES];\n";
     out += "layout(location = " + std::to_string((int)Uniform::Texture0) + ") uniform sampler2D tex[3];\n";
     out += "layout(location = " + std::to_string((int)Uniform::Texture0) + ") uniform sampler2D tex[3];\n";
-    out += "layout(location = " + std::to_string((int)Uniform::TevCombinerBufferColor) + ") uniform vec4 tev_combiner_buffer_color;\n";
 
 
     out += "void main() {\n";
     out += "void main() {\n";
     out += "vec4 combiner_buffer = tev_combiner_buffer_color;\n";
     out += "vec4 combiner_buffer = tev_combiner_buffer_color;\n";

+ 8 - 0
src/video_core/renderer_opengl/gl_state.cpp

@@ -180,6 +180,11 @@ void OpenGLState::Apply() {
         glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer);
         glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer);
     }
     }
 
 
+    // Uniform buffer
+    if (draw.uniform_buffer != cur_state.draw.uniform_buffer) {
+        glBindBuffer(GL_UNIFORM_BUFFER, draw.uniform_buffer);
+    }
+
     // Shader program
     // Shader program
     if (draw.shader_program != cur_state.draw.shader_program) {
     if (draw.shader_program != cur_state.draw.shader_program) {
         glUseProgram(draw.shader_program);
         glUseProgram(draw.shader_program);
@@ -214,6 +219,9 @@ void OpenGLState::ResetBuffer(GLuint id) {
     if (cur_state.draw.vertex_buffer == id) {
     if (cur_state.draw.vertex_buffer == id) {
         cur_state.draw.vertex_buffer = 0;
         cur_state.draw.vertex_buffer = 0;
     }
     }
+    if (cur_state.draw.uniform_buffer == id) {
+        cur_state.draw.uniform_buffer = 0;
+    }
 }
 }
 
 
 void OpenGLState::ResetVertexArray(GLuint id) {
 void OpenGLState::ResetVertexArray(GLuint id) {

+ 1 - 0
src/video_core/renderer_opengl/gl_state.h

@@ -64,6 +64,7 @@ public:
         GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING
         GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING
         GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING
         GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING
         GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING
         GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING
+        GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING
         GLuint shader_program; // GL_CURRENT_PROGRAM
         GLuint shader_program; // GL_CURRENT_PROGRAM
         bool shader_dirty;
         bool shader_dirty;
     } draw;
     } draw;

+ 1 - 0
src/video_core/renderer_opengl/renderer_opengl.cpp

@@ -256,6 +256,7 @@ void RendererOpenGL::InitOpenGLObjects() {
 
 
     state.draw.vertex_array = vertex_array_handle;
     state.draw.vertex_array = vertex_array_handle;
     state.draw.vertex_buffer = vertex_buffer_handle;
     state.draw.vertex_buffer = vertex_buffer_handle;
+    state.draw.uniform_buffer = 0;
     state.Apply();
     state.Apply();
 
 
     // Attach vertex data to VAO
     // Attach vertex data to VAO