summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2017-01-27 21:47:34 -0800
committerGravatar Yuri Kunde Schlesner2017-02-04 13:59:11 -0800
commit23713d5dee8015a73ecab1bf944ebcab908e347c (patch)
tree160bdc8411a899f690e51d055ad1213e19abba5c /src
parentVideoCore: Split texturing regs from Regs struct (diff)
downloadyuzu-23713d5dee8015a73ecab1bf944ebcab908e347c.tar.gz
yuzu-23713d5dee8015a73ecab1bf944ebcab908e347c.tar.xz
yuzu-23713d5dee8015a73ecab1bf944ebcab908e347c.zip
VideoCore: Split framebuffer regs from Regs struct
Diffstat (limited to 'src')
-rw-r--r--src/citra_qt/debugger/graphics/graphics_surface.cpp24
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/pica.h270
-rw-r--r--src/video_core/rasterizer.cpp229
-rw-r--r--src/video_core/regs_framebuffer.h282
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp109
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h6
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp8
-rw-r--r--src/video_core/renderer_opengl/pica_to_gl.h10
11 files changed, 503 insertions, 457 deletions
diff --git a/src/citra_qt/debugger/graphics/graphics_surface.cpp b/src/citra_qt/debugger/graphics/graphics_surface.cpp
index 406a49f42..78156d5ec 100644
--- a/src/citra_qt/debugger/graphics/graphics_surface.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_surface.cpp
@@ -414,30 +414,30 @@ void GraphicsSurfaceWidget::OnUpdate() {
414 // TODO: Store a reference to the registers in the debug context instead of accessing them 414 // TODO: Store a reference to the registers in the debug context instead of accessing them
415 // directly... 415 // directly...
416 416
417 const auto& framebuffer = Pica::g_state.regs.framebuffer; 417 const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer;
418 418
419 surface_address = framebuffer.GetColorBufferPhysicalAddress(); 419 surface_address = framebuffer.GetColorBufferPhysicalAddress();
420 surface_width = framebuffer.GetWidth(); 420 surface_width = framebuffer.GetWidth();
421 surface_height = framebuffer.GetHeight(); 421 surface_height = framebuffer.GetHeight();
422 422
423 switch (framebuffer.color_format) { 423 switch (framebuffer.color_format) {
424 case Pica::Regs::ColorFormat::RGBA8: 424 case Pica::FramebufferRegs::ColorFormat::RGBA8:
425 surface_format = Format::RGBA8; 425 surface_format = Format::RGBA8;
426 break; 426 break;
427 427
428 case Pica::Regs::ColorFormat::RGB8: 428 case Pica::FramebufferRegs::ColorFormat::RGB8:
429 surface_format = Format::RGB8; 429 surface_format = Format::RGB8;
430 break; 430 break;
431 431
432 case Pica::Regs::ColorFormat::RGB5A1: 432 case Pica::FramebufferRegs::ColorFormat::RGB5A1:
433 surface_format = Format::RGB5A1; 433 surface_format = Format::RGB5A1;
434 break; 434 break;
435 435
436 case Pica::Regs::ColorFormat::RGB565: 436 case Pica::FramebufferRegs::ColorFormat::RGB565:
437 surface_format = Format::RGB565; 437 surface_format = Format::RGB565;
438 break; 438 break;
439 439
440 case Pica::Regs::ColorFormat::RGBA4: 440 case Pica::FramebufferRegs::ColorFormat::RGBA4:
441 surface_format = Format::RGBA4; 441 surface_format = Format::RGBA4;
442 break; 442 break;
443 443
@@ -450,22 +450,22 @@ void GraphicsSurfaceWidget::OnUpdate() {
450 } 450 }
451 451
452 case Source::DepthBuffer: { 452 case Source::DepthBuffer: {
453 const auto& framebuffer = Pica::g_state.regs.framebuffer; 453 const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer;
454 454
455 surface_address = framebuffer.GetDepthBufferPhysicalAddress(); 455 surface_address = framebuffer.GetDepthBufferPhysicalAddress();
456 surface_width = framebuffer.GetWidth(); 456 surface_width = framebuffer.GetWidth();
457 surface_height = framebuffer.GetHeight(); 457 surface_height = framebuffer.GetHeight();
458 458
459 switch (framebuffer.depth_format) { 459 switch (framebuffer.depth_format) {
460 case Pica::Regs::DepthFormat::D16: 460 case Pica::FramebufferRegs::DepthFormat::D16:
461 surface_format = Format::D16; 461 surface_format = Format::D16;
462 break; 462 break;
463 463
464 case Pica::Regs::DepthFormat::D24: 464 case Pica::FramebufferRegs::DepthFormat::D24:
465 surface_format = Format::D24; 465 surface_format = Format::D24;
466 break; 466 break;
467 467
468 case Pica::Regs::DepthFormat::D24S8: 468 case Pica::FramebufferRegs::DepthFormat::D24S8:
469 surface_format = Format::D24X8; 469 surface_format = Format::D24X8;
470 break; 470 break;
471 471
@@ -478,14 +478,14 @@ void GraphicsSurfaceWidget::OnUpdate() {
478 } 478 }
479 479
480 case Source::StencilBuffer: { 480 case Source::StencilBuffer: {
481 const auto& framebuffer = Pica::g_state.regs.framebuffer; 481 const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer;
482 482
483 surface_address = framebuffer.GetDepthBufferPhysicalAddress(); 483 surface_address = framebuffer.GetDepthBufferPhysicalAddress();
484 surface_width = framebuffer.GetWidth(); 484 surface_width = framebuffer.GetWidth();
485 surface_height = framebuffer.GetHeight(); 485 surface_height = framebuffer.GetHeight();
486 486
487 switch (framebuffer.depth_format) { 487 switch (framebuffer.depth_format) {
488 case Pica::Regs::DepthFormat::D24S8: 488 case Pica::FramebufferRegs::DepthFormat::D24S8:
489 surface_format = Format::X24S8; 489 surface_format = Format::X24S8;
490 break; 490 break;
491 491
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index c0358fc20..718c709e5 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -32,6 +32,7 @@ set(HEADERS
32 primitive_assembly.h 32 primitive_assembly.h
33 rasterizer.h 33 rasterizer.h
34 rasterizer_interface.h 34 rasterizer_interface.h
35 regs_framebuffer.h
35 regs_rasterizer.h 36 regs_rasterizer.h
36 regs_texturing.h 37 regs_texturing.h
37 renderer_base.h 38 renderer_base.h
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 71194198a..50a549c42 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -18,6 +18,7 @@
18#include "common/common_types.h" 18#include "common/common_types.h"
19#include "common/logging/log.h" 19#include "common/logging/log.h"
20#include "common/vector_math.h" 20#include "common/vector_math.h"
21#include "video_core/regs_framebuffer.h"
21#include "video_core/regs_rasterizer.h" 22#include "video_core/regs_rasterizer.h"
22#include "video_core/regs_texturing.h" 23#include "video_core/regs_texturing.h"
23 24
@@ -51,268 +52,7 @@ struct Regs {
51 INSERT_PADDING_WORDS(0x2f); 52 INSERT_PADDING_WORDS(0x2f);
52 RasterizerRegs rasterizer; 53 RasterizerRegs rasterizer;
53 TexturingRegs texturing; 54 TexturingRegs texturing;
54 55 FramebufferRegs framebuffer;
55 enum class LogicOp : u32 {
56 Clear = 0,
57 And = 1,
58 AndReverse = 2,
59 Copy = 3,
60 Set = 4,
61 CopyInverted = 5,
62 NoOp = 6,
63 Invert = 7,
64 Nand = 8,
65 Or = 9,
66 Nor = 10,
67 Xor = 11,
68 Equiv = 12,
69 AndInverted = 13,
70 OrReverse = 14,
71 OrInverted = 15,
72 };
73
74 enum class BlendEquation : u32 {
75 Add = 0,
76 Subtract = 1,
77 ReverseSubtract = 2,
78 Min = 3,
79 Max = 4,
80 };
81
82 enum class BlendFactor : u32 {
83 Zero = 0,
84 One = 1,
85 SourceColor = 2,
86 OneMinusSourceColor = 3,
87 DestColor = 4,
88 OneMinusDestColor = 5,
89 SourceAlpha = 6,
90 OneMinusSourceAlpha = 7,
91 DestAlpha = 8,
92 OneMinusDestAlpha = 9,
93 ConstantColor = 10,
94 OneMinusConstantColor = 11,
95 ConstantAlpha = 12,
96 OneMinusConstantAlpha = 13,
97 SourceAlphaSaturate = 14,
98 };
99
100 enum class CompareFunc : u32 {
101 Never = 0,
102 Always = 1,
103 Equal = 2,
104 NotEqual = 3,
105 LessThan = 4,
106 LessThanOrEqual = 5,
107 GreaterThan = 6,
108 GreaterThanOrEqual = 7,
109 };
110
111 enum class StencilAction : u32 {
112 Keep = 0,
113 Zero = 1,
114 Replace = 2,
115 Increment = 3,
116 Decrement = 4,
117 Invert = 5,
118 IncrementWrap = 6,
119 DecrementWrap = 7,
120 };
121
122 struct {
123 union {
124 // If false, logic blending is used
125 BitField<8, 1, u32> alphablend_enable;
126 };
127
128 union {
129 BitField<0, 8, BlendEquation> blend_equation_rgb;
130 BitField<8, 8, BlendEquation> blend_equation_a;
131
132 BitField<16, 4, BlendFactor> factor_source_rgb;
133 BitField<20, 4, BlendFactor> factor_dest_rgb;
134
135 BitField<24, 4, BlendFactor> factor_source_a;
136 BitField<28, 4, BlendFactor> factor_dest_a;
137 } alpha_blending;
138
139 union {
140 BitField<0, 4, LogicOp> logic_op;
141 };
142
143 union {
144 u32 raw;
145 BitField<0, 8, u32> r;
146 BitField<8, 8, u32> g;
147 BitField<16, 8, u32> b;
148 BitField<24, 8, u32> a;
149 } blend_const;
150
151 union {
152 BitField<0, 1, u32> enable;
153 BitField<4, 3, CompareFunc> func;
154 BitField<8, 8, u32> ref;
155 } alpha_test;
156
157 struct {
158 union {
159 // Raw value of this register
160 u32 raw_func;
161
162 // If true, enable stencil testing
163 BitField<0, 1, u32> enable;
164
165 // Comparison operation for stencil testing
166 BitField<4, 3, CompareFunc> func;
167
168 // Mask used to control writing to the stencil buffer
169 BitField<8, 8, u32> write_mask;
170
171 // Value to compare against for stencil testing
172 BitField<16, 8, u32> reference_value;
173
174 // Mask to apply on stencil test inputs
175 BitField<24, 8, u32> input_mask;
176 };
177
178 union {
179 // Raw value of this register
180 u32 raw_op;
181
182 // Action to perform when the stencil test fails
183 BitField<0, 3, StencilAction> action_stencil_fail;
184
185 // Action to perform when stencil testing passed but depth testing fails
186 BitField<4, 3, StencilAction> action_depth_fail;
187
188 // Action to perform when both stencil and depth testing pass
189 BitField<8, 3, StencilAction> action_depth_pass;
190 };
191 } stencil_test;
192
193 union {
194 BitField<0, 1, u32> depth_test_enable;
195 BitField<4, 3, CompareFunc> depth_test_func;
196 BitField<8, 1, u32> red_enable;
197 BitField<9, 1, u32> green_enable;
198 BitField<10, 1, u32> blue_enable;
199 BitField<11, 1, u32> alpha_enable;
200 BitField<12, 1, u32> depth_write_enable;
201 };
202
203 INSERT_PADDING_WORDS(0x8);
204 } output_merger;
205
206 // Components are laid out in reverse byte order, most significant bits first.
207 enum class ColorFormat : u32 {
208 RGBA8 = 0,
209 RGB8 = 1,
210 RGB5A1 = 2,
211 RGB565 = 3,
212 RGBA4 = 4,
213 };
214
215 enum class DepthFormat : u32 {
216 D16 = 0,
217 D24 = 2,
218 D24S8 = 3,
219 };
220
221 // Returns the number of bytes in the specified color format
222 static unsigned BytesPerColorPixel(ColorFormat format) {
223 switch (format) {
224 case ColorFormat::RGBA8:
225 return 4;
226 case ColorFormat::RGB8:
227 return 3;
228 case ColorFormat::RGB5A1:
229 case ColorFormat::RGB565:
230 case ColorFormat::RGBA4:
231 return 2;
232 default:
233 LOG_CRITICAL(HW_GPU, "Unknown color format %u", format);
234 UNIMPLEMENTED();
235 }
236 }
237
238 struct FramebufferConfig {
239 INSERT_PADDING_WORDS(0x3);
240
241 union {
242 BitField<0, 4, u32> allow_color_write; // 0 = disable, else enable
243 };
244
245 INSERT_PADDING_WORDS(0x1);
246
247 union {
248 BitField<0, 2, u32> allow_depth_stencil_write; // 0 = disable, else enable
249 };
250
251 DepthFormat depth_format; // TODO: Should be a BitField!
252 BitField<16, 3, ColorFormat> color_format;
253
254 INSERT_PADDING_WORDS(0x4);
255
256 u32 depth_buffer_address;
257 u32 color_buffer_address;
258
259 union {
260 // Apparently, the framebuffer width is stored as expected,
261 // while the height is stored as the actual height minus one.
262 // Hence, don't access these fields directly but use the accessors
263 // GetWidth() and GetHeight() instead.
264 BitField<0, 11, u32> width;
265 BitField<12, 10, u32> height;
266 };
267
268 INSERT_PADDING_WORDS(0x1);
269
270 inline u32 GetColorBufferPhysicalAddress() const {
271 return DecodeAddressRegister(color_buffer_address);
272 }
273 inline u32 GetDepthBufferPhysicalAddress() const {
274 return DecodeAddressRegister(depth_buffer_address);
275 }
276
277 inline u32 GetWidth() const {
278 return width;
279 }
280
281 inline u32 GetHeight() const {
282 return height + 1;
283 }
284 } framebuffer;
285
286 // Returns the number of bytes in the specified depth format
287 static u32 BytesPerDepthPixel(DepthFormat format) {
288 switch (format) {
289 case DepthFormat::D16:
290 return 2;
291 case DepthFormat::D24:
292 return 3;
293 case DepthFormat::D24S8:
294 return 4;
295 default:
296 LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
297 UNIMPLEMENTED();
298 }
299 }
300
301 // Returns the number of bits per depth component of the specified depth format
302 static u32 DepthBitsPerPixel(DepthFormat format) {
303 switch (format) {
304 case DepthFormat::D16:
305 return 16;
306 case DepthFormat::D24:
307 case DepthFormat::D24S8:
308 return 24;
309 default:
310 LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
311 UNIMPLEMENTED();
312 }
313 }
314
315 INSERT_PADDING_WORDS(0x20);
316 56
317 enum class LightingSampler { 57 enum class LightingSampler {
318 Distribution0 = 0, 58 Distribution0 = 0,
@@ -957,8 +697,10 @@ ASSERT_REG_POSITION(texturing.tev_stage4, 0xf0);
957ASSERT_REG_POSITION(texturing.tev_stage5, 0xf8); 697ASSERT_REG_POSITION(texturing.tev_stage5, 0xf8);
958ASSERT_REG_POSITION(texturing.tev_combiner_buffer_color, 0xfd); 698ASSERT_REG_POSITION(texturing.tev_combiner_buffer_color, 0xfd);
959 699
960ASSERT_REG_POSITION(output_merger, 0x100); 700ASSERT_REG_POSITION(framebuffer, 0x100);
961ASSERT_REG_POSITION(framebuffer, 0x110); 701ASSERT_REG_POSITION(framebuffer.output_merger, 0x100);
702ASSERT_REG_POSITION(framebuffer.framebuffer, 0x110);
703
962ASSERT_REG_POSITION(lighting, 0x140); 704ASSERT_REG_POSITION(lighting, 0x140);
963ASSERT_REG_POSITION(vertex_attributes, 0x200); 705ASSERT_REG_POSITION(vertex_attributes, 0x200);
964ASSERT_REG_POSITION(index_array, 0x227); 706ASSERT_REG_POSITION(index_array, 0x227);
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 }
diff --git a/src/video_core/regs_framebuffer.h b/src/video_core/regs_framebuffer.h
new file mode 100644
index 000000000..40d8aea0c
--- /dev/null
+++ b/src/video_core/regs_framebuffer.h
@@ -0,0 +1,282 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8
9#include "common/bit_field.h"
10#include "common/common_funcs.h"
11#include "common/common_types.h"
12
13namespace Pica {
14
15struct FramebufferRegs {
16 enum class LogicOp : u32 {
17 Clear = 0,
18 And = 1,
19 AndReverse = 2,
20 Copy = 3,
21 Set = 4,
22 CopyInverted = 5,
23 NoOp = 6,
24 Invert = 7,
25 Nand = 8,
26 Or = 9,
27 Nor = 10,
28 Xor = 11,
29 Equiv = 12,
30 AndInverted = 13,
31 OrReverse = 14,
32 OrInverted = 15,
33 };
34
35 enum class BlendEquation : u32 {
36 Add = 0,
37 Subtract = 1,
38 ReverseSubtract = 2,
39 Min = 3,
40 Max = 4,
41 };
42
43 enum class BlendFactor : u32 {
44 Zero = 0,
45 One = 1,
46 SourceColor = 2,
47 OneMinusSourceColor = 3,
48 DestColor = 4,
49 OneMinusDestColor = 5,
50 SourceAlpha = 6,
51 OneMinusSourceAlpha = 7,
52 DestAlpha = 8,
53 OneMinusDestAlpha = 9,
54 ConstantColor = 10,
55 OneMinusConstantColor = 11,
56 ConstantAlpha = 12,
57 OneMinusConstantAlpha = 13,
58 SourceAlphaSaturate = 14,
59 };
60
61 enum class CompareFunc : u32 {
62 Never = 0,
63 Always = 1,
64 Equal = 2,
65 NotEqual = 3,
66 LessThan = 4,
67 LessThanOrEqual = 5,
68 GreaterThan = 6,
69 GreaterThanOrEqual = 7,
70 };
71
72 enum class StencilAction : u32 {
73 Keep = 0,
74 Zero = 1,
75 Replace = 2,
76 Increment = 3,
77 Decrement = 4,
78 Invert = 5,
79 IncrementWrap = 6,
80 DecrementWrap = 7,
81 };
82
83 struct {
84 union {
85 // If false, logic blending is used
86 BitField<8, 1, u32> alphablend_enable;
87 };
88
89 union {
90 BitField<0, 8, BlendEquation> blend_equation_rgb;
91 BitField<8, 8, BlendEquation> blend_equation_a;
92
93 BitField<16, 4, BlendFactor> factor_source_rgb;
94 BitField<20, 4, BlendFactor> factor_dest_rgb;
95
96 BitField<24, 4, BlendFactor> factor_source_a;
97 BitField<28, 4, BlendFactor> factor_dest_a;
98 } alpha_blending;
99
100 union {
101 BitField<0, 4, LogicOp> logic_op;
102 };
103
104 union {
105 u32 raw;
106 BitField<0, 8, u32> r;
107 BitField<8, 8, u32> g;
108 BitField<16, 8, u32> b;
109 BitField<24, 8, u32> a;
110 } blend_const;
111
112 union {
113 BitField<0, 1, u32> enable;
114 BitField<4, 3, CompareFunc> func;
115 BitField<8, 8, u32> ref;
116 } alpha_test;
117
118 struct {
119 union {
120 // Raw value of this register
121 u32 raw_func;
122
123 // If true, enable stencil testing
124 BitField<0, 1, u32> enable;
125
126 // Comparison operation for stencil testing
127 BitField<4, 3, CompareFunc> func;
128
129 // Mask used to control writing to the stencil buffer
130 BitField<8, 8, u32> write_mask;
131
132 // Value to compare against for stencil testing
133 BitField<16, 8, u32> reference_value;
134
135 // Mask to apply on stencil test inputs
136 BitField<24, 8, u32> input_mask;
137 };
138
139 union {
140 // Raw value of this register
141 u32 raw_op;
142
143 // Action to perform when the stencil test fails
144 BitField<0, 3, StencilAction> action_stencil_fail;
145
146 // Action to perform when stencil testing passed but depth testing fails
147 BitField<4, 3, StencilAction> action_depth_fail;
148
149 // Action to perform when both stencil and depth testing pass
150 BitField<8, 3, StencilAction> action_depth_pass;
151 };
152 } stencil_test;
153
154 union {
155 BitField<0, 1, u32> depth_test_enable;
156 BitField<4, 3, CompareFunc> depth_test_func;
157 BitField<8, 1, u32> red_enable;
158 BitField<9, 1, u32> green_enable;
159 BitField<10, 1, u32> blue_enable;
160 BitField<11, 1, u32> alpha_enable;
161 BitField<12, 1, u32> depth_write_enable;
162 };
163
164 INSERT_PADDING_WORDS(0x8);
165 } output_merger;
166
167 // Components are laid out in reverse byte order, most significant bits first.
168 enum class ColorFormat : u32 {
169 RGBA8 = 0,
170 RGB8 = 1,
171 RGB5A1 = 2,
172 RGB565 = 3,
173 RGBA4 = 4,
174 };
175
176 enum class DepthFormat : u32 {
177 D16 = 0,
178 D24 = 2,
179 D24S8 = 3,
180 };
181
182 // Returns the number of bytes in the specified color format
183 static unsigned BytesPerColorPixel(ColorFormat format) {
184 switch (format) {
185 case ColorFormat::RGBA8:
186 return 4;
187 case ColorFormat::RGB8:
188 return 3;
189 case ColorFormat::RGB5A1:
190 case ColorFormat::RGB565:
191 case ColorFormat::RGBA4:
192 return 2;
193 default:
194 LOG_CRITICAL(HW_GPU, "Unknown color format %u", format);
195 UNIMPLEMENTED();
196 }
197 }
198
199 struct FramebufferConfig {
200 INSERT_PADDING_WORDS(0x3);
201
202 union {
203 BitField<0, 4, u32> allow_color_write; // 0 = disable, else enable
204 };
205
206 INSERT_PADDING_WORDS(0x1);
207
208 union {
209 BitField<0, 2, u32> allow_depth_stencil_write; // 0 = disable, else enable
210 };
211
212 DepthFormat depth_format; // TODO: Should be a BitField!
213 BitField<16, 3, ColorFormat> color_format;
214
215 INSERT_PADDING_WORDS(0x4);
216
217 u32 depth_buffer_address;
218 u32 color_buffer_address;
219
220 union {
221 // Apparently, the framebuffer width is stored as expected,
222 // while the height is stored as the actual height minus one.
223 // Hence, don't access these fields directly but use the accessors
224 // GetWidth() and GetHeight() instead.
225 BitField<0, 11, u32> width;
226 BitField<12, 10, u32> height;
227 };
228
229 INSERT_PADDING_WORDS(0x1);
230
231 inline PAddr GetColorBufferPhysicalAddress() const {
232 return color_buffer_address * 8;
233 }
234 inline PAddr GetDepthBufferPhysicalAddress() const {
235 return depth_buffer_address * 8;
236 }
237
238 inline u32 GetWidth() const {
239 return width;
240 }
241
242 inline u32 GetHeight() const {
243 return height + 1;
244 }
245 } framebuffer;
246
247 // Returns the number of bytes in the specified depth format
248 static u32 BytesPerDepthPixel(DepthFormat format) {
249 switch (format) {
250 case DepthFormat::D16:
251 return 2;
252 case DepthFormat::D24:
253 return 3;
254 case DepthFormat::D24S8:
255 return 4;
256 default:
257 LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
258 UNIMPLEMENTED();
259 }
260 }
261
262 // Returns the number of bits per depth component of the specified depth format
263 static u32 DepthBitsPerPixel(DepthFormat format) {
264 switch (format) {
265 case DepthFormat::D16:
266 return 16;
267 case DepthFormat::D24:
268 case DepthFormat::D24S8:
269 return 24;
270 default:
271 LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
272 UNIMPLEMENTED();
273 }
274 }
275
276 INSERT_PADDING_WORDS(0x20);
277};
278
279static_assert(sizeof(FramebufferRegs) == 0x40 * sizeof(u32),
280 "FramebufferRegs struct has incorrect size");
281
282} // namespace Pica
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index f7eaa17e2..967c3159f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -183,7 +183,7 @@ void RasterizerOpenGL::DrawTriangles() {
183 CachedSurface* depth_surface; 183 CachedSurface* depth_surface;
184 MathUtil::Rectangle<int> rect; 184 MathUtil::Rectangle<int> rect;
185 std::tie(color_surface, depth_surface, rect) = 185 std::tie(color_surface, depth_surface, rect) =
186 res_cache.GetFramebufferSurfaces(regs.framebuffer); 186 res_cache.GetFramebufferSurfaces(regs.framebuffer.framebuffer);
187 187
188 state.draw.draw_framebuffer = framebuffer.handle; 188 state.draw.draw_framebuffer = framebuffer.handle;
189 state.Apply(); 189 state.Apply();
@@ -192,7 +192,8 @@ void RasterizerOpenGL::DrawTriangles() {
192 color_surface != nullptr ? color_surface->texture.handle : 0, 0); 192 color_surface != nullptr ? color_surface->texture.handle : 0, 0);
193 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 193 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
194 depth_surface != nullptr ? depth_surface->texture.handle : 0, 0); 194 depth_surface != nullptr ? depth_surface->texture.handle : 0, 0);
195 bool has_stencil = regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; 195 bool has_stencil =
196 regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8;
196 glFramebufferTexture2D( 197 glFramebufferTexture2D(
197 GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 198 GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
198 (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0); 199 (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0);
@@ -339,13 +340,13 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
339 break; 340 break;
340 341
341 // Blending 342 // Blending
342 case PICA_REG_INDEX(output_merger.alphablend_enable): 343 case PICA_REG_INDEX(framebuffer.output_merger.alphablend_enable):
343 SyncBlendEnabled(); 344 SyncBlendEnabled();
344 break; 345 break;
345 case PICA_REG_INDEX(output_merger.alpha_blending): 346 case PICA_REG_INDEX(framebuffer.output_merger.alpha_blending):
346 SyncBlendFuncs(); 347 SyncBlendFuncs();
347 break; 348 break;
348 case PICA_REG_INDEX(output_merger.blend_const): 349 case PICA_REG_INDEX(framebuffer.output_merger.blend_const):
349 SyncBlendColor(); 350 SyncBlendColor();
350 break; 351 break;
351 352
@@ -365,25 +366,25 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
365 break; 366 break;
366 367
367 // Alpha test 368 // Alpha test
368 case PICA_REG_INDEX(output_merger.alpha_test): 369 case PICA_REG_INDEX(framebuffer.output_merger.alpha_test):
369 SyncAlphaTest(); 370 SyncAlphaTest();
370 shader_dirty = true; 371 shader_dirty = true;
371 break; 372 break;
372 373
373 // Sync GL stencil test + stencil write mask 374 // Sync GL stencil test + stencil write mask
374 // (Pica stencil test function register also contains a stencil write mask) 375 // (Pica stencil test function register also contains a stencil write mask)
375 case PICA_REG_INDEX(output_merger.stencil_test.raw_func): 376 case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_func):
376 SyncStencilTest(); 377 SyncStencilTest();
377 SyncStencilWriteMask(); 378 SyncStencilWriteMask();
378 break; 379 break;
379 case PICA_REG_INDEX(output_merger.stencil_test.raw_op): 380 case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_op):
380 case PICA_REG_INDEX(framebuffer.depth_format): 381 case PICA_REG_INDEX(framebuffer.framebuffer.depth_format):
381 SyncStencilTest(); 382 SyncStencilTest();
382 break; 383 break;
383 384
384 // Sync GL depth test + depth and color write mask 385 // Sync GL depth test + depth and color write mask
385 // (Pica depth test function register also contains a depth and color write mask) 386 // (Pica depth test function register also contains a depth and color write mask)
386 case PICA_REG_INDEX(output_merger.depth_test_enable): 387 case PICA_REG_INDEX(framebuffer.output_merger.depth_test_enable):
387 SyncDepthTest(); 388 SyncDepthTest();
388 SyncDepthWriteMask(); 389 SyncDepthWriteMask();
389 SyncColorWriteMask(); 390 SyncColorWriteMask();
@@ -391,14 +392,14 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
391 392
392 // Sync GL depth and stencil write mask 393 // Sync GL depth and stencil write mask
393 // (This is a dedicated combined depth / stencil write-enable register) 394 // (This is a dedicated combined depth / stencil write-enable register)
394 case PICA_REG_INDEX(framebuffer.allow_depth_stencil_write): 395 case PICA_REG_INDEX(framebuffer.framebuffer.allow_depth_stencil_write):
395 SyncDepthWriteMask(); 396 SyncDepthWriteMask();
396 SyncStencilWriteMask(); 397 SyncStencilWriteMask();
397 break; 398 break;
398 399
399 // Sync GL color write mask 400 // Sync GL color write mask
400 // (This is a dedicated color write-enable register) 401 // (This is a dedicated color write-enable register)
401 case PICA_REG_INDEX(framebuffer.allow_color_write): 402 case PICA_REG_INDEX(framebuffer.framebuffer.allow_color_write):
402 SyncColorWriteMask(); 403 SyncColorWriteMask();
403 break; 404 break;
404 405
@@ -408,7 +409,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
408 break; 409 break;
409 410
410 // Logic op 411 // Logic op
411 case PICA_REG_INDEX(output_merger.logic_op): 412 case PICA_REG_INDEX(framebuffer.output_merger.logic_op):
412 SyncLogicOp(); 413 SyncLogicOp();
413 break; 414 break;
414 415
@@ -1158,25 +1159,28 @@ void RasterizerOpenGL::SyncDepthOffset() {
1158} 1159}
1159 1160
1160void RasterizerOpenGL::SyncBlendEnabled() { 1161void RasterizerOpenGL::SyncBlendEnabled() {
1161 state.blend.enabled = (Pica::g_state.regs.output_merger.alphablend_enable == 1); 1162 state.blend.enabled = (Pica::g_state.regs.framebuffer.output_merger.alphablend_enable == 1);
1162} 1163}
1163 1164
1164void RasterizerOpenGL::SyncBlendFuncs() { 1165void RasterizerOpenGL::SyncBlendFuncs() {
1165 const auto& regs = Pica::g_state.regs; 1166 const auto& regs = Pica::g_state.regs;
1166 state.blend.rgb_equation = 1167 state.blend.rgb_equation =
1167 PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_rgb); 1168 PicaToGL::BlendEquation(regs.framebuffer.output_merger.alpha_blending.blend_equation_rgb);
1168 state.blend.a_equation = 1169 state.blend.a_equation =
1169 PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_a); 1170 PicaToGL::BlendEquation(regs.framebuffer.output_merger.alpha_blending.blend_equation_a);
1170 state.blend.src_rgb_func = 1171 state.blend.src_rgb_func =
1171 PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb); 1172 PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_source_rgb);
1172 state.blend.dst_rgb_func = 1173 state.blend.dst_rgb_func =
1173 PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb); 1174 PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_rgb);
1174 state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a); 1175 state.blend.src_a_func =
1175 state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a); 1176 PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_source_a);
1177 state.blend.dst_a_func =
1178 PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_a);
1176} 1179}
1177 1180
1178void RasterizerOpenGL::SyncBlendColor() { 1181void RasterizerOpenGL::SyncBlendColor() {
1179 auto blend_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.output_merger.blend_const.raw); 1182 auto blend_color =
1183 PicaToGL::ColorRGBA8(Pica::g_state.regs.framebuffer.output_merger.blend_const.raw);
1180 state.blend.color.red = blend_color[0]; 1184 state.blend.color.red = blend_color[0];
1181 state.blend.color.green = blend_color[1]; 1185 state.blend.color.green = blend_color[1];
1182 state.blend.color.blue = blend_color[2]; 1186 state.blend.color.blue = blend_color[2];
@@ -1208,66 +1212,73 @@ void RasterizerOpenGL::SyncFogLUT() {
1208 1212
1209void RasterizerOpenGL::SyncAlphaTest() { 1213void RasterizerOpenGL::SyncAlphaTest() {
1210 const auto& regs = Pica::g_state.regs; 1214 const auto& regs = Pica::g_state.regs;
1211 if (regs.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) { 1215 if (regs.framebuffer.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) {
1212 uniform_block_data.data.alphatest_ref = regs.output_merger.alpha_test.ref; 1216 uniform_block_data.data.alphatest_ref = regs.framebuffer.output_merger.alpha_test.ref;
1213 uniform_block_data.dirty = true; 1217 uniform_block_data.dirty = true;
1214 } 1218 }
1215} 1219}
1216 1220
1217void RasterizerOpenGL::SyncLogicOp() { 1221void RasterizerOpenGL::SyncLogicOp() {
1218 state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op); 1222 state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.framebuffer.output_merger.logic_op);
1219} 1223}
1220 1224
1221void RasterizerOpenGL::SyncColorWriteMask() { 1225void RasterizerOpenGL::SyncColorWriteMask() {
1222 const auto& regs = Pica::g_state.regs; 1226 const auto& regs = Pica::g_state.regs;
1223 1227
1224 auto IsColorWriteEnabled = [&](u32 value) { 1228 auto IsColorWriteEnabled = [&](u32 value) {
1225 return (regs.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE : GL_FALSE; 1229 return (regs.framebuffer.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE
1230 : GL_FALSE;
1226 }; 1231 };
1227 1232
1228 state.color_mask.red_enabled = IsColorWriteEnabled(regs.output_merger.red_enable); 1233 state.color_mask.red_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.red_enable);
1229 state.color_mask.green_enabled = IsColorWriteEnabled(regs.output_merger.green_enable); 1234 state.color_mask.green_enabled =
1230 state.color_mask.blue_enabled = IsColorWriteEnabled(regs.output_merger.blue_enable); 1235 IsColorWriteEnabled(regs.framebuffer.output_merger.green_enable);
1231 state.color_mask.alpha_enabled = IsColorWriteEnabled(regs.output_merger.alpha_enable); 1236 state.color_mask.blue_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.blue_enable);
1237 state.color_mask.alpha_enabled =
1238 IsColorWriteEnabled(regs.framebuffer.output_merger.alpha_enable);
1232} 1239}
1233 1240
1234void RasterizerOpenGL::SyncStencilWriteMask() { 1241void RasterizerOpenGL::SyncStencilWriteMask() {
1235 const auto& regs = Pica::g_state.regs; 1242 const auto& regs = Pica::g_state.regs;
1236 state.stencil.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0) 1243 state.stencil.write_mask =
1237 ? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask) 1244 (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0)
1238 : 0; 1245 ? static_cast<GLuint>(regs.framebuffer.output_merger.stencil_test.write_mask)
1246 : 0;
1239} 1247}
1240 1248
1241void RasterizerOpenGL::SyncDepthWriteMask() { 1249void RasterizerOpenGL::SyncDepthWriteMask() {
1242 const auto& regs = Pica::g_state.regs; 1250 const auto& regs = Pica::g_state.regs;
1243 state.depth.write_mask = 1251 state.depth.write_mask = (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 &&
1244 (regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable) 1252 regs.framebuffer.output_merger.depth_write_enable)
1245 ? GL_TRUE 1253 ? GL_TRUE
1246 : GL_FALSE; 1254 : GL_FALSE;
1247} 1255}
1248 1256
1249void RasterizerOpenGL::SyncStencilTest() { 1257void RasterizerOpenGL::SyncStencilTest() {
1250 const auto& regs = Pica::g_state.regs; 1258 const auto& regs = Pica::g_state.regs;
1251 state.stencil.test_enabled = regs.output_merger.stencil_test.enable && 1259 state.stencil.test_enabled =
1252 regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; 1260 regs.framebuffer.output_merger.stencil_test.enable &&
1253 state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func); 1261 regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8;
1254 state.stencil.test_ref = regs.output_merger.stencil_test.reference_value; 1262 state.stencil.test_func =
1255 state.stencil.test_mask = regs.output_merger.stencil_test.input_mask; 1263 PicaToGL::CompareFunc(regs.framebuffer.output_merger.stencil_test.func);
1264 state.stencil.test_ref = regs.framebuffer.output_merger.stencil_test.reference_value;
1265 state.stencil.test_mask = regs.framebuffer.output_merger.stencil_test.input_mask;
1256 state.stencil.action_stencil_fail = 1266 state.stencil.action_stencil_fail =
1257 PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail); 1267 PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_stencil_fail);
1258 state.stencil.action_depth_fail = 1268 state.stencil.action_depth_fail =
1259 PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail); 1269 PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_depth_fail);
1260 state.stencil.action_depth_pass = 1270 state.stencil.action_depth_pass =
1261 PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass); 1271 PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_depth_pass);
1262} 1272}
1263 1273
1264void RasterizerOpenGL::SyncDepthTest() { 1274void RasterizerOpenGL::SyncDepthTest() {
1265 const auto& regs = Pica::g_state.regs; 1275 const auto& regs = Pica::g_state.regs;
1266 state.depth.test_enabled = 1276 state.depth.test_enabled = regs.framebuffer.output_merger.depth_test_enable == 1 ||
1267 regs.output_merger.depth_test_enable == 1 || regs.output_merger.depth_write_enable == 1; 1277 regs.framebuffer.output_merger.depth_write_enable == 1;
1268 state.depth.test_func = regs.output_merger.depth_test_enable == 1 1278 state.depth.test_func =
1269 ? PicaToGL::CompareFunc(regs.output_merger.depth_test_func) 1279 regs.framebuffer.output_merger.depth_test_enable == 1
1270 : GL_ALWAYS; 1280 ? PicaToGL::CompareFunc(regs.framebuffer.output_merger.depth_test_func)
1281 : GL_ALWAYS;
1271} 1282}
1272 1283
1273void RasterizerOpenGL::SyncCombinerColor() { 1284void RasterizerOpenGL::SyncCombinerColor() {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 519df6478..bfdc0c8a4 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -56,9 +56,9 @@ union PicaShaderConfig {
56 56
57 state.depthmap_enable = regs.rasterizer.depthmap_enable; 57 state.depthmap_enable = regs.rasterizer.depthmap_enable;
58 58
59 state.alpha_test_func = regs.output_merger.alpha_test.enable 59 state.alpha_test_func = regs.framebuffer.output_merger.alpha_test.enable
60 ? regs.output_merger.alpha_test.func.Value() 60 ? regs.framebuffer.output_merger.alpha_test.func.Value()
61 : Pica::Regs::CompareFunc::Always; 61 : Pica::FramebufferRegs::CompareFunc::Always;
62 62
63 state.texture0_type = regs.texturing.texture0.type; 63 state.texture0_type = regs.texturing.texture0.type;
64 64
@@ -172,7 +172,7 @@ union PicaShaderConfig {
172 }; 172 };
173 173
174 struct State { 174 struct State {
175 Pica::Regs::CompareFunc alpha_test_func; 175 Pica::FramebufferRegs::CompareFunc alpha_test_func;
176 Pica::RasterizerRegs::ScissorMode scissor_test_mode; 176 Pica::RasterizerRegs::ScissorMode scissor_test_mode;
177 Pica::TexturingRegs::TextureConfig::TextureType texture0_type; 177 Pica::TexturingRegs::TextureConfig::TextureType texture0_type;
178 std::array<TevStageConfigRaw, 6> tev_stages; 178 std::array<TevStageConfigRaw, 6> tev_stages;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 6d08d1a67..0818a87b3 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -525,7 +525,9 @@ CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(
525} 525}
526 526
527std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> 527std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>>
528RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config) { 528RasterizerCacheOpenGL::GetFramebufferSurfaces(
529 const Pica::FramebufferRegs::FramebufferConfig& config) {
530
529 const auto& regs = Pica::g_state.regs; 531 const auto& regs = Pica::g_state.regs;
530 532
531 // Make sur that framebuffers don't overlap if both color and depth are being used 533 // Make sur that framebuffers don't overlap if both color and depth are being used
@@ -537,11 +539,12 @@ RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfi
537 config.GetColorBufferPhysicalAddress(), 539 config.GetColorBufferPhysicalAddress(),
538 fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())), 540 fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())),
539 config.GetDepthBufferPhysicalAddress(), 541 config.GetDepthBufferPhysicalAddress(),
540 fb_area * Pica::Regs::BytesPerDepthPixel(config.depth_format)); 542 fb_area * Pica::FramebufferRegs::BytesPerDepthPixel(config.depth_format));
541 bool using_color_fb = config.GetColorBufferPhysicalAddress() != 0; 543 bool using_color_fb = config.GetColorBufferPhysicalAddress() != 0;
542 bool using_depth_fb = config.GetDepthBufferPhysicalAddress() != 0 && 544 bool using_depth_fb =
543 (regs.output_merger.depth_test_enable || 545 config.GetDepthBufferPhysicalAddress() != 0 &&
544 regs.output_merger.depth_write_enable || !framebuffers_overlap); 546 (regs.framebuffer.output_merger.depth_test_enable ||
547 regs.framebuffer.output_merger.depth_write_enable || !framebuffers_overlap);
545 548
546 if (framebuffers_overlap && using_color_fb && using_depth_fb) { 549 if (framebuffers_overlap && using_color_fb && using_depth_fb) {
547 LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; " 550 LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; "
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index c354dfa33..2812b4bf6 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -100,11 +100,11 @@ struct CachedSurface {
100 return ((unsigned int)format < 14) ? (PixelFormat)format : PixelFormat::Invalid; 100 return ((unsigned int)format < 14) ? (PixelFormat)format : PixelFormat::Invalid;
101 } 101 }
102 102
103 static PixelFormat PixelFormatFromColorFormat(Pica::Regs::ColorFormat format) { 103 static PixelFormat PixelFormatFromColorFormat(Pica::FramebufferRegs::ColorFormat format) {
104 return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid; 104 return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid;
105 } 105 }
106 106
107 static PixelFormat PixelFormatFromDepthFormat(Pica::Regs::DepthFormat format) { 107 static PixelFormat PixelFormatFromDepthFormat(Pica::FramebufferRegs::DepthFormat format) {
108 return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14) 108 return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14)
109 : PixelFormat::Invalid; 109 : PixelFormat::Invalid;
110 } 110 }
@@ -217,7 +217,7 @@ public:
217 /// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer 217 /// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer
218 /// configuration 218 /// configuration
219 std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> GetFramebufferSurfaces( 219 std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> GetFramebufferSurfaces(
220 const Pica::Regs::FramebufferConfig& config); 220 const Pica::FramebufferRegs::FramebufferConfig& config);
221 221
222 /// Attempt to get a surface that exactly matches the fill region and format 222 /// Attempt to get a surface that exactly matches the fill region and format
223 CachedSurface* TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config); 223 CachedSurface* TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config);
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index c3b0fdcee..9c7687f62 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -277,8 +277,8 @@ static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation oper
277} 277}
278 278
279/// Writes the if-statement condition used to evaluate alpha testing 279/// Writes the if-statement condition used to evaluate alpha testing
280static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) { 280static void AppendAlphaTestCondition(std::string& out, Pica::FramebufferRegs::CompareFunc func) {
281 using CompareFunc = Regs::CompareFunc; 281 using CompareFunc = Pica::FramebufferRegs::CompareFunc;
282 switch (func) { 282 switch (func) {
283 case CompareFunc::Never: 283 case CompareFunc::Never:
284 out += "true"; 284 out += "true";
@@ -634,7 +634,7 @@ vec4 secondary_fragment_color = vec4(0.0);
634)"; 634)";
635 635
636 // Do not do any sort of processing if it's obvious we're not going to pass the alpha test 636 // Do not do any sort of processing if it's obvious we're not going to pass the alpha test
637 if (state.alpha_test_func == Regs::CompareFunc::Never) { 637 if (state.alpha_test_func == Pica::FramebufferRegs::CompareFunc::Never) {
638 out += "discard; }"; 638 out += "discard; }";
639 return out; 639 return out;
640 } 640 }
@@ -667,7 +667,7 @@ vec4 secondary_fragment_color = vec4(0.0);
667 for (size_t index = 0; index < state.tev_stages.size(); ++index) 667 for (size_t index = 0; index < state.tev_stages.size(); ++index)
668 WriteTevStage(out, config, (unsigned)index); 668 WriteTevStage(out, config, (unsigned)index);
669 669
670 if (state.alpha_test_func != Regs::CompareFunc::Always) { 670 if (state.alpha_test_func != Pica::FramebufferRegs::CompareFunc::Always) {
671 out += "if ("; 671 out += "if (";
672 AppendAlphaTestCondition(out, state.alpha_test_func); 672 AppendAlphaTestCondition(out, state.alpha_test_func);
673 out += ") discard;\n"; 673 out += ") discard;\n";
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index 37cfbd45a..c1bf3dc24 100644
--- a/src/video_core/renderer_opengl/pica_to_gl.h
+++ b/src/video_core/renderer_opengl/pica_to_gl.h
@@ -76,7 +76,7 @@ inline GLenum WrapMode(Pica::TexturingRegs::TextureConfig::WrapMode mode) {
76 return gl_mode; 76 return gl_mode;
77} 77}
78 78
79inline GLenum BlendEquation(Pica::Regs::BlendEquation equation) { 79inline GLenum BlendEquation(Pica::FramebufferRegs::BlendEquation equation) {
80 static const GLenum blend_equation_table[] = { 80 static const GLenum blend_equation_table[] = {
81 GL_FUNC_ADD, // BlendEquation::Add 81 GL_FUNC_ADD, // BlendEquation::Add
82 GL_FUNC_SUBTRACT, // BlendEquation::Subtract 82 GL_FUNC_SUBTRACT, // BlendEquation::Subtract
@@ -96,7 +96,7 @@ inline GLenum BlendEquation(Pica::Regs::BlendEquation equation) {
96 return blend_equation_table[(unsigned)equation]; 96 return blend_equation_table[(unsigned)equation];
97} 97}
98 98
99inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) { 99inline GLenum BlendFunc(Pica::FramebufferRegs::BlendFactor factor) {
100 static const GLenum blend_func_table[] = { 100 static const GLenum blend_func_table[] = {
101 GL_ZERO, // BlendFactor::Zero 101 GL_ZERO, // BlendFactor::Zero
102 GL_ONE, // BlendFactor::One 102 GL_ONE, // BlendFactor::One
@@ -126,7 +126,7 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) {
126 return blend_func_table[(unsigned)factor]; 126 return blend_func_table[(unsigned)factor];
127} 127}
128 128
129inline GLenum LogicOp(Pica::Regs::LogicOp op) { 129inline GLenum LogicOp(Pica::FramebufferRegs::LogicOp op) {
130 static const GLenum logic_op_table[] = { 130 static const GLenum logic_op_table[] = {
131 GL_CLEAR, // Clear 131 GL_CLEAR, // Clear
132 GL_AND, // And 132 GL_AND, // And
@@ -157,7 +157,7 @@ inline GLenum LogicOp(Pica::Regs::LogicOp op) {
157 return logic_op_table[(unsigned)op]; 157 return logic_op_table[(unsigned)op];
158} 158}
159 159
160inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { 160inline GLenum CompareFunc(Pica::FramebufferRegs::CompareFunc func) {
161 static const GLenum compare_func_table[] = { 161 static const GLenum compare_func_table[] = {
162 GL_NEVER, // CompareFunc::Never 162 GL_NEVER, // CompareFunc::Never
163 GL_ALWAYS, // CompareFunc::Always 163 GL_ALWAYS, // CompareFunc::Always
@@ -180,7 +180,7 @@ inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
180 return compare_func_table[(unsigned)func]; 180 return compare_func_table[(unsigned)func];
181} 181}
182 182
183inline GLenum StencilOp(Pica::Regs::StencilAction action) { 183inline GLenum StencilOp(Pica::FramebufferRegs::StencilAction action) {
184 static const GLenum stencil_op_table[] = { 184 static const GLenum stencil_op_table[] = {
185 GL_KEEP, // StencilAction::Keep 185 GL_KEEP, // StencilAction::Keep
186 GL_ZERO, // StencilAction::Zero 186 GL_ZERO, // StencilAction::Zero