diff options
| author | 2017-06-16 14:00:15 +0300 | |
|---|---|---|
| committer | 2017-06-21 23:13:06 +0300 | |
| commit | ab60414122184851415a27ae8bcacb4aab0504b6 (patch) | |
| tree | f26b042d908ede118686e781eedfec24539ab299 /src | |
| parent | Merge pull request #2776 from wwylele/geo-factor (diff) | |
| download | yuzu-ab60414122184851415a27ae8bcacb4aab0504b6.tar.gz yuzu-ab60414122184851415a27ae8bcacb4aab0504b6.tar.xz yuzu-ab60414122184851415a27ae8bcacb4aab0504b6.zip | |
gl_rasterizer/lighting: fix LUT interpolation
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/pica_state.h | 12 | ||||
| -rw-r--r-- | src/video_core/regs_lighting.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 71 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 7 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 110 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 4 |
7 files changed, 102 insertions, 116 deletions
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h index f46db09fb..3b00df0b3 100644 --- a/src/video_core/pica_state.h +++ b/src/video_core/pica_state.h | |||
| @@ -87,12 +87,18 @@ struct State { | |||
| 87 | // LUT value, encoded as 12-bit fixed point, with 12 fraction bits | 87 | // LUT value, encoded as 12-bit fixed point, with 12 fraction bits |
| 88 | BitField<0, 12, u32> value; // 0.0.12 fixed point | 88 | BitField<0, 12, u32> value; // 0.0.12 fixed point |
| 89 | 89 | ||
| 90 | // Used by HW for efficient interpolation, Citra does not use these | 90 | // Used for efficient interpolation. |
| 91 | BitField<12, 12, s32> difference; // 1.0.11 fixed point | 91 | BitField<12, 11, u32> difference; // 0.0.11 fixed point |
| 92 | BitField<23, 1, u32> neg_difference; | ||
| 92 | 93 | ||
| 93 | float ToFloat() { | 94 | float ToFloat() const { |
| 94 | return static_cast<float>(value) / 4095.f; | 95 | return static_cast<float>(value) / 4095.f; |
| 95 | } | 96 | } |
| 97 | |||
| 98 | float DiffToFloat() const { | ||
| 99 | float diff = static_cast<float>(difference) / 2047.f; | ||
| 100 | return neg_difference ? -diff : diff; | ||
| 101 | } | ||
| 96 | }; | 102 | }; |
| 97 | 103 | ||
| 98 | std::array<std::array<LutEntry, 256>, 24> luts; | 104 | std::array<std::array<LutEntry, 256>, 24> luts; |
diff --git a/src/video_core/regs_lighting.h b/src/video_core/regs_lighting.h index 7221d1688..b89709cfe 100644 --- a/src/video_core/regs_lighting.h +++ b/src/video_core/regs_lighting.h | |||
| @@ -26,6 +26,8 @@ struct LightingRegs { | |||
| 26 | DistanceAttenuation = 16, | 26 | DistanceAttenuation = 16, |
| 27 | }; | 27 | }; |
| 28 | 28 | ||
| 29 | static constexpr unsigned NumLightingSampler = 24; | ||
| 30 | |||
| 29 | static LightingSampler SpotlightAttenuationSampler(unsigned index) { | 31 | static LightingSampler SpotlightAttenuationSampler(unsigned index) { |
| 30 | return static_cast<LightingSampler>( | 32 | return static_cast<LightingSampler>( |
| 31 | static_cast<unsigned>(LightingSampler::SpotlightAttenuation) + index); | 33 | static_cast<unsigned>(LightingSampler::SpotlightAttenuation) + index); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index e6cccebf6..c73e1d6e2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -49,9 +49,7 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { | |||
| 49 | 49 | ||
| 50 | uniform_block_data.dirty = true; | 50 | uniform_block_data.dirty = true; |
| 51 | 51 | ||
| 52 | for (unsigned index = 0; index < lighting_luts.size(); index++) { | 52 | uniform_block_data.lut_dirty.fill(true); |
| 53 | uniform_block_data.lut_dirty[index] = true; | ||
| 54 | } | ||
| 55 | 53 | ||
| 56 | uniform_block_data.fog_lut_dirty = true; | 54 | uniform_block_data.fog_lut_dirty = true; |
| 57 | 55 | ||
| @@ -96,18 +94,16 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { | |||
| 96 | framebuffer.Create(); | 94 | framebuffer.Create(); |
| 97 | 95 | ||
| 98 | // Allocate and bind lighting lut textures | 96 | // Allocate and bind lighting lut textures |
| 99 | for (size_t i = 0; i < lighting_luts.size(); ++i) { | 97 | lighting_lut_buffer.Create(); |
| 100 | lighting_luts[i].Create(); | 98 | state.lighting_lut.texture_buffer = lighting_lut.handle; |
| 101 | state.lighting_luts[i].texture_1d = lighting_luts[i].handle; | ||
| 102 | } | ||
| 103 | state.Apply(); | 99 | state.Apply(); |
| 104 | 100 | lighting_lut.Create(); | |
| 105 | for (size_t i = 0; i < lighting_luts.size(); ++i) { | 101 | glBindBuffer(GL_TEXTURE_BUFFER, lighting_lut_buffer.handle); |
| 106 | glActiveTexture(static_cast<GLenum>(GL_TEXTURE3 + i)); | 102 | glBufferData(GL_TEXTURE_BUFFER, |
| 107 | glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 256, 0, GL_RGBA, GL_FLOAT, nullptr); | 103 | sizeof(GLfloat) * 2 * 256 * Pica::LightingRegs::NumLightingSampler, nullptr, |
| 108 | glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 104 | GL_DYNAMIC_DRAW); |
| 109 | glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 105 | glActiveTexture(GL_TEXTURE15); |
| 110 | } | 106 | glTexBuffer(GL_TEXTURE_BUFFER, GL_RG32F, lighting_lut_buffer.handle); |
| 111 | 107 | ||
| 112 | // Setup the LUT for the fog | 108 | // Setup the LUT for the fog |
| 113 | { | 109 | { |
| @@ -313,7 +309,7 @@ void RasterizerOpenGL::DrawTriangles() { | |||
| 313 | } | 309 | } |
| 314 | 310 | ||
| 315 | // Sync the lighting luts | 311 | // Sync the lighting luts |
| 316 | for (unsigned index = 0; index < lighting_luts.size(); index++) { | 312 | for (unsigned index = 0; index < uniform_block_data.lut_dirty.size(); index++) { |
| 317 | if (uniform_block_data.lut_dirty[index]) { | 313 | if (uniform_block_data.lut_dirty[index]) { |
| 318 | SyncLightingLUT(index); | 314 | SyncLightingLUT(index); |
| 319 | uniform_block_data.lut_dirty[index] = false; | 315 | uniform_block_data.lut_dirty[index] = false; |
| @@ -851,7 +847,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 851 | case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[6], 0x1ce): | 847 | case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[6], 0x1ce): |
| 852 | case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf): { | 848 | case PICA_REG_INDEX_WORKAROUND(lighting.lut_data[7], 0x1cf): { |
| 853 | auto& lut_config = regs.lighting.lut_config; | 849 | auto& lut_config = regs.lighting.lut_config; |
| 854 | uniform_block_data.lut_dirty[lut_config.type / 4] = true; | 850 | uniform_block_data.lut_dirty[lut_config.type] = true; |
| 855 | break; | 851 | break; |
| 856 | } | 852 | } |
| 857 | } | 853 | } |
| @@ -1201,29 +1197,9 @@ void RasterizerOpenGL::SetShader() { | |||
| 1201 | } | 1197 | } |
| 1202 | 1198 | ||
| 1203 | // Set the texture samplers to correspond to different lookup table texture units | 1199 | // Set the texture samplers to correspond to different lookup table texture units |
| 1204 | GLuint uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[0]"); | 1200 | GLuint uniform_lut = glGetUniformLocation(shader->shader.handle, "lighting_lut"); |
| 1205 | if (uniform_lut != -1) { | ||
| 1206 | glUniform1i(uniform_lut, 3); | ||
| 1207 | } | ||
| 1208 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[1]"); | ||
| 1209 | if (uniform_lut != -1) { | ||
| 1210 | glUniform1i(uniform_lut, 4); | ||
| 1211 | } | ||
| 1212 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[2]"); | ||
| 1213 | if (uniform_lut != -1) { | ||
| 1214 | glUniform1i(uniform_lut, 5); | ||
| 1215 | } | ||
| 1216 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[3]"); | ||
| 1217 | if (uniform_lut != -1) { | 1201 | if (uniform_lut != -1) { |
| 1218 | glUniform1i(uniform_lut, 6); | 1202 | glUniform1i(uniform_lut, 15); |
| 1219 | } | ||
| 1220 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[4]"); | ||
| 1221 | if (uniform_lut != -1) { | ||
| 1222 | glUniform1i(uniform_lut, 7); | ||
| 1223 | } | ||
| 1224 | uniform_lut = glGetUniformLocation(shader->shader.handle, "lut[5]"); | ||
| 1225 | if (uniform_lut != -1) { | ||
| 1226 | glUniform1i(uniform_lut, 8); | ||
| 1227 | } | 1203 | } |
| 1228 | 1204 | ||
| 1229 | GLuint uniform_fog_lut = glGetUniformLocation(shader->shader.handle, "fog_lut"); | 1205 | GLuint uniform_fog_lut = glGetUniformLocation(shader->shader.handle, "fog_lut"); |
| @@ -1571,20 +1547,17 @@ void RasterizerOpenGL::SyncGlobalAmbient() { | |||
| 1571 | } | 1547 | } |
| 1572 | 1548 | ||
| 1573 | void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) { | 1549 | void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) { |
| 1574 | std::array<GLvec4, 256> new_data; | 1550 | std::array<GLvec2, 256> new_data; |
| 1575 | 1551 | const auto& source_lut = Pica::g_state.lighting.luts[lut_index]; | |
| 1576 | for (unsigned offset = 0; offset < new_data.size(); ++offset) { | 1552 | std::transform(source_lut.begin(), source_lut.end(), new_data.begin(), [](const auto& entry) { |
| 1577 | new_data[offset][0] = Pica::g_state.lighting.luts[(lut_index * 4) + 0][offset].ToFloat(); | 1553 | return GLvec2{entry.ToFloat(), entry.DiffToFloat()}; |
| 1578 | new_data[offset][1] = Pica::g_state.lighting.luts[(lut_index * 4) + 1][offset].ToFloat(); | 1554 | }); |
| 1579 | new_data[offset][2] = Pica::g_state.lighting.luts[(lut_index * 4) + 2][offset].ToFloat(); | ||
| 1580 | new_data[offset][3] = Pica::g_state.lighting.luts[(lut_index * 4) + 3][offset].ToFloat(); | ||
| 1581 | } | ||
| 1582 | 1555 | ||
| 1583 | if (new_data != lighting_lut_data[lut_index]) { | 1556 | if (new_data != lighting_lut_data[lut_index]) { |
| 1584 | lighting_lut_data[lut_index] = new_data; | 1557 | lighting_lut_data[lut_index] = new_data; |
| 1585 | glActiveTexture(GL_TEXTURE3 + lut_index); | 1558 | glBindBuffer(GL_TEXTURE_BUFFER, lighting_lut_buffer.handle); |
| 1586 | glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT, | 1559 | glBufferSubData(GL_TEXTURE_BUFFER, lut_index * new_data.size() * sizeof(GLvec2), |
| 1587 | lighting_lut_data[lut_index].data()); | 1560 | new_data.size() * sizeof(GLvec2), new_data.data()); |
| 1588 | } | 1561 | } |
| 1589 | } | 1562 | } |
| 1590 | 1563 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index d9a3e9d1c..79acd4230 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -263,7 +263,7 @@ private: | |||
| 263 | 263 | ||
| 264 | struct { | 264 | struct { |
| 265 | UniformData data; | 265 | UniformData data; |
| 266 | bool lut_dirty[6]; | 266 | std::array<bool, Pica::LightingRegs::NumLightingSampler> lut_dirty; |
| 267 | bool fog_lut_dirty; | 267 | bool fog_lut_dirty; |
| 268 | bool proctex_noise_lut_dirty; | 268 | bool proctex_noise_lut_dirty; |
| 269 | bool proctex_color_map_dirty; | 269 | bool proctex_color_map_dirty; |
| @@ -279,8 +279,9 @@ private: | |||
| 279 | OGLBuffer uniform_buffer; | 279 | OGLBuffer uniform_buffer; |
| 280 | OGLFramebuffer framebuffer; | 280 | OGLFramebuffer framebuffer; |
| 281 | 281 | ||
| 282 | std::array<OGLTexture, 6> lighting_luts; | 282 | OGLBuffer lighting_lut_buffer; |
| 283 | std::array<std::array<GLvec4, 256>, 6> lighting_lut_data{}; | 283 | OGLTexture lighting_lut; |
| 284 | std::array<std::array<GLvec2, 256>, Pica::LightingRegs::NumLightingSampler> lighting_lut_data{}; | ||
| 284 | 285 | ||
| 285 | OGLTexture fog_lut; | 286 | OGLTexture fog_lut; |
| 286 | std::array<GLuint, 128> fog_lut_data{}; | 287 | std::array<GLuint, 128> fog_lut_data{}; |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 540cbb9d0..0c7c4dd5c 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -562,9 +562,9 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 562 | out += "vec3 normal = quaternion_rotate(normalized_normquat, surface_normal);\n"; | 562 | out += "vec3 normal = quaternion_rotate(normalized_normquat, surface_normal);\n"; |
| 563 | out += "vec3 tangent = quaternion_rotate(normalized_normquat, surface_tangent);\n"; | 563 | out += "vec3 tangent = quaternion_rotate(normalized_normquat, surface_tangent);\n"; |
| 564 | 564 | ||
| 565 | // Gets the index into the specified lookup table for specular lighting | 565 | // Samples the specified lookup table for specular lighting |
| 566 | auto GetLutIndex = [&lighting](unsigned light_num, LightingRegs::LightingLutInput input, | 566 | auto GetLutValue = [&lighting](LightingRegs::LightingSampler sampler, unsigned light_num, |
| 567 | bool abs) { | 567 | LightingRegs::LightingLutInput input, bool abs) { |
| 568 | std::string index; | 568 | std::string index; |
| 569 | switch (input) { | 569 | switch (input) { |
| 570 | case LightingRegs::LightingLutInput::NH: | 570 | case LightingRegs::LightingLutInput::NH: |
| @@ -610,22 +610,18 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 610 | break; | 610 | break; |
| 611 | } | 611 | } |
| 612 | 612 | ||
| 613 | std::string sampler_string = std::to_string(static_cast<unsigned>(sampler)); | ||
| 614 | |||
| 613 | if (abs) { | 615 | if (abs) { |
| 614 | // LUT index is in the range of (0.0, 1.0) | 616 | // LUT index is in the range of (0.0, 1.0) |
| 615 | index = lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")" | 617 | index = lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")" |
| 616 | : "max(" + index + ", 0.0)"; | 618 | : "max(" + index + ", 0.0)"; |
| 619 | return "LookupLightingLUTUnsigned(" + sampler_string + ", " + index + ")"; | ||
| 617 | } else { | 620 | } else { |
| 618 | // LUT index is in the range of (-1.0, 1.0) | 621 | // LUT index is in the range of (-1.0, 1.0) |
| 619 | index = "((" + index + " < 0) ? " + index + " + 2.0 : " + index + ") / 2.0"; | 622 | return "LookupLightingLUTSigned(" + sampler_string + ", " + index + ")"; |
| 620 | } | 623 | } |
| 621 | 624 | ||
| 622 | return "(OFFSET_256 + SCALE_256 * clamp(" + index + ", 0.0, 1.0))"; | ||
| 623 | }; | ||
| 624 | |||
| 625 | // Gets the lighting lookup table value given the specified sampler and index | ||
| 626 | auto GetLutValue = [](LightingRegs::LightingSampler sampler, std::string lut_index) { | ||
| 627 | return std::string("texture(lut[" + std::to_string((unsigned)sampler / 4) + "], " + | ||
| 628 | lut_index + ")[" + std::to_string((unsigned)sampler & 3) + "]"); | ||
| 629 | }; | 625 | }; |
| 630 | 626 | ||
| 631 | // Write the code to emulate each enabled light | 627 | // Write the code to emulate each enabled light |
| @@ -653,21 +649,21 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 653 | if (light_config.spot_atten_enable && | 649 | if (light_config.spot_atten_enable && |
| 654 | LightingRegs::IsLightingSamplerSupported( | 650 | LightingRegs::IsLightingSamplerSupported( |
| 655 | lighting.config, LightingRegs::LightingSampler::SpotlightAttenuation)) { | 651 | lighting.config, LightingRegs::LightingSampler::SpotlightAttenuation)) { |
| 656 | std::string index = | 652 | std::string value = |
| 657 | GetLutIndex(light_config.num, lighting.lut_sp.type, lighting.lut_sp.abs_input); | 653 | GetLutValue(LightingRegs::SpotlightAttenuationSampler(light_config.num), |
| 658 | auto sampler = LightingRegs::SpotlightAttenuationSampler(light_config.num); | 654 | light_config.num, lighting.lut_sp.type, lighting.lut_sp.abs_input); |
| 659 | spot_atten = "(" + std::to_string(lighting.lut_sp.scale) + " * " + | 655 | spot_atten = "(" + std::to_string(lighting.lut_sp.scale) + " * " + value + ")"; |
| 660 | GetLutValue(sampler, index) + ")"; | ||
| 661 | } | 656 | } |
| 662 | 657 | ||
| 663 | // If enabled, compute distance attenuation value | 658 | // If enabled, compute distance attenuation value |
| 664 | std::string dist_atten = "1.0"; | 659 | std::string dist_atten = "1.0"; |
| 665 | if (light_config.dist_atten_enable) { | 660 | if (light_config.dist_atten_enable) { |
| 666 | std::string index = "(" + light_src + ".dist_atten_scale * length(-view - " + | 661 | std::string index = "clamp(" + light_src + ".dist_atten_scale * length(-view - " + |
| 667 | light_src + ".position) + " + light_src + ".dist_atten_bias)"; | 662 | light_src + ".position) + " + light_src + |
| 668 | index = "(OFFSET_256 + SCALE_256 * clamp(" + index + ", 0.0, 1.0))"; | 663 | ".dist_atten_bias, 0.0, 1.0)"; |
| 669 | auto sampler = LightingRegs::DistanceAttenuationSampler(light_config.num); | 664 | auto sampler = LightingRegs::DistanceAttenuationSampler(light_config.num); |
| 670 | dist_atten = GetLutValue(sampler, index); | 665 | dist_atten = "LookupLightingLUTUnsigned(" + |
| 666 | std::to_string(static_cast<unsigned>(sampler)) + "," + index + ")"; | ||
| 671 | } | 667 | } |
| 672 | 668 | ||
| 673 | // If enabled, clamp specular component if lighting result is negative | 669 | // If enabled, clamp specular component if lighting result is negative |
| @@ -686,10 +682,10 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 686 | LightingRegs::IsLightingSamplerSupported( | 682 | LightingRegs::IsLightingSamplerSupported( |
| 687 | lighting.config, LightingRegs::LightingSampler::Distribution0)) { | 683 | lighting.config, LightingRegs::LightingSampler::Distribution0)) { |
| 688 | // Lookup specular "distribution 0" LUT value | 684 | // Lookup specular "distribution 0" LUT value |
| 689 | std::string index = | 685 | std::string value = |
| 690 | GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input); | 686 | GetLutValue(LightingRegs::LightingSampler::Distribution0, light_config.num, |
| 691 | d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " + | 687 | lighting.lut_d0.type, lighting.lut_d0.abs_input); |
| 692 | GetLutValue(LightingRegs::LightingSampler::Distribution0, index) + ")"; | 688 | d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " + value + ")"; |
| 693 | } | 689 | } |
| 694 | std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)"; | 690 | std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)"; |
| 695 | if (light_config.geometric_factor_0) { | 691 | if (light_config.geometric_factor_0) { |
| @@ -700,10 +696,10 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 700 | if (lighting.lut_rr.enable && | 696 | if (lighting.lut_rr.enable && |
| 701 | LightingRegs::IsLightingSamplerSupported(lighting.config, | 697 | LightingRegs::IsLightingSamplerSupported(lighting.config, |
| 702 | LightingRegs::LightingSampler::ReflectRed)) { | 698 | LightingRegs::LightingSampler::ReflectRed)) { |
| 703 | std::string index = | 699 | std::string value = |
| 704 | GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input); | 700 | GetLutValue(LightingRegs::LightingSampler::ReflectRed, light_config.num, |
| 705 | std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " + | 701 | lighting.lut_rr.type, lighting.lut_rr.abs_input); |
| 706 | GetLutValue(LightingRegs::LightingSampler::ReflectRed, index) + ")"; | 702 | value = "(" + std::to_string(lighting.lut_rr.scale) + " * " + value + ")"; |
| 707 | out += "refl_value.r = " + value + ";\n"; | 703 | out += "refl_value.r = " + value + ";\n"; |
| 708 | } else { | 704 | } else { |
| 709 | out += "refl_value.r = 1.0;\n"; | 705 | out += "refl_value.r = 1.0;\n"; |
| @@ -713,11 +709,10 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 713 | if (lighting.lut_rg.enable && | 709 | if (lighting.lut_rg.enable && |
| 714 | LightingRegs::IsLightingSamplerSupported(lighting.config, | 710 | LightingRegs::IsLightingSamplerSupported(lighting.config, |
| 715 | LightingRegs::LightingSampler::ReflectGreen)) { | 711 | LightingRegs::LightingSampler::ReflectGreen)) { |
| 716 | std::string index = | 712 | std::string value = |
| 717 | GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input); | 713 | GetLutValue(LightingRegs::LightingSampler::ReflectGreen, light_config.num, |
| 718 | std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " + | 714 | lighting.lut_rg.type, lighting.lut_rg.abs_input); |
| 719 | GetLutValue(LightingRegs::LightingSampler::ReflectGreen, index) + | 715 | value = "(" + std::to_string(lighting.lut_rg.scale) + " * " + value + ")"; |
| 720 | ")"; | ||
| 721 | out += "refl_value.g = " + value + ";\n"; | 716 | out += "refl_value.g = " + value + ";\n"; |
| 722 | } else { | 717 | } else { |
| 723 | out += "refl_value.g = refl_value.r;\n"; | 718 | out += "refl_value.g = refl_value.r;\n"; |
| @@ -727,11 +722,10 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 727 | if (lighting.lut_rb.enable && | 722 | if (lighting.lut_rb.enable && |
| 728 | LightingRegs::IsLightingSamplerSupported(lighting.config, | 723 | LightingRegs::IsLightingSamplerSupported(lighting.config, |
| 729 | LightingRegs::LightingSampler::ReflectBlue)) { | 724 | LightingRegs::LightingSampler::ReflectBlue)) { |
| 730 | std::string index = | 725 | std::string value = |
| 731 | GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input); | 726 | GetLutValue(LightingRegs::LightingSampler::ReflectBlue, light_config.num, |
| 732 | std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " + | 727 | lighting.lut_rb.type, lighting.lut_rb.abs_input); |
| 733 | GetLutValue(LightingRegs::LightingSampler::ReflectBlue, index) + | 728 | value = "(" + std::to_string(lighting.lut_rb.scale) + " * " + value + ")"; |
| 734 | ")"; | ||
| 735 | out += "refl_value.b = " + value + ";\n"; | 729 | out += "refl_value.b = " + value + ";\n"; |
| 736 | } else { | 730 | } else { |
| 737 | out += "refl_value.b = refl_value.r;\n"; | 731 | out += "refl_value.b = refl_value.r;\n"; |
| @@ -743,10 +737,10 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 743 | LightingRegs::IsLightingSamplerSupported( | 737 | LightingRegs::IsLightingSamplerSupported( |
| 744 | lighting.config, LightingRegs::LightingSampler::Distribution1)) { | 738 | lighting.config, LightingRegs::LightingSampler::Distribution1)) { |
| 745 | // Lookup specular "distribution 1" LUT value | 739 | // Lookup specular "distribution 1" LUT value |
| 746 | std::string index = | 740 | std::string value = |
| 747 | GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input); | 741 | GetLutValue(LightingRegs::LightingSampler::Distribution1, light_config.num, |
| 748 | d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " + | 742 | lighting.lut_d1.type, lighting.lut_d1.abs_input); |
| 749 | GetLutValue(LightingRegs::LightingSampler::Distribution1, index) + ")"; | 743 | d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " + value + ")"; |
| 750 | } | 744 | } |
| 751 | std::string specular_1 = | 745 | std::string specular_1 = |
| 752 | "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)"; | 746 | "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)"; |
| @@ -759,10 +753,10 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 759 | LightingRegs::IsLightingSamplerSupported(lighting.config, | 753 | LightingRegs::IsLightingSamplerSupported(lighting.config, |
| 760 | LightingRegs::LightingSampler::Fresnel)) { | 754 | LightingRegs::LightingSampler::Fresnel)) { |
| 761 | // Lookup fresnel LUT value | 755 | // Lookup fresnel LUT value |
| 762 | std::string index = | 756 | std::string value = |
| 763 | GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input); | 757 | GetLutValue(LightingRegs::LightingSampler::Fresnel, light_config.num, |
| 764 | std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " + | 758 | lighting.lut_fr.type, lighting.lut_fr.abs_input); |
| 765 | GetLutValue(LightingRegs::LightingSampler::Fresnel, index) + ")"; | 759 | value = "(" + std::to_string(lighting.lut_fr.scale) + " * " + value + ")"; |
| 766 | 760 | ||
| 767 | // Enabled for difffuse lighting alpha component | 761 | // Enabled for difffuse lighting alpha component |
| 768 | if (lighting.fresnel_selector == LightingRegs::LightingFresnelSelector::PrimaryAlpha || | 762 | if (lighting.fresnel_selector == LightingRegs::LightingFresnelSelector::PrimaryAlpha || |
| @@ -1016,10 +1010,6 @@ std::string GenerateFragmentShader(const PicaShaderConfig& config) { | |||
| 1016 | #define NUM_TEV_STAGES 6 | 1010 | #define NUM_TEV_STAGES 6 |
| 1017 | #define NUM_LIGHTS 8 | 1011 | #define NUM_LIGHTS 8 |
| 1018 | 1012 | ||
| 1019 | // Texture coordinate offsets and scales | ||
| 1020 | #define OFFSET_256 (0.5 / 256.0) | ||
| 1021 | #define SCALE_256 (255.0 / 256.0) | ||
| 1022 | |||
| 1023 | in vec4 primary_color; | 1013 | in vec4 primary_color; |
| 1024 | in vec2 texcoord[3]; | 1014 | in vec2 texcoord[3]; |
| 1025 | in float texcoord0_w; | 1015 | in float texcoord0_w; |
| @@ -1061,7 +1051,7 @@ layout (std140) uniform shader_data { | |||
| 1061 | }; | 1051 | }; |
| 1062 | 1052 | ||
| 1063 | uniform sampler2D tex[3]; | 1053 | uniform sampler2D tex[3]; |
| 1064 | uniform sampler1D lut[6]; | 1054 | uniform samplerBuffer lighting_lut; |
| 1065 | uniform usampler1D fog_lut; | 1055 | uniform usampler1D fog_lut; |
| 1066 | uniform sampler1D proctex_noise_lut; | 1056 | uniform sampler1D proctex_noise_lut; |
| 1067 | uniform sampler1D proctex_color_map; | 1057 | uniform sampler1D proctex_color_map; |
| @@ -1074,6 +1064,24 @@ vec3 quaternion_rotate(vec4 q, vec3 v) { | |||
| 1074 | return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); | 1064 | return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); |
| 1075 | } | 1065 | } |
| 1076 | 1066 | ||
| 1067 | float LookupLightingLUT(int lut_index, int index, float delta) { | ||
| 1068 | vec2 entry = texelFetch(lighting_lut, lut_index * 256 + index).rg; | ||
| 1069 | return entry.r + entry.g * delta; | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | float LookupLightingLUTUnsigned(int lut_index, float pos) { | ||
| 1073 | int index = clamp(int(pos * 256.0), 0, 255); | ||
| 1074 | float delta = pos * 256.0 - index; | ||
| 1075 | return LookupLightingLUT(lut_index, index, delta); | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | float LookupLightingLUTSigned(int lut_index, float pos) { | ||
| 1079 | int index = clamp(int(pos * 128.0), -128, 127); | ||
| 1080 | float delta = pos * 128.0 - index; | ||
| 1081 | if (index < 0) index += 256; | ||
| 1082 | return LookupLightingLUT(lut_index, index, delta); | ||
| 1083 | } | ||
| 1084 | |||
| 1077 | )"; | 1085 | )"; |
| 1078 | 1086 | ||
| 1079 | if (config.state.proctex.enable) | 1087 | if (config.state.proctex.enable) |
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index bf837a7fb..40d7cee96 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -52,9 +52,7 @@ OpenGLState::OpenGLState() { | |||
| 52 | texture_unit.sampler = 0; | 52 | texture_unit.sampler = 0; |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | for (auto& lut : lighting_luts) { | 55 | lighting_lut.texture_buffer = 0; |
| 56 | lut.texture_1d = 0; | ||
| 57 | } | ||
| 58 | 56 | ||
| 59 | fog_lut.texture_1d = 0; | 57 | fog_lut.texture_1d = 0; |
| 60 | 58 | ||
| @@ -194,11 +192,9 @@ void OpenGLState::Apply() const { | |||
| 194 | } | 192 | } |
| 195 | 193 | ||
| 196 | // Lighting LUTs | 194 | // Lighting LUTs |
| 197 | for (unsigned i = 0; i < ARRAY_SIZE(lighting_luts); ++i) { | 195 | if (lighting_lut.texture_buffer != cur_state.lighting_lut.texture_buffer) { |
| 198 | if (lighting_luts[i].texture_1d != cur_state.lighting_luts[i].texture_1d) { | 196 | glActiveTexture(GL_TEXTURE15); |
| 199 | glActiveTexture(GL_TEXTURE3 + i); | 197 | glBindTexture(GL_TEXTURE_BUFFER, cur_state.lighting_lut.texture_buffer); |
| 200 | glBindTexture(GL_TEXTURE_1D, lighting_luts[i].texture_1d); | ||
| 201 | } | ||
| 202 | } | 198 | } |
| 203 | 199 | ||
| 204 | // Fog LUT | 200 | // Fog LUT |
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 7dcc03bd5..d524d0625 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -64,8 +64,8 @@ public: | |||
| 64 | } texture_units[3]; | 64 | } texture_units[3]; |
| 65 | 65 | ||
| 66 | struct { | 66 | struct { |
| 67 | GLuint texture_1d; // GL_TEXTURE_BINDING_1D | 67 | GLuint texture_buffer; // GL_TEXTURE_BINDING_BUFFER |
| 68 | } lighting_luts[6]; | 68 | } lighting_lut; |
| 69 | 69 | ||
| 70 | struct { | 70 | struct { |
| 71 | GLuint texture_1d; // GL_TEXTURE_BINDING_1D | 71 | GLuint texture_1d; // GL_TEXTURE_BINDING_1D |