diff options
| author | 2015-08-29 20:06:25 -0400 | |
|---|---|---|
| committer | 2015-08-29 20:06:25 -0400 | |
| commit | 58e9f78844168e2770bf0b43d6931569642f27fb (patch) | |
| tree | f0a3705f7e09bf6a067467553eac2119a691984b /src/video_core/rasterizer.cpp | |
| parent | Merge pull request #1080 from yuriks/linear-heap-base-typo (diff) | |
| parent | HWRenderer: Added a workaround for the Intel Windows driver bug that causes g... (diff) | |
| download | yuzu-58e9f78844168e2770bf0b43d6931569642f27fb.tar.gz yuzu-58e9f78844168e2770bf0b43d6931569642f27fb.tar.xz yuzu-58e9f78844168e2770bf0b43d6931569642f27fb.zip | |
Merge pull request #1049 from Subv/stencil
Rasterizer: Corrected the stencil implementation.
Diffstat (limited to 'src/video_core/rasterizer.cpp')
| -rw-r--r-- | src/video_core/rasterizer.cpp | 58 |
1 files changed, 39 insertions, 19 deletions
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 4a159da8e..77eadda9e 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp | |||
| @@ -216,14 +216,33 @@ static void SetStencil(int x, int y, u8 value) { | |||
| 216 | } | 216 | } |
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | // TODO: Should the stencil mask be applied to the "dest" or "ref" operands? Most likely not! | 219 | static u8 PerformStencilAction(Regs::StencilAction action, u8 old_stencil, u8 ref) { |
| 220 | static u8 PerformStencilAction(Regs::StencilAction action, u8 dest, u8 ref) { | ||
| 221 | switch (action) { | 220 | switch (action) { |
| 222 | case Regs::StencilAction::Keep: | 221 | case Regs::StencilAction::Keep: |
| 223 | return dest; | 222 | return old_stencil; |
| 224 | 223 | ||
| 225 | case Regs::StencilAction::Xor: | 224 | case Regs::StencilAction::Zero: |
| 226 | return dest ^ ref; | 225 | return 0; |
| 226 | |||
| 227 | case Regs::StencilAction::Replace: | ||
| 228 | return ref; | ||
| 229 | |||
| 230 | case Regs::StencilAction::Increment: | ||
| 231 | // Saturated increment | ||
| 232 | return std::min<u8>(old_stencil, 254) + 1; | ||
| 233 | |||
| 234 | case Regs::StencilAction::Decrement: | ||
| 235 | // Saturated decrement | ||
| 236 | return std::max<u8>(old_stencil, 1) - 1; | ||
| 237 | |||
| 238 | case Regs::StencilAction::Invert: | ||
| 239 | return ~old_stencil; | ||
| 240 | |||
| 241 | case Regs::StencilAction::IncrementWrap: | ||
| 242 | return old_stencil + 1; | ||
| 243 | |||
| 244 | case Regs::StencilAction::DecrementWrap: | ||
| 245 | return old_stencil - 1; | ||
| 227 | 246 | ||
| 228 | default: | 247 | default: |
| 229 | LOG_CRITICAL(HW_GPU, "Unknown stencil action %x", (int)action); | 248 | LOG_CRITICAL(HW_GPU, "Unknown stencil action %x", (int)action); |
| @@ -783,10 +802,16 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 783 | } | 802 | } |
| 784 | 803 | ||
| 785 | u8 old_stencil = 0; | 804 | u8 old_stencil = 0; |
| 805 | |||
| 806 | auto UpdateStencil = [stencil_test, x, y, &old_stencil](Pica::Regs::StencilAction action) { | ||
| 807 | u8 new_stencil = PerformStencilAction(action, old_stencil, stencil_test.reference_value); | ||
| 808 | SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) | (old_stencil & ~stencil_test.write_mask)); | ||
| 809 | }; | ||
| 810 | |||
| 786 | if (stencil_action_enable) { | 811 | if (stencil_action_enable) { |
| 787 | old_stencil = GetStencil(x >> 4, y >> 4); | 812 | old_stencil = GetStencil(x >> 4, y >> 4); |
| 788 | u8 dest = old_stencil & stencil_test.mask; | 813 | u8 dest = old_stencil & stencil_test.input_mask; |
| 789 | u8 ref = stencil_test.reference_value & stencil_test.mask; | 814 | u8 ref = stencil_test.reference_value & stencil_test.input_mask; |
| 790 | 815 | ||
| 791 | bool pass = false; | 816 | bool pass = false; |
| 792 | switch (stencil_test.func) { | 817 | switch (stencil_test.func) { |
| @@ -824,8 +849,7 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 824 | } | 849 | } |
| 825 | 850 | ||
| 826 | if (!pass) { | 851 | if (!pass) { |
| 827 | u8 new_stencil = PerformStencilAction(stencil_test.action_stencil_fail, old_stencil, stencil_test.replacement_value); | 852 | UpdateStencil(stencil_test.action_stencil_fail); |
| 828 | SetStencil(x >> 4, y >> 4, new_stencil); | ||
| 829 | continue; | 853 | continue; |
| 830 | } | 854 | } |
| 831 | } | 855 | } |
| @@ -875,23 +899,19 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 875 | } | 899 | } |
| 876 | 900 | ||
| 877 | if (!pass) { | 901 | if (!pass) { |
| 878 | if (stencil_action_enable) { | 902 | if (stencil_action_enable) |
| 879 | u8 new_stencil = PerformStencilAction(stencil_test.action_depth_fail, old_stencil, stencil_test.replacement_value); | 903 | UpdateStencil(stencil_test.action_depth_fail); |
| 880 | SetStencil(x >> 4, y >> 4, new_stencil); | ||
| 881 | } | ||
| 882 | continue; | 904 | continue; |
| 883 | } | 905 | } |
| 884 | 906 | ||
| 885 | if (output_merger.depth_write_enable) | 907 | if (output_merger.depth_write_enable) |
| 886 | SetDepth(x >> 4, y >> 4, z); | 908 | SetDepth(x >> 4, y >> 4, z); |
| 887 | |||
| 888 | if (stencil_action_enable) { | ||
| 889 | // TODO: What happens if stencil testing is enabled, but depth testing is not? Will stencil get updated anyway? | ||
| 890 | u8 new_stencil = PerformStencilAction(stencil_test.action_depth_pass, old_stencil, stencil_test.replacement_value); | ||
| 891 | SetStencil(x >> 4, y >> 4, new_stencil); | ||
| 892 | } | ||
| 893 | } | 909 | } |
| 894 | 910 | ||
| 911 | // The stencil depth_pass action is executed even if depth testing is disabled | ||
| 912 | if (stencil_action_enable) | ||
| 913 | UpdateStencil(stencil_test.action_depth_pass); | ||
| 914 | |||
| 895 | auto dest = GetPixel(x >> 4, y >> 4); | 915 | auto dest = GetPixel(x >> 4, y >> 4); |
| 896 | Math::Vec4<u8> blend_output = combiner_output; | 916 | Math::Vec4<u8> blend_output = combiner_output; |
| 897 | 917 | ||