diff options
Diffstat (limited to 'src/video_core')
-rw-r--r-- | src/video_core/command_processor.cpp | 2 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 42 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 28 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 20 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 8 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 1 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 1 |
7 files changed, 75 insertions, 27 deletions
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 47afd8938..bd1b09a4b 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -157,6 +157,8 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { // TODO: What happens if a loader overwrites a previous one's data? for (unsigned component = 0; component < loader_config.component_count; ++component) { + if (component >= 12) + LOG_ERROR(HW_GPU, "Overflow in the vertex attribute loader %u trying to load component %u", loader, component); u32 attribute_index = loader_config.GetComponent(component); vertex_attribute_sources[attribute_index] = load_address; vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index d1def2f3b..822739088 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/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; } - // Generate VBO and VAO + // Generate VBO, VAO and UBO vertex_buffer.Create(); vertex_array.Create(); + uniform_buffer.Create(); state.draw.vertex_array = vertex_array.handle; state.draw.vertex_buffer = vertex_buffer.handle; + state.draw.uniform_buffer = uniform_buffer.handle; 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 glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION); @@ -148,6 +155,11 @@ void RasterizerOpenGL::DrawTriangles() { 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); glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size()); @@ -480,11 +492,17 @@ void RasterizerOpenGL::SetShader() { state.Apply(); // Set the texture samplers to correspond to different texture units - glUniform1i(PicaShader::Uniform::Texture0, 0); - glUniform1i(PicaShader::Uniform::Texture1, 1); - glUniform1i(PicaShader::Uniform::Texture2, 2); + GLuint uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[0]"); + if (uniform_tex != -1) { glUniform1i(uniform_tex, 0); } + uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[1]"); + if (uniform_tex != -1) { glUniform1i(uniform_tex, 1); } + uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]"); + if (uniform_tex != -1) { glUniform1i(uniform_tex, 2); } 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 @@ -615,7 +633,10 @@ void RasterizerOpenGL::SyncBlendColor() { void RasterizerOpenGL::SyncAlphaTest() { 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() { @@ -647,12 +668,18 @@ void RasterizerOpenGL::SyncDepthTest() { void RasterizerOpenGL::SyncCombinerColor() { 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) { 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() { @@ -683,6 +710,7 @@ void RasterizerOpenGL::SyncDrawState() { } } + state.draw.uniform_buffer = uniform_buffer.handle; state.Apply(); } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 872cae7da..5ba898189 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -138,16 +138,6 @@ public: struct PicaShader { /// OpenGL shader resource OGLShader shader; - - /// Fragment shader uniforms - enum Uniform : GLuint { - AlphaTestRef = 0, - TevConstColors = 1, - Texture0 = 7, - Texture1 = 8, - Texture2 = 9, - TevCombinerBufferColor = 10, - }; }; private: @@ -216,6 +206,18 @@ private: 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 void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height); @@ -298,7 +300,13 @@ private: std::unordered_map<PicaShaderConfig, std::unique_ptr<PicaShader>> shader_cache; const PicaShader* current_shader = nullptr; + struct { + UniformData data; + bool dirty; + } uniform_block_data; + OGLVertexArray vertex_array; OGLBuffer vertex_buffer; + OGLBuffer uniform_buffer; OGLFramebuffer framebuffer; }; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index d19d15e75..5268340cf 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -320,23 +320,23 @@ static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsi std::string GenerateFragmentShader(const PicaShaderConfig& config) { std::string out = R"( -#version 330 -#extension GL_ARB_explicit_uniform_location : require - +#version 330 core #define NUM_TEV_STAGES 6 in vec4 primary_color; in vec2 texcoord[3]; out vec4 color; -)"; - 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::TevCombinerBufferColor) + ") uniform vec4 tev_combiner_buffer_color;\n"; +layout (std140) uniform shader_data { + vec4 const_color[NUM_TEV_STAGES]; + vec4 tev_combiner_buffer_color; + int alphatest_ref; +}; + +)"; + out += "uniform sampler2D tex[3];\n"; out += "void main() {\n"; out += "vec4 combiner_buffer = tev_combiner_buffer_color;\n"; out += "vec4 last_tex_env_out = vec4(0.0);\n"; @@ -362,7 +362,7 @@ out vec4 color; } std::string GenerateVertexShader() { - std::string out = "#version 330\n"; + std::string out = "#version 330 core\n"; out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n"; out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n"; out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + ") in vec2 vert_texcoord0;\n"; diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 77b2816cb..c44497fc3 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -180,6 +180,11 @@ void OpenGLState::Apply() { 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 if (draw.shader_program != cur_state.draw.shader_program) { glUseProgram(draw.shader_program); @@ -214,6 +219,9 @@ void OpenGLState::ResetBuffer(GLuint id) { if (cur_state.draw.vertex_buffer == id) { cur_state.draw.vertex_buffer = 0; } + if (cur_state.draw.uniform_buffer == id) { + cur_state.draw.uniform_buffer = 0; + } } void OpenGLState::ResetVertexArray(GLuint id) { diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 668b04259..84b3d49bc 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -64,6 +64,7 @@ public: GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING + GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING GLuint shader_program; // GL_CURRENT_PROGRAM bool shader_dirty; } draw; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index ac0a058db..1420229cc 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/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_buffer = vertex_buffer_handle; + state.draw.uniform_buffer = 0; state.Apply(); // Attach vertex data to VAO |