summaryrefslogtreecommitdiff
path: root/src/video_core/rasterizer.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2015-08-29 20:06:25 -0400
committerGravatar bunnei2015-08-29 20:06:25 -0400
commit58e9f78844168e2770bf0b43d6931569642f27fb (patch)
treef0a3705f7e09bf6a067467553eac2119a691984b /src/video_core/rasterizer.cpp
parentMerge pull request #1080 from yuriks/linear-heap-base-typo (diff)
parentHWRenderer: Added a workaround for the Intel Windows driver bug that causes g... (diff)
downloadyuzu-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.cpp58
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! 219static u8 PerformStencilAction(Regs::StencilAction action, u8 old_stencil, u8 ref) {
220static 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