From e9af70eaf3e9d190b2c75c039b004beb71f0e436 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 13 Nov 2015 22:52:20 -0500 Subject: [PATCH] renderer_opengl: Implement HW fragment lighting LUTs within our default UBO. --- src/video_core/pica.h | 2 +- .../renderer_opengl/gl_rasterizer.cpp | 63 +++++++++++++++---- .../renderer_opengl/gl_rasterizer.h | 9 ++- .../renderer_opengl/gl_shader_gen.cpp | 7 +++ 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/video_core/pica.h b/src/video_core/pica.h index b82ecf68aa..aad9effdc3 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -1216,7 +1216,7 @@ struct State { } }; - std::array luts[24]; + std::array, 24> luts; } lighting; /// Current Pica command list diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 1e51a76550..80693fa292 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -162,6 +162,13 @@ void RasterizerOpenGL::DrawTriangles() { state.draw.shader_dirty = false; } + for (unsigned index = 0; index < Pica::g_state.lighting.luts.size(); index++) { + if (uniform_block_data.lut_dirty[index]) { + SyncLightingLUT(index); + uniform_block_data.lut_dirty[index] = false; + } + } + if (uniform_block_data.dirty) { glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data, GL_STATIC_DRAW); uniform_block_data.dirty = false; @@ -381,6 +388,21 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { SyncGlobalAmbient(); break; + // Fragment lighting lookup tables + case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[0], 0x1c8): + case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[1], 0x1c9): + case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[2], 0x1ca): + case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[3], 0x1cb): + case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[4], 0x1cc): + case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[5], 0x1cd): + case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[6], 0x1ce): + case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf): + { + auto& lut_config = regs.lighting.lut_config; + uniform_block_data.lut_dirty[lut_config.type] = true; + break; + } + } } @@ -593,20 +615,23 @@ void RasterizerOpenGL::SetShader() { unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data"); glUniformBlockBinding(current_shader->shader.handle, block_index, 0); - } - // Update uniforms - SyncAlphaTest(); - SyncCombinerColor(); - auto& tev_stages = Pica::g_state.regs.GetTevStages(); - for (int index = 0; index < tev_stages.size(); ++index) - SyncTevConstColor(index, tev_stages[index]); + // Update uniforms + SyncAlphaTest(); + SyncCombinerColor(); + auto& tev_stages = Pica::g_state.regs.GetTevStages(); + for (int index = 0; index < tev_stages.size(); ++index) + SyncTevConstColor(index, tev_stages[index]); - SyncGlobalAmbient(); - for (int light_index = 0; light_index < 8; light_index++) { - SyncLightDiffuse(light_index); - SyncLightAmbient(light_index); - SyncLightPosition(light_index); + for (unsigned index = 0; index < Pica::g_state.lighting.luts.size(); ++index) + SyncLightingLUT(index); + + SyncGlobalAmbient(); + for (int light_index = 0; light_index < 8; light_index++) { + SyncLightDiffuse(light_index); + SyncLightAmbient(light_index); + SyncLightPosition(light_index); + } } } @@ -796,6 +821,20 @@ void RasterizerOpenGL::SyncGlobalAmbient() { } } +void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) { + auto& lut = uniform_block_data.data.lighting_lut[lut_index / 4]; + std::array, 256> new_lut; + + for (int offset = 0; offset < new_lut.size(); ++offset) { + new_lut[offset][lut_index & 3] = Pica::g_state.lighting.luts[lut_index][offset].ToFloat(); + } + + if (new_lut != lut) { + lut = new_lut; + uniform_block_data.dirty = true; + } +} + void RasterizerOpenGL::SyncLightDiffuse(int light_index) { auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].diffuse); if (color != uniform_block_data.data.light_src[light_index].diffuse) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 698ca5c4cc..fa4a78cb17 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -242,10 +242,11 @@ private: std::array lighting_global_ambient; INSERT_PADDING_WORDS(1); LightSrc light_src[8]; + std::array, 256>, 6> lighting_lut; }; - static_assert(sizeof(UniformData) == 0x210, "The size of the UniformData structure has changed, update the structure in the shader"); - static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec"); + static_assert(sizeof(UniformData) == 0x6210, "The size of the UniformData structure has changed, update the structure in the shader"); + static_assert(sizeof(UniformData) < 32768, "UniformData structure must be less than 32kb"); /// Reconfigure the OpenGL color texture to use the given format and dimensions void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height); @@ -295,6 +296,9 @@ private: /// Syncs the lighting global ambient color to match the PICA register void SyncGlobalAmbient(); + /// Syncs the lighting lookup tables + void SyncLightingLUT(unsigned index); + /// Syncs the specified light's diffuse color to match the PICA register void SyncLightDiffuse(int light_index); @@ -346,6 +350,7 @@ private: struct { UniformData data; + bool lut_dirty[24]; bool dirty; } uniform_block_data; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 5bc588b0b2..4e02671ddb 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -324,6 +324,7 @@ std::string GenerateFragmentShader(const PicaShaderConfig& config) { #version 330 core #define NUM_TEV_STAGES 6 #define NUM_LIGHTS 8 +#define LIGHTING_LUT_SIZE 256 in vec4 primary_color; in vec2 texcoord[3]; @@ -345,6 +346,12 @@ layout (std140) uniform shader_data { float depth_offset; vec3 lighting_global_ambient; LightSrc light_src[NUM_LIGHTS]; + vec4 lighting_lut_0[LIGHTING_LUT_SIZE]; + vec4 lighting_lut_1[LIGHTING_LUT_SIZE]; + vec4 lighting_lut_2[LIGHTING_LUT_SIZE]; + vec4 lighting_lut_3[LIGHTING_LUT_SIZE]; + vec4 lighting_lut_4[LIGHTING_LUT_SIZE]; + vec4 lighting_lut_5[LIGHTING_LUT_SIZE]; }; uniform sampler2D tex[3];