mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Merge pull request #1237 from Subv/ubos
Shaders: Use UBOs instead of individual uniforms in the generated frag shaders
This commit is contained in:
		
						commit
						ac829f87e0
					
				
					 6 changed files with 67 additions and 13 deletions
				
			
		|  | @ -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(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -141,12 +141,9 @@ public: | ||||||
| 
 | 
 | ||||||
|         /// Fragment shader uniforms
 |         /// Fragment shader uniforms
 | ||||||
|         enum Uniform : GLuint { |         enum Uniform : GLuint { | ||||||
|             AlphaTestRef = 0, |             Texture0 = 0, | ||||||
|             TevConstColors = 1, |             Texture1 = 1, | ||||||
|             Texture0 = 7, |             Texture2 = 2, | ||||||
|             Texture1 = 8, |  | ||||||
|             Texture2 = 9, |  | ||||||
|             TevCombinerBufferColor = 10, |  | ||||||
|         }; |         }; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  | @ -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; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -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"; | ||||||
|  |  | ||||||
|  | @ -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) { | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  |  | ||||||
|  | @ -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
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue