summaryrefslogtreecommitdiff
path: root/src/video_core/rasterizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/rasterizer.cpp')
-rw-r--r--src/video_core/rasterizer.cpp229
1 files changed, 118 insertions, 111 deletions
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 48bc26571..f053143f1 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -29,7 +29,7 @@ namespace Pica {
29namespace Rasterizer { 29namespace Rasterizer {
30 30
31static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { 31static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
32 const auto& framebuffer = g_state.regs.framebuffer; 32 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
33 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress(); 33 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
34 34
35 // Similarly to textures, the render framebuffer is laid out from bottom to top, too. 35 // Similarly to textures, the render framebuffer is laid out from bottom to top, too.
@@ -44,23 +44,23 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
44 u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset; 44 u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset;
45 45
46 switch (framebuffer.color_format) { 46 switch (framebuffer.color_format) {
47 case Regs::ColorFormat::RGBA8: 47 case FramebufferRegs::ColorFormat::RGBA8:
48 Color::EncodeRGBA8(color, dst_pixel); 48 Color::EncodeRGBA8(color, dst_pixel);
49 break; 49 break;
50 50
51 case Regs::ColorFormat::RGB8: 51 case FramebufferRegs::ColorFormat::RGB8:
52 Color::EncodeRGB8(color, dst_pixel); 52 Color::EncodeRGB8(color, dst_pixel);
53 break; 53 break;
54 54
55 case Regs::ColorFormat::RGB5A1: 55 case FramebufferRegs::ColorFormat::RGB5A1:
56 Color::EncodeRGB5A1(color, dst_pixel); 56 Color::EncodeRGB5A1(color, dst_pixel);
57 break; 57 break;
58 58
59 case Regs::ColorFormat::RGB565: 59 case FramebufferRegs::ColorFormat::RGB565:
60 Color::EncodeRGB565(color, dst_pixel); 60 Color::EncodeRGB565(color, dst_pixel);
61 break; 61 break;
62 62
63 case Regs::ColorFormat::RGBA4: 63 case FramebufferRegs::ColorFormat::RGBA4:
64 Color::EncodeRGBA4(color, dst_pixel); 64 Color::EncodeRGBA4(color, dst_pixel);
65 break; 65 break;
66 66
@@ -72,7 +72,7 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
72} 72}
73 73
74static const Math::Vec4<u8> GetPixel(int x, int y) { 74static const Math::Vec4<u8> GetPixel(int x, int y) {
75 const auto& framebuffer = g_state.regs.framebuffer; 75 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
76 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress(); 76 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
77 77
78 y = framebuffer.height - y; 78 y = framebuffer.height - y;
@@ -85,19 +85,19 @@ static const Math::Vec4<u8> GetPixel(int x, int y) {
85 u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset; 85 u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset;
86 86
87 switch (framebuffer.color_format) { 87 switch (framebuffer.color_format) {
88 case Regs::ColorFormat::RGBA8: 88 case FramebufferRegs::ColorFormat::RGBA8:
89 return Color::DecodeRGBA8(src_pixel); 89 return Color::DecodeRGBA8(src_pixel);
90 90
91 case Regs::ColorFormat::RGB8: 91 case FramebufferRegs::ColorFormat::RGB8:
92 return Color::DecodeRGB8(src_pixel); 92 return Color::DecodeRGB8(src_pixel);
93 93
94 case Regs::ColorFormat::RGB5A1: 94 case FramebufferRegs::ColorFormat::RGB5A1:
95 return Color::DecodeRGB5A1(src_pixel); 95 return Color::DecodeRGB5A1(src_pixel);
96 96
97 case Regs::ColorFormat::RGB565: 97 case FramebufferRegs::ColorFormat::RGB565:
98 return Color::DecodeRGB565(src_pixel); 98 return Color::DecodeRGB565(src_pixel);
99 99
100 case Regs::ColorFormat::RGBA4: 100 case FramebufferRegs::ColorFormat::RGBA4:
101 return Color::DecodeRGBA4(src_pixel); 101 return Color::DecodeRGBA4(src_pixel);
102 102
103 default: 103 default:
@@ -110,25 +110,25 @@ static const Math::Vec4<u8> GetPixel(int x, int y) {
110} 110}
111 111
112static u32 GetDepth(int x, int y) { 112static u32 GetDepth(int x, int y) {
113 const auto& framebuffer = g_state.regs.framebuffer; 113 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
114 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); 114 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
115 u8* depth_buffer = Memory::GetPhysicalPointer(addr); 115 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
116 116
117 y = framebuffer.height - y; 117 y = framebuffer.height - y;
118 118
119 const u32 coarse_y = y & ~7; 119 const u32 coarse_y = y & ~7;
120 u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format); 120 u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
121 u32 stride = framebuffer.width * bytes_per_pixel; 121 u32 stride = framebuffer.width * bytes_per_pixel;
122 122
123 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; 123 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
124 u8* src_pixel = depth_buffer + src_offset; 124 u8* src_pixel = depth_buffer + src_offset;
125 125
126 switch (framebuffer.depth_format) { 126 switch (framebuffer.depth_format) {
127 case Regs::DepthFormat::D16: 127 case FramebufferRegs::DepthFormat::D16:
128 return Color::DecodeD16(src_pixel); 128 return Color::DecodeD16(src_pixel);
129 case Regs::DepthFormat::D24: 129 case FramebufferRegs::DepthFormat::D24:
130 return Color::DecodeD24(src_pixel); 130 return Color::DecodeD24(src_pixel);
131 case Regs::DepthFormat::D24S8: 131 case FramebufferRegs::DepthFormat::D24S8:
132 return Color::DecodeD24S8(src_pixel).x; 132 return Color::DecodeD24S8(src_pixel).x;
133 default: 133 default:
134 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); 134 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
@@ -138,21 +138,21 @@ static u32 GetDepth(int x, int y) {
138} 138}
139 139
140static u8 GetStencil(int x, int y) { 140static u8 GetStencil(int x, int y) {
141 const auto& framebuffer = g_state.regs.framebuffer; 141 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
142 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); 142 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
143 u8* depth_buffer = Memory::GetPhysicalPointer(addr); 143 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
144 144
145 y = framebuffer.height - y; 145 y = framebuffer.height - y;
146 146
147 const u32 coarse_y = y & ~7; 147 const u32 coarse_y = y & ~7;
148 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format); 148 u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
149 u32 stride = framebuffer.width * bytes_per_pixel; 149 u32 stride = framebuffer.width * bytes_per_pixel;
150 150
151 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; 151 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
152 u8* src_pixel = depth_buffer + src_offset; 152 u8* src_pixel = depth_buffer + src_offset;
153 153
154 switch (framebuffer.depth_format) { 154 switch (framebuffer.depth_format) {
155 case Regs::DepthFormat::D24S8: 155 case FramebufferRegs::DepthFormat::D24S8:
156 return Color::DecodeD24S8(src_pixel).y; 156 return Color::DecodeD24S8(src_pixel).y;
157 157
158 default: 158 default:
@@ -165,29 +165,29 @@ static u8 GetStencil(int x, int y) {
165} 165}
166 166
167static void SetDepth(int x, int y, u32 value) { 167static void SetDepth(int x, int y, u32 value) {
168 const auto& framebuffer = g_state.regs.framebuffer; 168 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
169 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); 169 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
170 u8* depth_buffer = Memory::GetPhysicalPointer(addr); 170 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
171 171
172 y = framebuffer.height - y; 172 y = framebuffer.height - y;
173 173
174 const u32 coarse_y = y & ~7; 174 const u32 coarse_y = y & ~7;
175 u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format); 175 u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
176 u32 stride = framebuffer.width * bytes_per_pixel; 176 u32 stride = framebuffer.width * bytes_per_pixel;
177 177
178 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; 178 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
179 u8* dst_pixel = depth_buffer + dst_offset; 179 u8* dst_pixel = depth_buffer + dst_offset;
180 180
181 switch (framebuffer.depth_format) { 181 switch (framebuffer.depth_format) {
182 case Regs::DepthFormat::D16: 182 case FramebufferRegs::DepthFormat::D16:
183 Color::EncodeD16(value, dst_pixel); 183 Color::EncodeD16(value, dst_pixel);
184 break; 184 break;
185 185
186 case Regs::DepthFormat::D24: 186 case FramebufferRegs::DepthFormat::D24:
187 Color::EncodeD24(value, dst_pixel); 187 Color::EncodeD24(value, dst_pixel);
188 break; 188 break;
189 189
190 case Regs::DepthFormat::D24S8: 190 case FramebufferRegs::DepthFormat::D24S8:
191 Color::EncodeD24X8(value, dst_pixel); 191 Color::EncodeD24X8(value, dst_pixel);
192 break; 192 break;
193 193
@@ -199,26 +199,26 @@ static void SetDepth(int x, int y, u32 value) {
199} 199}
200 200
201static void SetStencil(int x, int y, u8 value) { 201static void SetStencil(int x, int y, u8 value) {
202 const auto& framebuffer = g_state.regs.framebuffer; 202 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
203 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); 203 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
204 u8* depth_buffer = Memory::GetPhysicalPointer(addr); 204 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
205 205
206 y = framebuffer.height - y; 206 y = framebuffer.height - y;
207 207
208 const u32 coarse_y = y & ~7; 208 const u32 coarse_y = y & ~7;
209 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format); 209 u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
210 u32 stride = framebuffer.width * bytes_per_pixel; 210 u32 stride = framebuffer.width * bytes_per_pixel;
211 211
212 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; 212 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
213 u8* dst_pixel = depth_buffer + dst_offset; 213 u8* dst_pixel = depth_buffer + dst_offset;
214 214
215 switch (framebuffer.depth_format) { 215 switch (framebuffer.depth_format) {
216 case Pica::Regs::DepthFormat::D16: 216 case Pica::FramebufferRegs::DepthFormat::D16:
217 case Pica::Regs::DepthFormat::D24: 217 case Pica::FramebufferRegs::DepthFormat::D24:
218 // Nothing to do 218 // Nothing to do
219 break; 219 break;
220 220
221 case Pica::Regs::DepthFormat::D24S8: 221 case Pica::FramebufferRegs::DepthFormat::D24S8:
222 Color::EncodeX24S8(value, dst_pixel); 222 Color::EncodeX24S8(value, dst_pixel);
223 break; 223 break;
224 224
@@ -229,32 +229,32 @@ static void SetStencil(int x, int y, u8 value) {
229 } 229 }
230} 230}
231 231
232static u8 PerformStencilAction(Regs::StencilAction action, u8 old_stencil, u8 ref) { 232static u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref) {
233 switch (action) { 233 switch (action) {
234 case Regs::StencilAction::Keep: 234 case FramebufferRegs::StencilAction::Keep:
235 return old_stencil; 235 return old_stencil;
236 236
237 case Regs::StencilAction::Zero: 237 case FramebufferRegs::StencilAction::Zero:
238 return 0; 238 return 0;
239 239
240 case Regs::StencilAction::Replace: 240 case FramebufferRegs::StencilAction::Replace:
241 return ref; 241 return ref;
242 242
243 case Regs::StencilAction::Increment: 243 case FramebufferRegs::StencilAction::Increment:
244 // Saturated increment 244 // Saturated increment
245 return std::min<u8>(old_stencil, 254) + 1; 245 return std::min<u8>(old_stencil, 254) + 1;
246 246
247 case Regs::StencilAction::Decrement: 247 case FramebufferRegs::StencilAction::Decrement:
248 // Saturated decrement 248 // Saturated decrement
249 return std::max<u8>(old_stencil, 1) - 1; 249 return std::max<u8>(old_stencil, 1) - 1;
250 250
251 case Regs::StencilAction::Invert: 251 case FramebufferRegs::StencilAction::Invert:
252 return ~old_stencil; 252 return ~old_stencil;
253 253
254 case Regs::StencilAction::IncrementWrap: 254 case FramebufferRegs::StencilAction::IncrementWrap:
255 return old_stencil + 1; 255 return old_stencil + 1;
256 256
257 case Regs::StencilAction::DecrementWrap: 257 case FramebufferRegs::StencilAction::DecrementWrap:
258 return old_stencil - 1; 258 return old_stencil - 1;
259 259
260 default: 260 default:
@@ -400,9 +400,10 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
400 auto textures = regs.texturing.GetTextures(); 400 auto textures = regs.texturing.GetTextures();
401 auto tev_stages = regs.texturing.GetTevStages(); 401 auto tev_stages = regs.texturing.GetTevStages();
402 402
403 bool stencil_action_enable = g_state.regs.output_merger.stencil_test.enable && 403 bool stencil_action_enable =
404 g_state.regs.framebuffer.depth_format == Regs::DepthFormat::D24S8; 404 g_state.regs.framebuffer.output_merger.stencil_test.enable &&
405 const auto stencil_test = g_state.regs.output_merger.stencil_test; 405 g_state.regs.framebuffer.framebuffer.depth_format == FramebufferRegs::DepthFormat::D24S8;
406 const auto stencil_test = g_state.regs.framebuffer.output_merger.stencil_test;
406 407
407 // Enter rasterization loop, starting at the center of the topleft bounding box corner. 408 // Enter rasterization loop, starting at the center of the topleft bounding box corner.
408 // TODO: Not sure if looping through x first might be faster 409 // TODO: Not sure if looping through x first might be faster
@@ -879,41 +880,41 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
879 } 880 }
880 } 881 }
881 882
882 const auto& output_merger = regs.output_merger; 883 const auto& output_merger = regs.framebuffer.output_merger;
883 // TODO: Does alpha testing happen before or after stencil? 884 // TODO: Does alpha testing happen before or after stencil?
884 if (output_merger.alpha_test.enable) { 885 if (output_merger.alpha_test.enable) {
885 bool pass = false; 886 bool pass = false;
886 887
887 switch (output_merger.alpha_test.func) { 888 switch (output_merger.alpha_test.func) {
888 case Regs::CompareFunc::Never: 889 case FramebufferRegs::CompareFunc::Never:
889 pass = false; 890 pass = false;
890 break; 891 break;
891 892
892 case Regs::CompareFunc::Always: 893 case FramebufferRegs::CompareFunc::Always:
893 pass = true; 894 pass = true;
894 break; 895 break;
895 896
896 case Regs::CompareFunc::Equal: 897 case FramebufferRegs::CompareFunc::Equal:
897 pass = combiner_output.a() == output_merger.alpha_test.ref; 898 pass = combiner_output.a() == output_merger.alpha_test.ref;
898 break; 899 break;
899 900
900 case Regs::CompareFunc::NotEqual: 901 case FramebufferRegs::CompareFunc::NotEqual:
901 pass = combiner_output.a() != output_merger.alpha_test.ref; 902 pass = combiner_output.a() != output_merger.alpha_test.ref;
902 break; 903 break;
903 904
904 case Regs::CompareFunc::LessThan: 905 case FramebufferRegs::CompareFunc::LessThan:
905 pass = combiner_output.a() < output_merger.alpha_test.ref; 906 pass = combiner_output.a() < output_merger.alpha_test.ref;
906 break; 907 break;
907 908
908 case Regs::CompareFunc::LessThanOrEqual: 909 case FramebufferRegs::CompareFunc::LessThanOrEqual:
909 pass = combiner_output.a() <= output_merger.alpha_test.ref; 910 pass = combiner_output.a() <= output_merger.alpha_test.ref;
910 break; 911 break;
911 912
912 case Regs::CompareFunc::GreaterThan: 913 case FramebufferRegs::CompareFunc::GreaterThan:
913 pass = combiner_output.a() > output_merger.alpha_test.ref; 914 pass = combiner_output.a() > output_merger.alpha_test.ref;
914 break; 915 break;
915 916
916 case Regs::CompareFunc::GreaterThanOrEqual: 917 case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
917 pass = combiner_output.a() >= output_merger.alpha_test.ref; 918 pass = combiner_output.a() >= output_merger.alpha_test.ref;
918 break; 919 break;
919 } 920 }
@@ -959,10 +960,10 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
959 u8 old_stencil = 0; 960 u8 old_stencil = 0;
960 961
961 auto UpdateStencil = [stencil_test, x, y, 962 auto UpdateStencil = [stencil_test, x, y,
962 &old_stencil](Pica::Regs::StencilAction action) { 963 &old_stencil](Pica::FramebufferRegs::StencilAction action) {
963 u8 new_stencil = 964 u8 new_stencil =
964 PerformStencilAction(action, old_stencil, stencil_test.reference_value); 965 PerformStencilAction(action, old_stencil, stencil_test.reference_value);
965 if (g_state.regs.framebuffer.allow_depth_stencil_write != 0) 966 if (g_state.regs.framebuffer.framebuffer.allow_depth_stencil_write != 0)
966 SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) | 967 SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) |
967 (old_stencil & ~stencil_test.write_mask)); 968 (old_stencil & ~stencil_test.write_mask));
968 }; 969 };
@@ -974,35 +975,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
974 975
975 bool pass = false; 976 bool pass = false;
976 switch (stencil_test.func) { 977 switch (stencil_test.func) {
977 case Regs::CompareFunc::Never: 978 case FramebufferRegs::CompareFunc::Never:
978 pass = false; 979 pass = false;
979 break; 980 break;
980 981
981 case Regs::CompareFunc::Always: 982 case FramebufferRegs::CompareFunc::Always:
982 pass = true; 983 pass = true;
983 break; 984 break;
984 985
985 case Regs::CompareFunc::Equal: 986 case FramebufferRegs::CompareFunc::Equal:
986 pass = (ref == dest); 987 pass = (ref == dest);
987 break; 988 break;
988 989
989 case Regs::CompareFunc::NotEqual: 990 case FramebufferRegs::CompareFunc::NotEqual:
990 pass = (ref != dest); 991 pass = (ref != dest);
991 break; 992 break;
992 993
993 case Regs::CompareFunc::LessThan: 994 case FramebufferRegs::CompareFunc::LessThan:
994 pass = (ref < dest); 995 pass = (ref < dest);
995 break; 996 break;
996 997
997 case Regs::CompareFunc::LessThanOrEqual: 998 case FramebufferRegs::CompareFunc::LessThanOrEqual:
998 pass = (ref <= dest); 999 pass = (ref <= dest);
999 break; 1000 break;
1000 1001
1001 case Regs::CompareFunc::GreaterThan: 1002 case FramebufferRegs::CompareFunc::GreaterThan:
1002 pass = (ref > dest); 1003 pass = (ref > dest);
1003 break; 1004 break;
1004 1005
1005 case Regs::CompareFunc::GreaterThanOrEqual: 1006 case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
1006 pass = (ref >= dest); 1007 pass = (ref >= dest);
1007 break; 1008 break;
1008 } 1009 }
@@ -1014,7 +1015,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1014 } 1015 }
1015 1016
1016 // Convert float to integer 1017 // Convert float to integer
1017 unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format); 1018 unsigned num_bits =
1019 FramebufferRegs::DepthBitsPerPixel(regs.framebuffer.framebuffer.depth_format);
1018 u32 z = (u32)(depth * ((1 << num_bits) - 1)); 1020 u32 z = (u32)(depth * ((1 << num_bits) - 1));
1019 1021
1020 if (output_merger.depth_test_enable) { 1022 if (output_merger.depth_test_enable) {
@@ -1023,35 +1025,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1023 bool pass = false; 1025 bool pass = false;
1024 1026
1025 switch (output_merger.depth_test_func) { 1027 switch (output_merger.depth_test_func) {
1026 case Regs::CompareFunc::Never: 1028 case FramebufferRegs::CompareFunc::Never:
1027 pass = false; 1029 pass = false;
1028 break; 1030 break;
1029 1031
1030 case Regs::CompareFunc::Always: 1032 case FramebufferRegs::CompareFunc::Always:
1031 pass = true; 1033 pass = true;
1032 break; 1034 break;
1033 1035
1034 case Regs::CompareFunc::Equal: 1036 case FramebufferRegs::CompareFunc::Equal:
1035 pass = z == ref_z; 1037 pass = z == ref_z;
1036 break; 1038 break;
1037 1039
1038 case Regs::CompareFunc::NotEqual: 1040 case FramebufferRegs::CompareFunc::NotEqual:
1039 pass = z != ref_z; 1041 pass = z != ref_z;
1040 break; 1042 break;
1041 1043
1042 case Regs::CompareFunc::LessThan: 1044 case FramebufferRegs::CompareFunc::LessThan:
1043 pass = z < ref_z; 1045 pass = z < ref_z;
1044 break; 1046 break;
1045 1047
1046 case Regs::CompareFunc::LessThanOrEqual: 1048 case FramebufferRegs::CompareFunc::LessThanOrEqual:
1047 pass = z <= ref_z; 1049 pass = z <= ref_z;
1048 break; 1050 break;
1049 1051
1050 case Regs::CompareFunc::GreaterThan: 1052 case FramebufferRegs::CompareFunc::GreaterThan:
1051 pass = z > ref_z; 1053 pass = z > ref_z;
1052 break; 1054 break;
1053 1055
1054 case Regs::CompareFunc::GreaterThanOrEqual: 1056 case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
1055 pass = z >= ref_z; 1057 pass = z >= ref_z;
1056 break; 1058 break;
1057 } 1059 }
@@ -1063,8 +1065,11 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1063 } 1065 }
1064 } 1066 }
1065 1067
1066 if (regs.framebuffer.allow_depth_stencil_write != 0 && output_merger.depth_write_enable) 1068 if (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 &&
1069 output_merger.depth_write_enable) {
1070
1067 SetDepth(x >> 4, y >> 4, z); 1071 SetDepth(x >> 4, y >> 4, z);
1072 }
1068 1073
1069 // The stencil depth_pass action is executed even if depth testing is disabled 1074 // The stencil depth_pass action is executed even if depth testing is disabled
1070 if (stencil_action_enable) 1075 if (stencil_action_enable)
@@ -1076,7 +1081,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1076 if (output_merger.alphablend_enable) { 1081 if (output_merger.alphablend_enable) {
1077 auto params = output_merger.alpha_blending; 1082 auto params = output_merger.alpha_blending;
1078 1083
1079 auto LookupFactor = [&](unsigned channel, Regs::BlendFactor factor) -> u8 { 1084 auto LookupFactor = [&](unsigned channel,
1085 FramebufferRegs::BlendFactor factor) -> u8 {
1080 DEBUG_ASSERT(channel < 4); 1086 DEBUG_ASSERT(channel < 4);
1081 1087
1082 const Math::Vec4<u8> blend_const = { 1088 const Math::Vec4<u8> blend_const = {
@@ -1087,49 +1093,49 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1087 }; 1093 };
1088 1094
1089 switch (factor) { 1095 switch (factor) {
1090 case Regs::BlendFactor::Zero: 1096 case FramebufferRegs::BlendFactor::Zero:
1091 return 0; 1097 return 0;
1092 1098
1093 case Regs::BlendFactor::One: 1099 case FramebufferRegs::BlendFactor::One:
1094 return 255; 1100 return 255;
1095 1101
1096 case Regs::BlendFactor::SourceColor: 1102 case FramebufferRegs::BlendFactor::SourceColor:
1097 return combiner_output[channel]; 1103 return combiner_output[channel];
1098 1104
1099 case Regs::BlendFactor::OneMinusSourceColor: 1105 case FramebufferRegs::BlendFactor::OneMinusSourceColor:
1100 return 255 - combiner_output[channel]; 1106 return 255 - combiner_output[channel];
1101 1107
1102 case Regs::BlendFactor::DestColor: 1108 case FramebufferRegs::BlendFactor::DestColor:
1103 return dest[channel]; 1109 return dest[channel];
1104 1110
1105 case Regs::BlendFactor::OneMinusDestColor: 1111 case FramebufferRegs::BlendFactor::OneMinusDestColor:
1106 return 255 - dest[channel]; 1112 return 255 - dest[channel];
1107 1113
1108 case Regs::BlendFactor::SourceAlpha: 1114 case FramebufferRegs::BlendFactor::SourceAlpha:
1109 return combiner_output.a(); 1115 return combiner_output.a();
1110 1116
1111 case Regs::BlendFactor::OneMinusSourceAlpha: 1117 case FramebufferRegs::BlendFactor::OneMinusSourceAlpha:
1112 return 255 - combiner_output.a(); 1118 return 255 - combiner_output.a();
1113 1119
1114 case Regs::BlendFactor::DestAlpha: 1120 case FramebufferRegs::BlendFactor::DestAlpha:
1115 return dest.a(); 1121 return dest.a();
1116 1122
1117 case Regs::BlendFactor::OneMinusDestAlpha: 1123 case FramebufferRegs::BlendFactor::OneMinusDestAlpha:
1118 return 255 - dest.a(); 1124 return 255 - dest.a();
1119 1125
1120 case Regs::BlendFactor::ConstantColor: 1126 case FramebufferRegs::BlendFactor::ConstantColor:
1121 return blend_const[channel]; 1127 return blend_const[channel];
1122 1128
1123 case Regs::BlendFactor::OneMinusConstantColor: 1129 case FramebufferRegs::BlendFactor::OneMinusConstantColor:
1124 return 255 - blend_const[channel]; 1130 return 255 - blend_const[channel];
1125 1131
1126 case Regs::BlendFactor::ConstantAlpha: 1132 case FramebufferRegs::BlendFactor::ConstantAlpha:
1127 return blend_const.a(); 1133 return blend_const.a();
1128 1134
1129 case Regs::BlendFactor::OneMinusConstantAlpha: 1135 case FramebufferRegs::BlendFactor::OneMinusConstantAlpha:
1130 return 255 - blend_const.a(); 1136 return 255 - blend_const.a();
1131 1137
1132 case Regs::BlendFactor::SourceAlphaSaturate: 1138 case FramebufferRegs::BlendFactor::SourceAlphaSaturate:
1133 // Returns 1.0 for the alpha channel 1139 // Returns 1.0 for the alpha channel
1134 if (channel == 3) 1140 if (channel == 3)
1135 return 255; 1141 return 255;
@@ -1147,36 +1153,37 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1147 static auto EvaluateBlendEquation = []( 1153 static auto EvaluateBlendEquation = [](
1148 const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor, 1154 const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
1149 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor, 1155 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
1150 Regs::BlendEquation equation) { 1156 FramebufferRegs::BlendEquation equation) {
1157
1151 Math::Vec4<int> result; 1158 Math::Vec4<int> result;
1152 1159
1153 auto src_result = (src * srcfactor).Cast<int>(); 1160 auto src_result = (src * srcfactor).Cast<int>();
1154 auto dst_result = (dest * destfactor).Cast<int>(); 1161 auto dst_result = (dest * destfactor).Cast<int>();
1155 1162
1156 switch (equation) { 1163 switch (equation) {
1157 case Regs::BlendEquation::Add: 1164 case FramebufferRegs::BlendEquation::Add:
1158 result = (src_result + dst_result) / 255; 1165 result = (src_result + dst_result) / 255;
1159 break; 1166 break;
1160 1167
1161 case Regs::BlendEquation::Subtract: 1168 case FramebufferRegs::BlendEquation::Subtract:
1162 result = (src_result - dst_result) / 255; 1169 result = (src_result - dst_result) / 255;
1163 break; 1170 break;
1164 1171
1165 case Regs::BlendEquation::ReverseSubtract: 1172 case FramebufferRegs::BlendEquation::ReverseSubtract:
1166 result = (dst_result - src_result) / 255; 1173 result = (dst_result - src_result) / 255;
1167 break; 1174 break;
1168 1175
1169 // TODO: How do these two actually work? 1176 // TODO: How do these two actually work?
1170 // OpenGL doesn't include the blend factors in the min/max computations, 1177 // OpenGL doesn't include the blend factors in the min/max computations,
1171 // but is this what the 3DS actually does? 1178 // but is this what the 3DS actually does?
1172 case Regs::BlendEquation::Min: 1179 case FramebufferRegs::BlendEquation::Min:
1173 result.r() = std::min(src.r(), dest.r()); 1180 result.r() = std::min(src.r(), dest.r());
1174 result.g() = std::min(src.g(), dest.g()); 1181 result.g() = std::min(src.g(), dest.g());
1175 result.b() = std::min(src.b(), dest.b()); 1182 result.b() = std::min(src.b(), dest.b());
1176 result.a() = std::min(src.a(), dest.a()); 1183 result.a() = std::min(src.a(), dest.a());
1177 break; 1184 break;
1178 1185
1179 case Regs::BlendEquation::Max: 1186 case FramebufferRegs::BlendEquation::Max:
1180 result.r() = std::max(src.r(), dest.r()); 1187 result.r() = std::max(src.r(), dest.r());
1181 result.g() = std::max(src.g(), dest.g()); 1188 result.g() = std::max(src.g(), dest.g());
1182 result.b() = std::max(src.b(), dest.b()); 1189 result.b() = std::max(src.b(), dest.b());
@@ -1209,54 +1216,54 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1209 dstfactor, params.blend_equation_a) 1216 dstfactor, params.blend_equation_a)
1210 .a(); 1217 .a();
1211 } else { 1218 } else {
1212 static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 { 1219 static auto LogicOp = [](u8 src, u8 dest, FramebufferRegs::LogicOp op) -> u8 {
1213 switch (op) { 1220 switch (op) {
1214 case Regs::LogicOp::Clear: 1221 case FramebufferRegs::LogicOp::Clear:
1215 return 0; 1222 return 0;
1216 1223
1217 case Regs::LogicOp::And: 1224 case FramebufferRegs::LogicOp::And:
1218 return src & dest; 1225 return src & dest;
1219 1226
1220 case Regs::LogicOp::AndReverse: 1227 case FramebufferRegs::LogicOp::AndReverse:
1221 return src & ~dest; 1228 return src & ~dest;
1222 1229
1223 case Regs::LogicOp::Copy: 1230 case FramebufferRegs::LogicOp::Copy:
1224 return src; 1231 return src;
1225 1232
1226 case Regs::LogicOp::Set: 1233 case FramebufferRegs::LogicOp::Set:
1227 return 255; 1234 return 255;
1228 1235
1229 case Regs::LogicOp::CopyInverted: 1236 case FramebufferRegs::LogicOp::CopyInverted:
1230 return ~src; 1237 return ~src;
1231 1238
1232 case Regs::LogicOp::NoOp: 1239 case FramebufferRegs::LogicOp::NoOp:
1233 return dest; 1240 return dest;
1234 1241
1235 case Regs::LogicOp::Invert: 1242 case FramebufferRegs::LogicOp::Invert:
1236 return ~dest; 1243 return ~dest;
1237 1244
1238 case Regs::LogicOp::Nand: 1245 case FramebufferRegs::LogicOp::Nand:
1239 return ~(src & dest); 1246 return ~(src & dest);
1240 1247
1241 case Regs::LogicOp::Or: 1248 case FramebufferRegs::LogicOp::Or:
1242 return src | dest; 1249 return src | dest;
1243 1250
1244 case Regs::LogicOp::Nor: 1251 case FramebufferRegs::LogicOp::Nor:
1245 return ~(src | dest); 1252 return ~(src | dest);
1246 1253
1247 case Regs::LogicOp::Xor: 1254 case FramebufferRegs::LogicOp::Xor:
1248 return src ^ dest; 1255 return src ^ dest;
1249 1256
1250 case Regs::LogicOp::Equiv: 1257 case FramebufferRegs::LogicOp::Equiv:
1251 return ~(src ^ dest); 1258 return ~(src ^ dest);
1252 1259
1253 case Regs::LogicOp::AndInverted: 1260 case FramebufferRegs::LogicOp::AndInverted:
1254 return ~src & dest; 1261 return ~src & dest;
1255 1262
1256 case Regs::LogicOp::OrReverse: 1263 case FramebufferRegs::LogicOp::OrReverse:
1257 return src | ~dest; 1264 return src | ~dest;
1258 1265
1259 case Regs::LogicOp::OrInverted: 1266 case FramebufferRegs::LogicOp::OrInverted:
1260 return ~src | dest; 1267 return ~src | dest;
1261 } 1268 }
1262 }; 1269 };
@@ -1275,7 +1282,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1275 output_merger.alpha_enable ? blend_output.a() : dest.a(), 1282 output_merger.alpha_enable ? blend_output.a() : dest.a(),
1276 }; 1283 };
1277 1284
1278 if (regs.framebuffer.allow_color_write != 0) 1285 if (regs.framebuffer.framebuffer.allow_color_write != 0)
1279 DrawPixel(x >> 4, y >> 4, result); 1286 DrawPixel(x >> 4, y >> 4, result);
1280 } 1287 }
1281 } 1288 }