summaryrefslogtreecommitdiff
path: root/src/video_core/rasterizer.cpp
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2017-02-08 22:07:34 -0800
committerGravatar GitHub2017-02-08 22:07:34 -0800
commit2889372e47624e368df0d0361cb38b8100f047dd (patch)
tree183cd1cd6edb60ab566bd1fe181b712643bef30c /src/video_core/rasterizer.cpp
parentMerge pull request #2539 from Kloen/re-killing-warnings (diff)
parentVideoCore: Move Regs to its own file (diff)
downloadyuzu-2889372e47624e368df0d0361cb38b8100f047dd.tar.gz
yuzu-2889372e47624e368df0d0361cb38b8100f047dd.tar.xz
yuzu-2889372e47624e368df0d0361cb38b8100f047dd.zip
Merge pull request #2482 from yuriks/pica-refactor
Split up monolithic Regs struct
Diffstat (limited to 'src/video_core/rasterizer.cpp')
-rw-r--r--src/video_core/rasterizer.cpp307
1 files changed, 159 insertions, 148 deletions
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 287d732b5..ca09c9d0e 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -16,10 +16,10 @@
16#include "core/hw/gpu.h" 16#include "core/hw/gpu.h"
17#include "core/memory.h" 17#include "core/memory.h"
18#include "video_core/debug_utils/debug_utils.h" 18#include "video_core/debug_utils/debug_utils.h"
19#include "video_core/pica.h"
20#include "video_core/pica_state.h" 19#include "video_core/pica_state.h"
21#include "video_core/pica_types.h" 20#include "video_core/pica_types.h"
22#include "video_core/rasterizer.h" 21#include "video_core/rasterizer.h"
22#include "video_core/regs.h"
23#include "video_core/shader/shader.h" 23#include "video_core/shader/shader.h"
24#include "video_core/texture/texture_decode.h" 24#include "video_core/texture/texture_decode.h"
25#include "video_core/utils.h" 25#include "video_core/utils.h"
@@ -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:
@@ -327,14 +327,14 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
327 ScreenToRasterizerCoordinates(v1.screenpos), 327 ScreenToRasterizerCoordinates(v1.screenpos),
328 ScreenToRasterizerCoordinates(v2.screenpos)}; 328 ScreenToRasterizerCoordinates(v2.screenpos)};
329 329
330 if (regs.cull_mode == Regs::CullMode::KeepAll) { 330 if (regs.rasterizer.cull_mode == RasterizerRegs::CullMode::KeepAll) {
331 // Make sure we always end up with a triangle wound counter-clockwise 331 // Make sure we always end up with a triangle wound counter-clockwise
332 if (!reversed && SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) { 332 if (!reversed && SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) {
333 ProcessTriangleInternal(v0, v2, v1, true); 333 ProcessTriangleInternal(v0, v2, v1, true);
334 return; 334 return;
335 } 335 }
336 } else { 336 } else {
337 if (!reversed && regs.cull_mode == Regs::CullMode::KeepClockWise) { 337 if (!reversed && regs.rasterizer.cull_mode == RasterizerRegs::CullMode::KeepClockWise) {
338 // Reverse vertex order and use the CCW code path. 338 // Reverse vertex order and use the CCW code path.
339 ProcessTriangleInternal(v0, v2, v1, true); 339 ProcessTriangleInternal(v0, v2, v1, true);
340 return; 340 return;
@@ -351,13 +351,13 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
351 u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); 351 u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y});
352 352
353 // Convert the scissor box coordinates to 12.4 fixed point 353 // Convert the scissor box coordinates to 12.4 fixed point
354 u16 scissor_x1 = (u16)(regs.scissor_test.x1 << 4); 354 u16 scissor_x1 = (u16)(regs.rasterizer.scissor_test.x1 << 4);
355 u16 scissor_y1 = (u16)(regs.scissor_test.y1 << 4); 355 u16 scissor_y1 = (u16)(regs.rasterizer.scissor_test.y1 << 4);
356 // x2,y2 have +1 added to cover the entire sub-pixel area 356 // x2,y2 have +1 added to cover the entire sub-pixel area
357 u16 scissor_x2 = (u16)((regs.scissor_test.x2 + 1) << 4); 357 u16 scissor_x2 = (u16)((regs.rasterizer.scissor_test.x2 + 1) << 4);
358 u16 scissor_y2 = (u16)((regs.scissor_test.y2 + 1) << 4); 358 u16 scissor_y2 = (u16)((regs.rasterizer.scissor_test.y2 + 1) << 4);
359 359
360 if (regs.scissor_test.mode == Regs::ScissorMode::Include) { 360 if (regs.rasterizer.scissor_test.mode == RasterizerRegs::ScissorMode::Include) {
361 // Calculate the new bounds 361 // Calculate the new bounds
362 min_x = std::max(min_x, scissor_x1); 362 min_x = std::max(min_x, scissor_x1);
363 min_y = std::max(min_y, scissor_y1); 363 min_y = std::max(min_y, scissor_y1);
@@ -397,12 +397,13 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
397 397
398 auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w); 398 auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w);
399 399
400 auto textures = regs.GetTextures(); 400 auto textures = regs.texturing.GetTextures();
401 auto tev_stages = regs.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
@@ -411,7 +412,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
411 412
412 // Do not process the pixel if it's inside the scissor box and the scissor mode is set 413 // Do not process the pixel if it's inside the scissor box and the scissor mode is set
413 // to Exclude 414 // to Exclude
414 if (regs.scissor_test.mode == Regs::ScissorMode::Exclude) { 415 if (regs.rasterizer.scissor_test.mode == RasterizerRegs::ScissorMode::Exclude) {
415 if (x >= scissor_x1 && x < scissor_x2 && y >= scissor_y1 && y < scissor_y2) 416 if (x >= scissor_x1 && x < scissor_x2 && y >= scissor_y1 && y < scissor_y2)
416 continue; 417 continue;
417 } 418 }
@@ -441,12 +442,14 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
441 442
442 // Not fully accurate. About 3 bits in precision are missing. 443 // Not fully accurate. About 3 bits in precision are missing.
443 // Z-Buffer (z / w * scale + offset) 444 // Z-Buffer (z / w * scale + offset)
444 float depth_scale = float24::FromRaw(regs.viewport_depth_range).ToFloat32(); 445 float depth_scale = float24::FromRaw(regs.rasterizer.viewport_depth_range).ToFloat32();
445 float depth_offset = float24::FromRaw(regs.viewport_depth_near_plane).ToFloat32(); 446 float depth_offset =
447 float24::FromRaw(regs.rasterizer.viewport_depth_near_plane).ToFloat32();
446 float depth = interpolated_z_over_w * depth_scale + depth_offset; 448 float depth = interpolated_z_over_w * depth_scale + depth_offset;
447 449
448 // Potentially switch to W-Buffer 450 // Potentially switch to W-Buffer
449 if (regs.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) { 451 if (regs.rasterizer.depthmap_enable ==
452 Pica::RasterizerRegs::DepthBuffering::WBuffering) {
450 // W-Buffer (z * scale + w * offset = (z / w * scale + offset) * w) 453 // W-Buffer (z * scale + w * offset = (z / w * scale + offset) * w)
451 depth *= interpolated_w_inverse.ToFloat32() * wsum; 454 depth *= interpolated_w_inverse.ToFloat32() * wsum;
452 } 455 }
@@ -513,9 +516,9 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
513 // TODO: Refactor so cubemaps and shadowmaps can be handled 516 // TODO: Refactor so cubemaps and shadowmaps can be handled
514 if (i == 0) { 517 if (i == 0) {
515 switch (texture.config.type) { 518 switch (texture.config.type) {
516 case Regs::TextureConfig::Texture2D: 519 case TexturingRegs::TextureConfig::Texture2D:
517 break; 520 break;
518 case Regs::TextureConfig::Projection2D: { 521 case TexturingRegs::TextureConfig::Projection2D: {
519 auto tc0_w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w); 522 auto tc0_w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w);
520 u /= tc0_w; 523 u /= tc0_w;
521 v /= tc0_w; 524 v /= tc0_w;
@@ -534,21 +537,21 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
534 int t = (int)(v * float24::FromFloat32(static_cast<float>(texture.config.height))) 537 int t = (int)(v * float24::FromFloat32(static_cast<float>(texture.config.height)))
535 .ToFloat32(); 538 .ToFloat32();
536 539
537 static auto GetWrappedTexCoord = [](Regs::TextureConfig::WrapMode mode, int val, 540 static auto GetWrappedTexCoord = [](TexturingRegs::TextureConfig::WrapMode mode,
538 unsigned size) { 541 int val, unsigned size) {
539 switch (mode) { 542 switch (mode) {
540 case Regs::TextureConfig::ClampToEdge: 543 case TexturingRegs::TextureConfig::ClampToEdge:
541 val = std::max(val, 0); 544 val = std::max(val, 0);
542 val = std::min(val, (int)size - 1); 545 val = std::min(val, (int)size - 1);
543 return val; 546 return val;
544 547
545 case Regs::TextureConfig::ClampToBorder: 548 case TexturingRegs::TextureConfig::ClampToBorder:
546 return val; 549 return val;
547 550
548 case Regs::TextureConfig::Repeat: 551 case TexturingRegs::TextureConfig::Repeat:
549 return (int)((unsigned)val % size); 552 return (int)((unsigned)val % size);
550 553
551 case Regs::TextureConfig::MirroredRepeat: { 554 case TexturingRegs::TextureConfig::MirroredRepeat: {
552 unsigned int coord = ((unsigned)val % (2 * size)); 555 unsigned int coord = ((unsigned)val % (2 * size));
553 if (coord >= size) 556 if (coord >= size)
554 coord = 2 * size - 1 - coord; 557 coord = 2 * size - 1 - coord;
@@ -562,9 +565,9 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
562 } 565 }
563 }; 566 };
564 567
565 if ((texture.config.wrap_s == Regs::TextureConfig::ClampToBorder && 568 if ((texture.config.wrap_s == TexturingRegs::TextureConfig::ClampToBorder &&
566 (s < 0 || static_cast<u32>(s) >= texture.config.width)) || 569 (s < 0 || static_cast<u32>(s) >= texture.config.width)) ||
567 (texture.config.wrap_t == Regs::TextureConfig::ClampToBorder && 570 (texture.config.wrap_t == TexturingRegs::TextureConfig::ClampToBorder &&
568 (t < 0 || static_cast<u32>(t) >= texture.config.height))) { 571 (t < 0 || static_cast<u32>(t) >= texture.config.height))) {
569 auto border_color = texture.config.border_color; 572 auto border_color = texture.config.border_color;
570 texture_color[i] = {border_color.r, border_color.g, border_color.b, 573 texture_color[i] = {border_color.r, border_color.g, border_color.b,
@@ -600,17 +603,19 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
600 Math::Vec4<u8> combiner_output; 603 Math::Vec4<u8> combiner_output;
601 Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0}; 604 Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0};
602 Math::Vec4<u8> next_combiner_buffer = { 605 Math::Vec4<u8> next_combiner_buffer = {
603 regs.tev_combiner_buffer_color.r, regs.tev_combiner_buffer_color.g, 606 regs.texturing.tev_combiner_buffer_color.r,
604 regs.tev_combiner_buffer_color.b, regs.tev_combiner_buffer_color.a, 607 regs.texturing.tev_combiner_buffer_color.g,
608 regs.texturing.tev_combiner_buffer_color.b,
609 regs.texturing.tev_combiner_buffer_color.a,
605 }; 610 };
606 611
607 for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); 612 for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size();
608 ++tev_stage_index) { 613 ++tev_stage_index) {
609 const auto& tev_stage = tev_stages[tev_stage_index]; 614 const auto& tev_stage = tev_stages[tev_stage_index];
610 using Source = Regs::TevStageConfig::Source; 615 using Source = TexturingRegs::TevStageConfig::Source;
611 using ColorModifier = Regs::TevStageConfig::ColorModifier; 616 using ColorModifier = TexturingRegs::TevStageConfig::ColorModifier;
612 using AlphaModifier = Regs::TevStageConfig::AlphaModifier; 617 using AlphaModifier = TexturingRegs::TevStageConfig::AlphaModifier;
613 using Operation = Regs::TevStageConfig::Operation; 618 using Operation = TexturingRegs::TevStageConfig::Operation;
614 619
615 auto GetSource = [&](Source source) -> Math::Vec4<u8> { 620 auto GetSource = [&](Source source) -> Math::Vec4<u8> {
616 switch (source) { 621 switch (source) {
@@ -862,54 +867,54 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
862 867
863 combiner_buffer = next_combiner_buffer; 868 combiner_buffer = next_combiner_buffer;
864 869
865 if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor( 870 if (regs.texturing.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(
866 tev_stage_index)) { 871 tev_stage_index)) {
867 next_combiner_buffer.r() = combiner_output.r(); 872 next_combiner_buffer.r() = combiner_output.r();
868 next_combiner_buffer.g() = combiner_output.g(); 873 next_combiner_buffer.g() = combiner_output.g();
869 next_combiner_buffer.b() = combiner_output.b(); 874 next_combiner_buffer.b() = combiner_output.b();
870 } 875 }
871 876
872 if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha( 877 if (regs.texturing.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(
873 tev_stage_index)) { 878 tev_stage_index)) {
874 next_combiner_buffer.a() = combiner_output.a(); 879 next_combiner_buffer.a() = combiner_output.a();
875 } 880 }
876 } 881 }
877 882
878 const auto& output_merger = regs.output_merger; 883 const auto& output_merger = regs.framebuffer.output_merger;
879 // TODO: Does alpha testing happen before or after stencil? 884 // TODO: Does alpha testing happen before or after stencil?
880 if (output_merger.alpha_test.enable) { 885 if (output_merger.alpha_test.enable) {
881 bool pass = false; 886 bool pass = false;
882 887
883 switch (output_merger.alpha_test.func) { 888 switch (output_merger.alpha_test.func) {
884 case Regs::CompareFunc::Never: 889 case FramebufferRegs::CompareFunc::Never:
885 pass = false; 890 pass = false;
886 break; 891 break;
887 892
888 case Regs::CompareFunc::Always: 893 case FramebufferRegs::CompareFunc::Always:
889 pass = true; 894 pass = true;
890 break; 895 break;
891 896
892 case Regs::CompareFunc::Equal: 897 case FramebufferRegs::CompareFunc::Equal:
893 pass = combiner_output.a() == output_merger.alpha_test.ref; 898 pass = combiner_output.a() == output_merger.alpha_test.ref;
894 break; 899 break;
895 900
896 case Regs::CompareFunc::NotEqual: 901 case FramebufferRegs::CompareFunc::NotEqual:
897 pass = combiner_output.a() != output_merger.alpha_test.ref; 902 pass = combiner_output.a() != output_merger.alpha_test.ref;
898 break; 903 break;
899 904
900 case Regs::CompareFunc::LessThan: 905 case FramebufferRegs::CompareFunc::LessThan:
901 pass = combiner_output.a() < output_merger.alpha_test.ref; 906 pass = combiner_output.a() < output_merger.alpha_test.ref;
902 break; 907 break;
903 908
904 case Regs::CompareFunc::LessThanOrEqual: 909 case FramebufferRegs::CompareFunc::LessThanOrEqual:
905 pass = combiner_output.a() <= output_merger.alpha_test.ref; 910 pass = combiner_output.a() <= output_merger.alpha_test.ref;
906 break; 911 break;
907 912
908 case Regs::CompareFunc::GreaterThan: 913 case FramebufferRegs::CompareFunc::GreaterThan:
909 pass = combiner_output.a() > output_merger.alpha_test.ref; 914 pass = combiner_output.a() > output_merger.alpha_test.ref;
910 break; 915 break;
911 916
912 case Regs::CompareFunc::GreaterThanOrEqual: 917 case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
913 pass = combiner_output.a() >= output_merger.alpha_test.ref; 918 pass = combiner_output.a() >= output_merger.alpha_test.ref;
914 break; 919 break;
915 } 920 }
@@ -922,16 +927,16 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
922 // Not fully accurate. We'd have to know what data type is used to 927 // Not fully accurate. We'd have to know what data type is used to
923 // store the depth etc. Using float for now until we know more 928 // store the depth etc. Using float for now until we know more
924 // about Pica datatypes 929 // about Pica datatypes
925 if (regs.fog_mode == Regs::FogMode::Fog) { 930 if (regs.texturing.fog_mode == TexturingRegs::FogMode::Fog) {
926 const Math::Vec3<u8> fog_color = { 931 const Math::Vec3<u8> fog_color = {
927 static_cast<u8>(regs.fog_color.r.Value()), 932 static_cast<u8>(regs.texturing.fog_color.r.Value()),
928 static_cast<u8>(regs.fog_color.g.Value()), 933 static_cast<u8>(regs.texturing.fog_color.g.Value()),
929 static_cast<u8>(regs.fog_color.b.Value()), 934 static_cast<u8>(regs.texturing.fog_color.b.Value()),
930 }; 935 };
931 936
932 // Get index into fog LUT 937 // Get index into fog LUT
933 float fog_index; 938 float fog_index;
934 if (g_state.regs.fog_flip) { 939 if (g_state.regs.texturing.fog_flip) {
935 fog_index = (1.0f - depth) * 128.0f; 940 fog_index = (1.0f - depth) * 128.0f;
936 } else { 941 } else {
937 fog_index = depth * 128.0f; 942 fog_index = depth * 128.0f;
@@ -955,10 +960,10 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
955 u8 old_stencil = 0; 960 u8 old_stencil = 0;
956 961
957 auto UpdateStencil = [stencil_test, x, y, 962 auto UpdateStencil = [stencil_test, x, y,
958 &old_stencil](Pica::Regs::StencilAction action) { 963 &old_stencil](Pica::FramebufferRegs::StencilAction action) {
959 u8 new_stencil = 964 u8 new_stencil =
960 PerformStencilAction(action, old_stencil, stencil_test.reference_value); 965 PerformStencilAction(action, old_stencil, stencil_test.reference_value);
961 if (g_state.regs.framebuffer.allow_depth_stencil_write != 0) 966 if (g_state.regs.framebuffer.framebuffer.allow_depth_stencil_write != 0)
962 SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) | 967 SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) |
963 (old_stencil & ~stencil_test.write_mask)); 968 (old_stencil & ~stencil_test.write_mask));
964 }; 969 };
@@ -970,35 +975,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
970 975
971 bool pass = false; 976 bool pass = false;
972 switch (stencil_test.func) { 977 switch (stencil_test.func) {
973 case Regs::CompareFunc::Never: 978 case FramebufferRegs::CompareFunc::Never:
974 pass = false; 979 pass = false;
975 break; 980 break;
976 981
977 case Regs::CompareFunc::Always: 982 case FramebufferRegs::CompareFunc::Always:
978 pass = true; 983 pass = true;
979 break; 984 break;
980 985
981 case Regs::CompareFunc::Equal: 986 case FramebufferRegs::CompareFunc::Equal:
982 pass = (ref == dest); 987 pass = (ref == dest);
983 break; 988 break;
984 989
985 case Regs::CompareFunc::NotEqual: 990 case FramebufferRegs::CompareFunc::NotEqual:
986 pass = (ref != dest); 991 pass = (ref != dest);
987 break; 992 break;
988 993
989 case Regs::CompareFunc::LessThan: 994 case FramebufferRegs::CompareFunc::LessThan:
990 pass = (ref < dest); 995 pass = (ref < dest);
991 break; 996 break;
992 997
993 case Regs::CompareFunc::LessThanOrEqual: 998 case FramebufferRegs::CompareFunc::LessThanOrEqual:
994 pass = (ref <= dest); 999 pass = (ref <= dest);
995 break; 1000 break;
996 1001
997 case Regs::CompareFunc::GreaterThan: 1002 case FramebufferRegs::CompareFunc::GreaterThan:
998 pass = (ref > dest); 1003 pass = (ref > dest);
999 break; 1004 break;
1000 1005
1001 case Regs::CompareFunc::GreaterThanOrEqual: 1006 case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
1002 pass = (ref >= dest); 1007 pass = (ref >= dest);
1003 break; 1008 break;
1004 } 1009 }
@@ -1010,7 +1015,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1010 } 1015 }
1011 1016
1012 // Convert float to integer 1017 // Convert float to integer
1013 unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format); 1018 unsigned num_bits =
1019 FramebufferRegs::DepthBitsPerPixel(regs.framebuffer.framebuffer.depth_format);
1014 u32 z = (u32)(depth * ((1 << num_bits) - 1)); 1020 u32 z = (u32)(depth * ((1 << num_bits) - 1));
1015 1021
1016 if (output_merger.depth_test_enable) { 1022 if (output_merger.depth_test_enable) {
@@ -1019,35 +1025,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1019 bool pass = false; 1025 bool pass = false;
1020 1026
1021 switch (output_merger.depth_test_func) { 1027 switch (output_merger.depth_test_func) {
1022 case Regs::CompareFunc::Never: 1028 case FramebufferRegs::CompareFunc::Never:
1023 pass = false; 1029 pass = false;
1024 break; 1030 break;
1025 1031
1026 case Regs::CompareFunc::Always: 1032 case FramebufferRegs::CompareFunc::Always:
1027 pass = true; 1033 pass = true;
1028 break; 1034 break;
1029 1035
1030 case Regs::CompareFunc::Equal: 1036 case FramebufferRegs::CompareFunc::Equal:
1031 pass = z == ref_z; 1037 pass = z == ref_z;
1032 break; 1038 break;
1033 1039
1034 case Regs::CompareFunc::NotEqual: 1040 case FramebufferRegs::CompareFunc::NotEqual:
1035 pass = z != ref_z; 1041 pass = z != ref_z;
1036 break; 1042 break;
1037 1043
1038 case Regs::CompareFunc::LessThan: 1044 case FramebufferRegs::CompareFunc::LessThan:
1039 pass = z < ref_z; 1045 pass = z < ref_z;
1040 break; 1046 break;
1041 1047
1042 case Regs::CompareFunc::LessThanOrEqual: 1048 case FramebufferRegs::CompareFunc::LessThanOrEqual:
1043 pass = z <= ref_z; 1049 pass = z <= ref_z;
1044 break; 1050 break;
1045 1051
1046 case Regs::CompareFunc::GreaterThan: 1052 case FramebufferRegs::CompareFunc::GreaterThan:
1047 pass = z > ref_z; 1053 pass = z > ref_z;
1048 break; 1054 break;
1049 1055
1050 case Regs::CompareFunc::GreaterThanOrEqual: 1056 case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
1051 pass = z >= ref_z; 1057 pass = z >= ref_z;
1052 break; 1058 break;
1053 } 1059 }
@@ -1059,8 +1065,11 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1059 } 1065 }
1060 } 1066 }
1061 1067
1062 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
1063 SetDepth(x >> 4, y >> 4, z); 1071 SetDepth(x >> 4, y >> 4, z);
1072 }
1064 1073
1065 // 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
1066 if (stencil_action_enable) 1075 if (stencil_action_enable)
@@ -1072,7 +1081,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1072 if (output_merger.alphablend_enable) { 1081 if (output_merger.alphablend_enable) {
1073 auto params = output_merger.alpha_blending; 1082 auto params = output_merger.alpha_blending;
1074 1083
1075 auto LookupFactor = [&](unsigned channel, Regs::BlendFactor factor) -> u8 { 1084 auto LookupFactor = [&](unsigned channel,
1085 FramebufferRegs::BlendFactor factor) -> u8 {
1076 DEBUG_ASSERT(channel < 4); 1086 DEBUG_ASSERT(channel < 4);
1077 1087
1078 const Math::Vec4<u8> blend_const = { 1088 const Math::Vec4<u8> blend_const = {
@@ -1083,49 +1093,49 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1083 }; 1093 };
1084 1094
1085 switch (factor) { 1095 switch (factor) {
1086 case Regs::BlendFactor::Zero: 1096 case FramebufferRegs::BlendFactor::Zero:
1087 return 0; 1097 return 0;
1088 1098
1089 case Regs::BlendFactor::One: 1099 case FramebufferRegs::BlendFactor::One:
1090 return 255; 1100 return 255;
1091 1101
1092 case Regs::BlendFactor::SourceColor: 1102 case FramebufferRegs::BlendFactor::SourceColor:
1093 return combiner_output[channel]; 1103 return combiner_output[channel];
1094 1104
1095 case Regs::BlendFactor::OneMinusSourceColor: 1105 case FramebufferRegs::BlendFactor::OneMinusSourceColor:
1096 return 255 - combiner_output[channel]; 1106 return 255 - combiner_output[channel];
1097 1107
1098 case Regs::BlendFactor::DestColor: 1108 case FramebufferRegs::BlendFactor::DestColor:
1099 return dest[channel]; 1109 return dest[channel];
1100 1110
1101 case Regs::BlendFactor::OneMinusDestColor: 1111 case FramebufferRegs::BlendFactor::OneMinusDestColor:
1102 return 255 - dest[channel]; 1112 return 255 - dest[channel];
1103 1113
1104 case Regs::BlendFactor::SourceAlpha: 1114 case FramebufferRegs::BlendFactor::SourceAlpha:
1105 return combiner_output.a(); 1115 return combiner_output.a();
1106 1116
1107 case Regs::BlendFactor::OneMinusSourceAlpha: 1117 case FramebufferRegs::BlendFactor::OneMinusSourceAlpha:
1108 return 255 - combiner_output.a(); 1118 return 255 - combiner_output.a();
1109 1119
1110 case Regs::BlendFactor::DestAlpha: 1120 case FramebufferRegs::BlendFactor::DestAlpha:
1111 return dest.a(); 1121 return dest.a();
1112 1122
1113 case Regs::BlendFactor::OneMinusDestAlpha: 1123 case FramebufferRegs::BlendFactor::OneMinusDestAlpha:
1114 return 255 - dest.a(); 1124 return 255 - dest.a();
1115 1125
1116 case Regs::BlendFactor::ConstantColor: 1126 case FramebufferRegs::BlendFactor::ConstantColor:
1117 return blend_const[channel]; 1127 return blend_const[channel];
1118 1128
1119 case Regs::BlendFactor::OneMinusConstantColor: 1129 case FramebufferRegs::BlendFactor::OneMinusConstantColor:
1120 return 255 - blend_const[channel]; 1130 return 255 - blend_const[channel];
1121 1131
1122 case Regs::BlendFactor::ConstantAlpha: 1132 case FramebufferRegs::BlendFactor::ConstantAlpha:
1123 return blend_const.a(); 1133 return blend_const.a();
1124 1134
1125 case Regs::BlendFactor::OneMinusConstantAlpha: 1135 case FramebufferRegs::BlendFactor::OneMinusConstantAlpha:
1126 return 255 - blend_const.a(); 1136 return 255 - blend_const.a();
1127 1137
1128 case Regs::BlendFactor::SourceAlphaSaturate: 1138 case FramebufferRegs::BlendFactor::SourceAlphaSaturate:
1129 // Returns 1.0 for the alpha channel 1139 // Returns 1.0 for the alpha channel
1130 if (channel == 3) 1140 if (channel == 3)
1131 return 255; 1141 return 255;
@@ -1143,36 +1153,37 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1143 static auto EvaluateBlendEquation = []( 1153 static auto EvaluateBlendEquation = [](
1144 const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor, 1154 const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
1145 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor, 1155 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
1146 Regs::BlendEquation equation) { 1156 FramebufferRegs::BlendEquation equation) {
1157
1147 Math::Vec4<int> result; 1158 Math::Vec4<int> result;
1148 1159
1149 auto src_result = (src * srcfactor).Cast<int>(); 1160 auto src_result = (src * srcfactor).Cast<int>();
1150 auto dst_result = (dest * destfactor).Cast<int>(); 1161 auto dst_result = (dest * destfactor).Cast<int>();
1151 1162
1152 switch (equation) { 1163 switch (equation) {
1153 case Regs::BlendEquation::Add: 1164 case FramebufferRegs::BlendEquation::Add:
1154 result = (src_result + dst_result) / 255; 1165 result = (src_result + dst_result) / 255;
1155 break; 1166 break;
1156 1167
1157 case Regs::BlendEquation::Subtract: 1168 case FramebufferRegs::BlendEquation::Subtract:
1158 result = (src_result - dst_result) / 255; 1169 result = (src_result - dst_result) / 255;
1159 break; 1170 break;
1160 1171
1161 case Regs::BlendEquation::ReverseSubtract: 1172 case FramebufferRegs::BlendEquation::ReverseSubtract:
1162 result = (dst_result - src_result) / 255; 1173 result = (dst_result - src_result) / 255;
1163 break; 1174 break;
1164 1175
1165 // TODO: How do these two actually work? 1176 // TODO: How do these two actually work?
1166 // 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,
1167 // but is this what the 3DS actually does? 1178 // but is this what the 3DS actually does?
1168 case Regs::BlendEquation::Min: 1179 case FramebufferRegs::BlendEquation::Min:
1169 result.r() = std::min(src.r(), dest.r()); 1180 result.r() = std::min(src.r(), dest.r());
1170 result.g() = std::min(src.g(), dest.g()); 1181 result.g() = std::min(src.g(), dest.g());
1171 result.b() = std::min(src.b(), dest.b()); 1182 result.b() = std::min(src.b(), dest.b());
1172 result.a() = std::min(src.a(), dest.a()); 1183 result.a() = std::min(src.a(), dest.a());
1173 break; 1184 break;
1174 1185
1175 case Regs::BlendEquation::Max: 1186 case FramebufferRegs::BlendEquation::Max:
1176 result.r() = std::max(src.r(), dest.r()); 1187 result.r() = std::max(src.r(), dest.r());
1177 result.g() = std::max(src.g(), dest.g()); 1188 result.g() = std::max(src.g(), dest.g());
1178 result.b() = std::max(src.b(), dest.b()); 1189 result.b() = std::max(src.b(), dest.b());
@@ -1205,54 +1216,54 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1205 dstfactor, params.blend_equation_a) 1216 dstfactor, params.blend_equation_a)
1206 .a(); 1217 .a();
1207 } else { 1218 } else {
1208 static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 { 1219 static auto LogicOp = [](u8 src, u8 dest, FramebufferRegs::LogicOp op) -> u8 {
1209 switch (op) { 1220 switch (op) {
1210 case Regs::LogicOp::Clear: 1221 case FramebufferRegs::LogicOp::Clear:
1211 return 0; 1222 return 0;
1212 1223
1213 case Regs::LogicOp::And: 1224 case FramebufferRegs::LogicOp::And:
1214 return src & dest; 1225 return src & dest;
1215 1226
1216 case Regs::LogicOp::AndReverse: 1227 case FramebufferRegs::LogicOp::AndReverse:
1217 return src & ~dest; 1228 return src & ~dest;
1218 1229
1219 case Regs::LogicOp::Copy: 1230 case FramebufferRegs::LogicOp::Copy:
1220 return src; 1231 return src;
1221 1232
1222 case Regs::LogicOp::Set: 1233 case FramebufferRegs::LogicOp::Set:
1223 return 255; 1234 return 255;
1224 1235
1225 case Regs::LogicOp::CopyInverted: 1236 case FramebufferRegs::LogicOp::CopyInverted:
1226 return ~src; 1237 return ~src;
1227 1238
1228 case Regs::LogicOp::NoOp: 1239 case FramebufferRegs::LogicOp::NoOp:
1229 return dest; 1240 return dest;
1230 1241
1231 case Regs::LogicOp::Invert: 1242 case FramebufferRegs::LogicOp::Invert:
1232 return ~dest; 1243 return ~dest;
1233 1244
1234 case Regs::LogicOp::Nand: 1245 case FramebufferRegs::LogicOp::Nand:
1235 return ~(src & dest); 1246 return ~(src & dest);
1236 1247
1237 case Regs::LogicOp::Or: 1248 case FramebufferRegs::LogicOp::Or:
1238 return src | dest; 1249 return src | dest;
1239 1250
1240 case Regs::LogicOp::Nor: 1251 case FramebufferRegs::LogicOp::Nor:
1241 return ~(src | dest); 1252 return ~(src | dest);
1242 1253
1243 case Regs::LogicOp::Xor: 1254 case FramebufferRegs::LogicOp::Xor:
1244 return src ^ dest; 1255 return src ^ dest;
1245 1256
1246 case Regs::LogicOp::Equiv: 1257 case FramebufferRegs::LogicOp::Equiv:
1247 return ~(src ^ dest); 1258 return ~(src ^ dest);
1248 1259
1249 case Regs::LogicOp::AndInverted: 1260 case FramebufferRegs::LogicOp::AndInverted:
1250 return ~src & dest; 1261 return ~src & dest;
1251 1262
1252 case Regs::LogicOp::OrReverse: 1263 case FramebufferRegs::LogicOp::OrReverse:
1253 return src | ~dest; 1264 return src | ~dest;
1254 1265
1255 case Regs::LogicOp::OrInverted: 1266 case FramebufferRegs::LogicOp::OrInverted:
1256 return ~src | dest; 1267 return ~src | dest;
1257 } 1268 }
1258 }; 1269 };
@@ -1271,7 +1282,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1271 output_merger.alpha_enable ? blend_output.a() : dest.a(), 1282 output_merger.alpha_enable ? blend_output.a() : dest.a(),
1272 }; 1283 };
1273 1284
1274 if (regs.framebuffer.allow_color_write != 0) 1285 if (regs.framebuffer.framebuffer.allow_color_write != 0)
1275 DrawPixel(x >> 4, y >> 4, result); 1286 DrawPixel(x >> 4, y >> 4, result);
1276 } 1287 }
1277 } 1288 }