diff options
| author | 2015-11-30 22:33:38 -0800 | |
|---|---|---|
| committer | 2015-11-30 22:45:18 -0800 | |
| commit | e9c209ccc8ec8800306aa49b9b805f9d502d0a7e (patch) | |
| tree | 8f500feafc6d53f3572a4242546e147649f28bff | |
| parent | Merge pull request #1257 from yuriks/svcGetSystemInfo (diff) | |
| download | yuzu-e9c209ccc8ec8800306aa49b9b805f9d502d0a7e.tar.gz yuzu-e9c209ccc8ec8800306aa49b9b805f9d502d0a7e.tar.xz yuzu-e9c209ccc8ec8800306aa49b9b805f9d502d0a7e.zip | |
PICA: Properly emulate 1-stage delay in the combiner buffer
This was discovered and verified by @fincs. The tev combiner buffer
actually lags behind by one stage, meaning stage 1 reads the initial
color, stage 2 reads stage 0's output, and so on.
Fixes character portraits in Fire Emblem: Awakening and world textures
in Zelda: ALBW. Closes #1140.
| -rw-r--r-- | src/video_core/rasterizer.cpp | 13 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 18 |
2 files changed, 19 insertions, 12 deletions
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 226fad783..ecfdbc9e8 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp | |||
| @@ -498,7 +498,8 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 498 | // with some basic arithmetic. Alpha combiners can be configured separately but work | 498 | // with some basic arithmetic. Alpha combiners can be configured separately but work |
| 499 | // analogously. | 499 | // analogously. |
| 500 | Math::Vec4<u8> combiner_output; | 500 | Math::Vec4<u8> combiner_output; |
| 501 | Math::Vec4<u8> combiner_buffer = { | 501 | Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0}; |
| 502 | Math::Vec4<u8> next_combiner_buffer = { | ||
| 502 | regs.tev_combiner_buffer_color.r, regs.tev_combiner_buffer_color.g, | 503 | regs.tev_combiner_buffer_color.r, regs.tev_combiner_buffer_color.g, |
| 503 | regs.tev_combiner_buffer_color.b, regs.tev_combiner_buffer_color.a | 504 | regs.tev_combiner_buffer_color.b, regs.tev_combiner_buffer_color.a |
| 504 | }; | 505 | }; |
| @@ -747,14 +748,16 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 747 | combiner_output[2] = std::min((unsigned)255, color_output.b() * tev_stage.GetColorMultiplier()); | 748 | combiner_output[2] = std::min((unsigned)255, color_output.b() * tev_stage.GetColorMultiplier()); |
| 748 | combiner_output[3] = std::min((unsigned)255, alpha_output * tev_stage.GetAlphaMultiplier()); | 749 | combiner_output[3] = std::min((unsigned)255, alpha_output * tev_stage.GetAlphaMultiplier()); |
| 749 | 750 | ||
| 751 | combiner_buffer = next_combiner_buffer; | ||
| 752 | |||
| 750 | if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index)) { | 753 | if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index)) { |
| 751 | combiner_buffer.r() = combiner_output.r(); | 754 | next_combiner_buffer.r() = combiner_output.r(); |
| 752 | combiner_buffer.g() = combiner_output.g(); | 755 | next_combiner_buffer.g() = combiner_output.g(); |
| 753 | combiner_buffer.b() = combiner_output.b(); | 756 | next_combiner_buffer.b() = combiner_output.b(); |
| 754 | } | 757 | } |
| 755 | 758 | ||
| 756 | if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)) { | 759 | if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)) { |
| 757 | combiner_buffer.a() = combiner_output.a(); | 760 | next_combiner_buffer.a() = combiner_output.a(); |
| 758 | } | 761 | } |
| 759 | } | 762 | } |
| 760 | 763 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 5268340cf..498c506e7 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -311,11 +311,13 @@ static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsi | |||
| 311 | "clamp(alpha_output_" + index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) + ".0, 0.0, 1.0));\n"; | 311 | "clamp(alpha_output_" + index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) + ".0, 0.0, 1.0));\n"; |
| 312 | } | 312 | } |
| 313 | 313 | ||
| 314 | out += "combiner_buffer = next_combiner_buffer;\n"; | ||
| 315 | |||
| 314 | if (config.TevStageUpdatesCombinerBufferColor(index)) | 316 | if (config.TevStageUpdatesCombinerBufferColor(index)) |
| 315 | out += "combiner_buffer.rgb = last_tex_env_out.rgb;\n"; | 317 | out += "next_combiner_buffer.rgb = last_tex_env_out.rgb;\n"; |
| 316 | 318 | ||
| 317 | if (config.TevStageUpdatesCombinerBufferAlpha(index)) | 319 | if (config.TevStageUpdatesCombinerBufferAlpha(index)) |
| 318 | out += "combiner_buffer.a = last_tex_env_out.a;\n"; | 320 | out += "next_combiner_buffer.a = last_tex_env_out.a;\n"; |
| 319 | } | 321 | } |
| 320 | 322 | ||
| 321 | std::string GenerateFragmentShader(const PicaShaderConfig& config) { | 323 | std::string GenerateFragmentShader(const PicaShaderConfig& config) { |
| @@ -334,12 +336,10 @@ layout (std140) uniform shader_data { | |||
| 334 | int alphatest_ref; | 336 | int alphatest_ref; |
| 335 | }; | 337 | }; |
| 336 | 338 | ||
| 337 | )"; | 339 | uniform sampler2D tex[3]; |
| 338 | 340 | ||
| 339 | out += "uniform sampler2D tex[3];\n"; | 341 | void main() { |
| 340 | out += "void main() {\n"; | 342 | )"; |
| 341 | out += "vec4 combiner_buffer = tev_combiner_buffer_color;\n"; | ||
| 342 | out += "vec4 last_tex_env_out = vec4(0.0);\n"; | ||
| 343 | 343 | ||
| 344 | // Do not do any sort of processing if it's obvious we're not going to pass the alpha test | 344 | // Do not do any sort of processing if it's obvious we're not going to pass the alpha test |
| 345 | if (config.alpha_test_func == Regs::CompareFunc::Never) { | 345 | if (config.alpha_test_func == Regs::CompareFunc::Never) { |
| @@ -347,6 +347,10 @@ layout (std140) uniform shader_data { | |||
| 347 | return out; | 347 | return out; |
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | out += "vec4 combiner_buffer = vec4(0.0);\n"; | ||
| 351 | out += "vec4 next_combiner_buffer = tev_combiner_buffer_color;\n"; | ||
| 352 | out += "vec4 last_tex_env_out = vec4(0.0);\n"; | ||
| 353 | |||
| 350 | for (size_t index = 0; index < config.tev_stages.size(); ++index) | 354 | for (size_t index = 0; index < config.tev_stages.size(); ++index) |
| 351 | WriteTevStage(out, config, (unsigned)index); | 355 | WriteTevStage(out, config, (unsigned)index); |
| 352 | 356 | ||