diff options
| author | 2015-11-15 17:43:01 -0500 | |
|---|---|---|
| committer | 2016-02-05 17:17:31 -0500 | |
| commit | 021cb0bced1d8045f04b85024b97a07a4d0df12f (patch) | |
| tree | af2e041a2625ebde8c5f734f2e0ab911aba11625 /src | |
| parent | renderer_opengl: Initial implementation of basic specular lighting. (diff) | |
| download | yuzu-021cb0bced1d8045f04b85024b97a07a4d0df12f.tar.gz yuzu-021cb0bced1d8045f04b85024b97a07a4d0df12f.tar.xz yuzu-021cb0bced1d8045f04b85024b97a07a4d0df12f.zip | |
renderer_opengl: Use textures for fragment shader LUTs instead of UBOs.
- Gets us LUT interpolation for free.
- Some older Intel GPU drivers did not support the big UBOs needed to store the LUTs.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 51 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 10 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 18 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 4 |
5 files changed, 64 insertions, 27 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index c6fb37c53..6e7d6a40d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -126,6 +126,19 @@ void RasterizerOpenGL::InitObjects() { | |||
| 126 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_color_texture.texture.handle, 0); | 126 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_color_texture.texture.handle, 0); |
| 127 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fb_depth_texture.texture.handle, 0); | 127 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fb_depth_texture.texture.handle, 0); |
| 128 | 128 | ||
| 129 | for (size_t i = 0; i < lighting_lut.size(); ++i) { | ||
| 130 | lighting_lut[i].Create(); | ||
| 131 | state.lighting_lut[i].texture_1d = lighting_lut[i].handle; | ||
| 132 | |||
| 133 | glActiveTexture(GL_TEXTURE3 + i); | ||
| 134 | glBindTexture(GL_TEXTURE_1D, state.lighting_lut[i].texture_1d); | ||
| 135 | |||
| 136 | glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 256, 0, GL_RGBA, GL_FLOAT, nullptr); | ||
| 137 | glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||
| 138 | glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||
| 139 | } | ||
| 140 | state.Apply(); | ||
| 141 | |||
| 129 | ASSERT_MSG(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, | 142 | ASSERT_MSG(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, |
| 130 | "OpenGL rasterizer framebuffer setup failed, status %X", glCheckFramebufferStatus(GL_FRAMEBUFFER)); | 143 | "OpenGL rasterizer framebuffer setup failed, status %X", glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
| 131 | } | 144 | } |
| @@ -162,7 +175,7 @@ void RasterizerOpenGL::DrawTriangles() { | |||
| 162 | state.draw.shader_dirty = false; | 175 | state.draw.shader_dirty = false; |
| 163 | } | 176 | } |
| 164 | 177 | ||
| 165 | for (unsigned index = 0; index < Pica::g_state.lighting.luts.size(); index++) { | 178 | for (unsigned index = 0; index < lighting_lut.size(); index++) { |
| 166 | if (uniform_block_data.lut_dirty[index]) { | 179 | if (uniform_block_data.lut_dirty[index]) { |
| 167 | SyncLightingLUT(index); | 180 | SyncLightingLUT(index); |
| 168 | uniform_block_data.lut_dirty[index] = false; | 181 | uniform_block_data.lut_dirty[index] = false; |
| @@ -451,7 +464,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 451 | case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf): | 464 | case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf): |
| 452 | { | 465 | { |
| 453 | auto& lut_config = regs.lighting.lut_config; | 466 | auto& lut_config = regs.lighting.lut_config; |
| 454 | uniform_block_data.lut_dirty[lut_config.type] = true; | 467 | uniform_block_data.lut_dirty[lut_config.type / 4] = true; |
| 455 | break; | 468 | break; |
| 456 | } | 469 | } |
| 457 | 470 | ||
| @@ -663,6 +676,20 @@ void RasterizerOpenGL::SetShader() { | |||
| 663 | uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]"); | 676 | uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]"); |
| 664 | if (uniform_tex != -1) { glUniform1i(uniform_tex, 2); } | 677 | if (uniform_tex != -1) { glUniform1i(uniform_tex, 2); } |
| 665 | 678 | ||
| 679 | // Set the texture samplers to correspond to different lookup table texture units | ||
| 680 | GLuint uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[0]"); | ||
| 681 | if (uniform_lut != -1) { glUniform1i(uniform_lut, 3); } | ||
| 682 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[1]"); | ||
| 683 | if (uniform_lut != -1) { glUniform1i(uniform_lut, 4); } | ||
| 684 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[2]"); | ||
| 685 | if (uniform_lut != -1) { glUniform1i(uniform_lut, 5); } | ||
| 686 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[3]"); | ||
| 687 | if (uniform_lut != -1) { glUniform1i(uniform_lut, 6); } | ||
| 688 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[4]"); | ||
| 689 | if (uniform_lut != -1) { glUniform1i(uniform_lut, 7); } | ||
| 690 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[5]"); | ||
| 691 | if (uniform_lut != -1) { glUniform1i(uniform_lut, 8); } | ||
| 692 | |||
| 666 | current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); | 693 | current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); |
| 667 | 694 | ||
| 668 | unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data"); | 695 | unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data"); |
| @@ -675,9 +702,6 @@ void RasterizerOpenGL::SetShader() { | |||
| 675 | for (int index = 0; index < tev_stages.size(); ++index) | 702 | for (int index = 0; index < tev_stages.size(); ++index) |
| 676 | SyncTevConstColor(index, tev_stages[index]); | 703 | SyncTevConstColor(index, tev_stages[index]); |
| 677 | 704 | ||
| 678 | for (unsigned index = 0; index < Pica::g_state.lighting.luts.size(); ++index) | ||
| 679 | SyncLightingLUT(index); | ||
| 680 | |||
| 681 | SyncGlobalAmbient(); | 705 | SyncGlobalAmbient(); |
| 682 | for (int light_index = 0; light_index < 8; light_index++) { | 706 | for (int light_index = 0; light_index < 8; light_index++) { |
| 683 | SyncLightDiffuse(light_index); | 707 | SyncLightDiffuse(light_index); |
| @@ -874,16 +898,19 @@ void RasterizerOpenGL::SyncGlobalAmbient() { | |||
| 874 | } | 898 | } |
| 875 | 899 | ||
| 876 | void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) { | 900 | void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) { |
| 877 | auto& lut = uniform_block_data.data.lighting_lut[lut_index / 4]; | 901 | std::array<std::array<GLfloat, 4>, 256> new_data; |
| 878 | std::array<std::array<GLfloat, 4>, 256> new_lut; | ||
| 879 | 902 | ||
| 880 | for (int offset = 0; offset < new_lut.size(); ++offset) { | 903 | for (unsigned offset = 0; offset < new_data.size(); ++offset) { |
| 881 | new_lut[offset][lut_index & 3] = Pica::g_state.lighting.luts[lut_index][offset].ToFloat(); | 904 | new_data[offset][0] = Pica::g_state.lighting.luts[(lut_index * 4) + 0][offset].ToFloat(); |
| 905 | new_data[offset][1] = Pica::g_state.lighting.luts[(lut_index * 4) + 1][offset].ToFloat(); | ||
| 906 | new_data[offset][2] = Pica::g_state.lighting.luts[(lut_index * 4) + 2][offset].ToFloat(); | ||
| 907 | new_data[offset][3] = Pica::g_state.lighting.luts[(lut_index * 4) + 3][offset].ToFloat(); | ||
| 882 | } | 908 | } |
| 883 | 909 | ||
| 884 | if (new_lut != lut) { | 910 | if (new_data != lighting_lut_data[lut_index]) { |
| 885 | lut = new_lut; | 911 | lighting_lut_data[lut_index] = new_data; |
| 886 | uniform_block_data.dirty = true; | 912 | glActiveTexture(GL_TEXTURE3 + lut_index); |
| 913 | glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT, lighting_lut_data[lut_index].data()); | ||
| 887 | } | 914 | } |
| 888 | } | 915 | } |
| 889 | 916 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 9e93b8b2f..b50542701 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -264,11 +264,10 @@ private: | |||
| 264 | std::array<GLfloat, 3> lighting_global_ambient; | 264 | std::array<GLfloat, 3> lighting_global_ambient; |
| 265 | INSERT_PADDING_WORDS(1); | 265 | INSERT_PADDING_WORDS(1); |
| 266 | LightSrc light_src[8]; | 266 | LightSrc light_src[8]; |
| 267 | std::array<std::array<std::array<GLfloat, 4>, 256>, 6> lighting_lut; | ||
| 268 | }; | 267 | }; |
| 269 | 268 | ||
| 270 | static_assert(sizeof(UniformData) == 0x6210, "The size of the UniformData structure has changed, update the structure in the shader"); | 269 | static_assert(sizeof(UniformData) == 0x310, "The size of the UniformData structure has changed, update the structure in the shader"); |
| 271 | static_assert(sizeof(UniformData) < 32768, "UniformData structure must be less than 32kb"); | 270 | static_assert(sizeof(UniformData) < 16384, "UniformData structure must be less than 16kb as per the OpenGL spec"); |
| 272 | 271 | ||
| 273 | /// Reconfigure the OpenGL color texture to use the given format and dimensions | 272 | /// Reconfigure the OpenGL color texture to use the given format and dimensions |
| 274 | void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height); | 273 | void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height); |
| @@ -378,7 +377,7 @@ private: | |||
| 378 | 377 | ||
| 379 | struct { | 378 | struct { |
| 380 | UniformData data; | 379 | UniformData data; |
| 381 | bool lut_dirty[24]; | 380 | bool lut_dirty[6]; |
| 382 | bool dirty; | 381 | bool dirty; |
| 383 | } uniform_block_data; | 382 | } uniform_block_data; |
| 384 | 383 | ||
| @@ -386,4 +385,7 @@ private: | |||
| 386 | OGLBuffer vertex_buffer; | 385 | OGLBuffer vertex_buffer; |
| 387 | OGLBuffer uniform_buffer; | 386 | OGLBuffer uniform_buffer; |
| 388 | OGLFramebuffer framebuffer; | 387 | OGLFramebuffer framebuffer; |
| 388 | |||
| 389 | std::array<OGLTexture, 6> lighting_lut; | ||
| 390 | std::array<std::array<std::array<GLfloat, 4>, 256>, 6> lighting_lut_data; | ||
| 389 | }; | 391 | }; |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index abcc89f1d..cb570c4d2 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) { | |||
| 324 | #define NUM_TEV_STAGES 6 | 324 | #define NUM_TEV_STAGES 6 |
| 325 | #define NUM_LIGHTS 8 | 325 | #define NUM_LIGHTS 8 |
| 326 | #define LIGHTING_LUT_SIZE 256 | 326 | #define LIGHTING_LUT_SIZE 256 |
| 327 | #define FLOAT_255 0.99609375 | ||
| 327 | 328 | ||
| 328 | in vec4 primary_color; | 329 | in vec4 primary_color; |
| 329 | in vec2 texcoord[3]; | 330 | in vec2 texcoord[3]; |
| @@ -347,15 +348,10 @@ layout (std140) uniform shader_data { | |||
| 347 | float depth_offset; | 348 | float depth_offset; |
| 348 | vec3 lighting_global_ambient; | 349 | vec3 lighting_global_ambient; |
| 349 | LightSrc light_src[NUM_LIGHTS]; | 350 | LightSrc light_src[NUM_LIGHTS]; |
| 350 | vec4 lighting_lut_0[LIGHTING_LUT_SIZE]; | ||
| 351 | vec4 lighting_lut_1[LIGHTING_LUT_SIZE]; | ||
| 352 | vec4 lighting_lut_2[LIGHTING_LUT_SIZE]; | ||
| 353 | vec4 lighting_lut_3[LIGHTING_LUT_SIZE]; | ||
| 354 | vec4 lighting_lut_4[LIGHTING_LUT_SIZE]; | ||
| 355 | vec4 lighting_lut_5[LIGHTING_LUT_SIZE]; | ||
| 356 | }; | 351 | }; |
| 357 | 352 | ||
| 358 | uniform sampler2D tex[3]; | 353 | uniform sampler2D tex[3]; |
| 354 | uniform sampler1D lut[6]; | ||
| 359 | 355 | ||
| 360 | void main() { | 356 | void main() { |
| 361 | vec4 primary_fragment_color = vec4(0.0); | 357 | vec4 primary_fragment_color = vec4(0.0); |
| @@ -404,11 +400,11 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
| 404 | if (abs) { | 400 | if (abs) { |
| 405 | // In the range of [ 0.f, 1.f] | 401 | // In the range of [ 0.f, 1.f] |
| 406 | index = config.light_src[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)"; | 402 | index = config.light_src[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)"; |
| 407 | return "clamp(int(" + index + " * 256.0), 0, 255)"; | 403 | return "clamp(" + index + ", 0.0, FLOAT_255)"; |
| 408 | } else { | 404 | } else { |
| 409 | // In the range of [-1.f, 1.f] | 405 | // In the range of [-1.f, 1.f] |
| 410 | index = "clamp(" + index + ", -1.0, 1.0)"; | 406 | index = "clamp(" + index + ", -1.0, 1.0)"; |
| 411 | return std::string("uint(int(" + index + " * 127.f) & 0xff)"); | 407 | return "clamp(((" + index + " < 0) ? " + index + " + 2.0 : " + index + ") / 2.0, 0.0, FLOAT_255)"; |
| 412 | } | 408 | } |
| 413 | 409 | ||
| 414 | return std::string(); | 410 | return std::string(); |
| @@ -435,10 +431,10 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
| 435 | std::string scale = std::to_string(config.light_src[light_index].dist_atten_scale); | 431 | std::string scale = std::to_string(config.light_src[light_index].dist_atten_scale); |
| 436 | std::string bias = std::to_string(config.light_src[light_index].dist_atten_bias); | 432 | std::string bias = std::to_string(config.light_src[light_index].dist_atten_bias); |
| 437 | std::string lut_index = "(" + scale + " * length(fragment_position - " + light_src + ".position) + " + bias + ")"; | 433 | std::string lut_index = "(" + scale + " * length(fragment_position - " + light_src + ".position) + " + bias + ")"; |
| 438 | std::string clamped_lut_index = "((clamp(int(" + lut_index + " * 256.0), 0, 255)))"; | 434 | std::string clamped_lut_index = "((clamp(" + lut_index + ", 0.0, FLOAT_255)))"; |
| 439 | 435 | ||
| 440 | const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num); | 436 | const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num); |
| 441 | out += "dist_atten = lighting_lut_" + std::to_string(lut_num / 4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "];\n"; | 437 | out += "dist_atten = texture(lut[" + std::to_string(lut_num / 4) + "], " + clamped_lut_index + ")[" + std::to_string(lut_num & 3) + "];\n"; |
| 442 | } | 438 | } |
| 443 | 439 | ||
| 444 | // Compute primary fragment color (diffuse lighting) function | 440 | // Compute primary fragment color (diffuse lighting) function |
| @@ -447,7 +443,7 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
| 447 | // Compute secondary fragment color (specular lighting) function | 443 | // Compute secondary fragment color (specular lighting) function |
| 448 | std::string clamped_lut_index = GetLutIndex(num, config.lighting_lut.d0_type, config.lighting_lut.d0_abs); | 444 | std::string clamped_lut_index = GetLutIndex(num, config.lighting_lut.d0_type, config.lighting_lut.d0_abs); |
| 449 | const unsigned lut_num = (unsigned)Regs::LightingSampler::Distribution0; | 445 | const unsigned lut_num = (unsigned)Regs::LightingSampler::Distribution0; |
| 450 | std::string lut_lookup = "lighting_lut_" + std::to_string(lut_num / 4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "]"; | 446 | std::string lut_lookup = "texture(lut[" + std::to_string(lut_num / 4) + "], " + clamped_lut_index + ")[" + std::to_string(lut_num & 3) + "]"; |
| 451 | 447 | ||
| 452 | out += "specular_sum += (" + lut_lookup + " * light_src[" + std::to_string(num) + "].specular_0 * dist_atten);\n"; | 448 | out += "specular_sum += (" + lut_lookup + " * light_src[" + std::to_string(num) + "].specular_0 * dist_atten);\n"; |
| 453 | } | 449 | } |
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index a82372995..ab4b6c7b1 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -170,6 +170,14 @@ void OpenGLState::Apply() { | |||
| 170 | } | 170 | } |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | // Lighting LUTs | ||
| 174 | for (unsigned i = 0; i < ARRAY_SIZE(lighting_lut); ++i) { | ||
| 175 | if (lighting_lut[i].texture_1d != cur_state.lighting_lut[i].texture_1d) { | ||
| 176 | glActiveTexture(GL_TEXTURE3 + i); | ||
| 177 | glBindTexture(GL_TEXTURE_1D, lighting_lut[i].texture_1d); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 173 | // Framebuffer | 181 | // Framebuffer |
| 174 | if (draw.framebuffer != cur_state.draw.framebuffer) { | 182 | if (draw.framebuffer != cur_state.draw.framebuffer) { |
| 175 | glBindFramebuffer(GL_FRAMEBUFFER, draw.framebuffer); | 183 | glBindFramebuffer(GL_FRAMEBUFFER, draw.framebuffer); |
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index b8ab45bb8..e848058d7 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -62,6 +62,10 @@ public: | |||
| 62 | } texture_units[3]; | 62 | } texture_units[3]; |
| 63 | 63 | ||
| 64 | struct { | 64 | struct { |
| 65 | GLuint texture_1d; // GL_TEXTURE_BINDING_1D | ||
| 66 | } lighting_lut[6]; | ||
| 67 | |||
| 68 | struct { | ||
| 65 | GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING | 69 | GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING |
| 66 | GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING | 70 | GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING |
| 67 | GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING | 71 | GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING |