summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2015-05-22 23:27:41 -0400
committerGravatar bunnei2015-05-22 23:27:41 -0400
commita7946f9027a87da93cd76ec46d54cadf4203b082 (patch)
tree01e98e937a3ed9d8c65b270df016658f8ae89a97
parentMerge pull request #801 from purpasmart96/hid_stubs (diff)
parentPica: Create 'State' structure and move state memory there. (diff)
downloadyuzu-a7946f9027a87da93cd76ec46d54cadf4203b082.tar.gz
yuzu-a7946f9027a87da93cd76ec46d54cadf4203b082.tar.xz
yuzu-a7946f9027a87da93cd76ec46d54cadf4203b082.zip
Merge pull request #776 from bunnei/pica-state
GPU: Consolidate Pica state
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.cpp10
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.cpp4
-rw-r--r--src/citra_qt/debugger/graphics_vertex_shader.cpp6
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/clipper.cpp13
-rw-r--r--src/video_core/command_processor.cpp47
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp2
-rw-r--r--src/video_core/pica.cpp20
-rw-r--r--src/video_core/pica.h186
-rw-r--r--src/video_core/rasterizer.cpp244
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp234
-rw-r--r--src/video_core/renderer_opengl/pica_to_gl.h12
-rw-r--r--src/video_core/vertex_shader.cpp96
-rw-r--r--src/video_core/vertex_shader.h11
-rw-r--r--src/video_core/video_core.cpp13
15 files changed, 461 insertions, 438 deletions
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp
index 66e11dd5b..804c735a3 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.cpp
+++ b/src/citra_qt/debugger/graphics_cmdlists.cpp
@@ -228,7 +228,7 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&
228 228
229#define COMMAND_IN_RANGE(cmd_id, reg_name) \ 229#define COMMAND_IN_RANGE(cmd_id, reg_name) \
230 (cmd_id >= PICA_REG_INDEX(reg_name) && \ 230 (cmd_id >= PICA_REG_INDEX(reg_name) && \
231 cmd_id < PICA_REG_INDEX(reg_name) + sizeof(decltype(Pica::registers.reg_name)) / 4) 231 cmd_id < PICA_REG_INDEX(reg_name) + sizeof(decltype(Pica::g_state.regs.reg_name)) / 4)
232 232
233void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) { 233void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
234 const unsigned int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt(); 234 const unsigned int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt();
@@ -244,8 +244,8 @@ void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
244 } else { 244 } else {
245 index = 2; 245 index = 2;
246 } 246 }
247 auto config = Pica::registers.GetTextures()[index].config; 247 auto config = Pica::g_state.regs.GetTextures()[index].config;
248 auto format = Pica::registers.GetTextures()[index].format; 248 auto format = Pica::g_state.regs.GetTextures()[index].format;
249 auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format); 249 auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
250 250
251 // TODO: Instead, emit a signal here to be caught by the main window widget. 251 // TODO: Instead, emit a signal here to be caught by the main window widget.
@@ -270,8 +270,8 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
270 } else { 270 } else {
271 index = 2; 271 index = 2;
272 } 272 }
273 auto config = Pica::registers.GetTextures()[index].config; 273 auto config = Pica::g_state.regs.GetTextures()[index].config;
274 auto format = Pica::registers.GetTextures()[index].format; 274 auto format = Pica::g_state.regs.GetTextures()[index].format;
275 275
276 auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format); 276 auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
277 u8* src = Memory::GetPhysicalPointer(config.GetPhysicalAddress()); 277 u8* src = Memory::GetPhysicalPointer(config.GetPhysicalAddress());
diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp
index 0c1a3f47f..e07344591 100644
--- a/src/citra_qt/debugger/graphics_framebuffer.cpp
+++ b/src/citra_qt/debugger/graphics_framebuffer.cpp
@@ -178,7 +178,7 @@ void GraphicsFramebufferWidget::OnUpdate()
178 { 178 {
179 // TODO: Store a reference to the registers in the debug context instead of accessing them directly... 179 // TODO: Store a reference to the registers in the debug context instead of accessing them directly...
180 180
181 const auto& framebuffer = Pica::registers.framebuffer; 181 const auto& framebuffer = Pica::g_state.regs.framebuffer;
182 182
183 framebuffer_address = framebuffer.GetColorBufferPhysicalAddress(); 183 framebuffer_address = framebuffer.GetColorBufferPhysicalAddress();
184 framebuffer_width = framebuffer.GetWidth(); 184 framebuffer_width = framebuffer.GetWidth();
@@ -191,7 +191,7 @@ void GraphicsFramebufferWidget::OnUpdate()
191 191
192 case Source::DepthBuffer: 192 case Source::DepthBuffer:
193 { 193 {
194 const auto& framebuffer = Pica::registers.framebuffer; 194 const auto& framebuffer = Pica::g_state.regs.framebuffer;
195 195
196 framebuffer_address = framebuffer.GetDepthBufferPhysicalAddress(); 196 framebuffer_address = framebuffer.GetDepthBufferPhysicalAddress();
197 framebuffer_width = framebuffer.GetWidth(); 197 framebuffer_width = framebuffer.GetWidth();
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp
index 3b072d015..14d3f8f39 100644
--- a/src/citra_qt/debugger/graphics_vertex_shader.cpp
+++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp
@@ -253,13 +253,13 @@ void GraphicsVertexShaderModel::OnUpdate()
253 253
254 info.Clear(); 254 info.Clear();
255 255
256 for (auto instr : Pica::VertexShader::GetShaderBinary()) 256 for (auto instr : Pica::g_state.vs.program_code)
257 info.code.push_back({instr}); 257 info.code.push_back({instr});
258 258
259 for (auto pattern : Pica::VertexShader::GetSwizzlePatterns()) 259 for (auto pattern : Pica::g_state.vs.swizzle_data)
260 info.swizzle_info.push_back({pattern}); 260 info.swizzle_info.push_back({pattern});
261 261
262 info.labels.insert({Pica::registers.vs_main_offset, "main"}); 262 info.labels.insert({ Pica::g_state.regs.vs_main_offset, "main" });
263 263
264 endResetModel(); 264 endResetModel();
265} 265}
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 9866078d4..0258a3255 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -9,6 +9,7 @@ set(SRCS
9 debug_utils/debug_utils.cpp 9 debug_utils/debug_utils.cpp
10 clipper.cpp 10 clipper.cpp
11 command_processor.cpp 11 command_processor.cpp
12 pica.cpp
12 primitive_assembly.cpp 13 primitive_assembly.cpp
13 rasterizer.cpp 14 rasterizer.cpp
14 utils.cpp 15 utils.cpp
diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp
index ba3876a76..943f3eb35 100644
--- a/src/video_core/clipper.cpp
+++ b/src/video_core/clipper.cpp
@@ -58,12 +58,13 @@ static void InitScreenCoordinates(OutputVertex& vtx)
58 float24 offset_z; 58 float24 offset_z;
59 } viewport; 59 } viewport;
60 60
61 viewport.halfsize_x = float24::FromRawFloat24(registers.viewport_size_x); 61 const auto& regs = g_state.regs;
62 viewport.halfsize_y = float24::FromRawFloat24(registers.viewport_size_y); 62 viewport.halfsize_x = float24::FromRawFloat24(regs.viewport_size_x);
63 viewport.offset_x = float24::FromFloat32(static_cast<float>(registers.viewport_corner.x)); 63 viewport.halfsize_y = float24::FromRawFloat24(regs.viewport_size_y);
64 viewport.offset_y = float24::FromFloat32(static_cast<float>(registers.viewport_corner.y)); 64 viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.viewport_corner.x));
65 viewport.zscale = float24::FromRawFloat24(registers.viewport_depth_range); 65 viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.viewport_corner.y));
66 viewport.offset_z = float24::FromRawFloat24(registers.viewport_depth_far_plane); 66 viewport.zscale = float24::FromRawFloat24(regs.viewport_depth_range);
67 viewport.offset_z = float24::FromRawFloat24(regs.viewport_depth_far_plane);
67 68
68 float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w; 69 float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w;
69 vtx.color *= inv_w; 70 vtx.color *= inv_w;
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 5c4c04408..100d8c7c1 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -21,8 +21,6 @@
21 21
22namespace Pica { 22namespace Pica {
23 23
24Regs registers;
25
26namespace CommandProcessor { 24namespace CommandProcessor {
27 25
28static int float_regs_counter = 0; 26static int float_regs_counter = 0;
@@ -36,8 +34,9 @@ static u32 default_attr_write_buffer[3];
36Common::Profiling::TimingCategory category_drawing("Drawing"); 34Common::Profiling::TimingCategory category_drawing("Drawing");
37 35
38static inline void WritePicaReg(u32 id, u32 value, u32 mask) { 36static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
37 auto& regs = g_state.regs;
39 38
40 if (id >= registers.NumIds()) 39 if (id >= regs.NumIds())
41 return; 40 return;
42 41
43 // If we're skipping this frame, only allow trigger IRQ 42 // If we're skipping this frame, only allow trigger IRQ
@@ -45,13 +44,13 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
45 return; 44 return;
46 45
47 // TODO: Figure out how register masking acts on e.g. vs_uniform_setup.set_value 46 // TODO: Figure out how register masking acts on e.g. vs_uniform_setup.set_value
48 u32 old_value = registers[id]; 47 u32 old_value = regs[id];
49 registers[id] = (old_value & ~mask) | (value & mask); 48 regs[id] = (old_value & ~mask) | (value & mask);
50 49
51 if (g_debug_context) 50 if (g_debug_context)
52 g_debug_context->OnEvent(DebugContext::Event::CommandLoaded, reinterpret_cast<void*>(&id)); 51 g_debug_context->OnEvent(DebugContext::Event::CommandLoaded, reinterpret_cast<void*>(&id));
53 52
54 DebugUtils::OnPicaRegWrite(id, registers[id]); 53 DebugUtils::OnPicaRegWrite(id, regs[id]);
55 54
56 switch(id) { 55 switch(id) {
57 // Trigger IRQ 56 // Trigger IRQ
@@ -65,12 +64,12 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
65 { 64 {
66 Common::Profiling::ScopeTimer scope_timer(category_drawing); 65 Common::Profiling::ScopeTimer scope_timer(category_drawing);
67 66
68 DebugUtils::DumpTevStageConfig(registers.GetTevStages()); 67 DebugUtils::DumpTevStageConfig(regs.GetTevStages());
69 68
70 if (g_debug_context) 69 if (g_debug_context)
71 g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr); 70 g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr);
72 71
73 const auto& attribute_config = registers.vertex_attributes; 72 const auto& attribute_config = regs.vertex_attributes;
74 const u32 base_address = attribute_config.GetPhysicalBaseAddress(); 73 const u32 base_address = attribute_config.GetPhysicalBaseAddress();
75 74
76 // Information about internal vertex attributes 75 // Information about internal vertex attributes
@@ -103,16 +102,16 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
103 // Load vertices 102 // Load vertices
104 bool is_indexed = (id == PICA_REG_INDEX(trigger_draw_indexed)); 103 bool is_indexed = (id == PICA_REG_INDEX(trigger_draw_indexed));
105 104
106 const auto& index_info = registers.index_array; 105 const auto& index_info = regs.index_array;
107 const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset); 106 const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset);
108 const u16* index_address_16 = (u16*)index_address_8; 107 const u16* index_address_16 = (u16*)index_address_8;
109 bool index_u16 = index_info.format != 0; 108 bool index_u16 = index_info.format != 0;
110 109
111 DebugUtils::GeometryDumper geometry_dumper; 110 DebugUtils::GeometryDumper geometry_dumper;
112 PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(registers.triangle_topology.Value()); 111 PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(regs.triangle_topology.Value());
113 PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(registers.triangle_topology.Value()); 112 PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value());
114 113
115 for (unsigned int index = 0; index < registers.num_vertices; ++index) 114 for (unsigned int index = 0; index < regs.num_vertices; ++index)
116 { 115 {
117 unsigned int vertex = is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) : index; 116 unsigned int vertex = is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) : index;
118 117
@@ -131,7 +130,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
131 for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) { 130 for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) {
132 // Load the default attribute if we're configured to do so, this data will be overwritten by the loader data if it's set 131 // Load the default attribute if we're configured to do so, this data will be overwritten by the loader data if it's set
133 if (attribute_config.IsDefaultAttribute(i)) { 132 if (attribute_config.IsDefaultAttribute(i)) {
134 input.attr[i] = VertexShader::GetDefaultAttribute(i); 133 input.attr[i] = g_state.vs.default_attributes[i];
135 LOG_TRACE(HW_GPU, "Loaded default attribute %x for vertex %x (index %x): (%f, %f, %f, %f)", 134 LOG_TRACE(HW_GPU, "Loaded default attribute %x for vertex %x (index %x): (%f, %f, %f, %f)",
136 i, vertex, index, 135 i, vertex, index,
137 input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(), 136 input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(),
@@ -216,7 +215,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
216 215
217 case PICA_REG_INDEX(vs_bool_uniforms): 216 case PICA_REG_INDEX(vs_bool_uniforms):
218 for (unsigned i = 0; i < 16; ++i) 217 for (unsigned i = 0; i < 16; ++i)
219 VertexShader::GetBoolUniform(i) = (registers.vs_bool_uniforms.Value() & (1 << i)) != 0; 218 g_state.vs.uniforms.b[i] = (regs.vs_bool_uniforms.Value() & (1 << i)) != 0;
220 219
221 break; 220 break;
222 221
@@ -226,8 +225,8 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
226 case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[3], 0x2b4): 225 case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[3], 0x2b4):
227 { 226 {
228 int index = (id - PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[0], 0x2b1)); 227 int index = (id - PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[0], 0x2b1));
229 auto values = registers.vs_int_uniforms[index]; 228 auto values = regs.vs_int_uniforms[index];
230 VertexShader::GetIntUniform(index) = Math::Vec4<u8>(values.x, values.y, values.z, values.w); 229 g_state.vs.uniforms.i[index] = Math::Vec4<u8>(values.x, values.y, values.z, values.w);
231 LOG_TRACE(HW_GPU, "Set integer uniform %d to %02x %02x %02x %02x", 230 LOG_TRACE(HW_GPU, "Set integer uniform %d to %02x %02x %02x %02x",
232 index, values.x.Value(), values.y.Value(), values.z.Value(), values.w.Value()); 231 index, values.x.Value(), values.y.Value(), values.z.Value(), values.w.Value());
233 break; 232 break;
@@ -242,7 +241,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
242 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[6], 0x2c7): 241 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[6], 0x2c7):
243 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[7], 0x2c8): 242 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[7], 0x2c8):
244 { 243 {
245 auto& uniform_setup = registers.vs_uniform_setup; 244 auto& uniform_setup = regs.vs_uniform_setup;
246 245
247 // TODO: Does actual hardware indeed keep an intermediate buffer or does 246 // TODO: Does actual hardware indeed keep an intermediate buffer or does
248 // it directly write the values? 247 // it directly write the values?
@@ -255,7 +254,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
255 (float_regs_counter >= 3 && !uniform_setup.IsFloat32())) { 254 (float_regs_counter >= 3 && !uniform_setup.IsFloat32())) {
256 float_regs_counter = 0; 255 float_regs_counter = 0;
257 256
258 auto& uniform = VertexShader::GetFloatUniform(uniform_setup.index); 257 auto& uniform = g_state.vs.uniforms.f[uniform_setup.index];
259 258
260 if (uniform_setup.index > 95) { 259 if (uniform_setup.index > 95) {
261 LOG_ERROR(HW_GPU, "Invalid VS uniform index %d", (int)uniform_setup.index); 260 LOG_ERROR(HW_GPU, "Invalid VS uniform index %d", (int)uniform_setup.index);
@@ -299,14 +298,14 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
299 if (default_attr_counter >= 3) { 298 if (default_attr_counter >= 3) {
300 default_attr_counter = 0; 299 default_attr_counter = 0;
301 300
302 auto& setup = registers.vs_default_attributes_setup; 301 auto& setup = regs.vs_default_attributes_setup;
303 302
304 if (setup.index >= 16) { 303 if (setup.index >= 16) {
305 LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index); 304 LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index);
306 break; 305 break;
307 } 306 }
308 307
309 Math::Vec4<float24>& attribute = VertexShader::GetDefaultAttribute(setup.index); 308 Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index];
310 309
311 // NOTE: The destination component order indeed is "backwards" 310 // NOTE: The destination component order indeed is "backwards"
312 attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8); 311 attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8);
@@ -334,8 +333,8 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
334 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[6], 0x2d2): 333 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[6], 0x2d2):
335 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[7], 0x2d3): 334 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[7], 0x2d3):
336 { 335 {
337 VertexShader::SubmitShaderMemoryChange(registers.vs_program.offset, value); 336 g_state.vs.program_code[regs.vs_program.offset] = value;
338 registers.vs_program.offset++; 337 regs.vs_program.offset++;
339 break; 338 break;
340 } 339 }
341 340
@@ -349,8 +348,8 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
349 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[6], 0x2dc): 348 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[6], 0x2dc):
350 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[7], 0x2dd): 349 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[7], 0x2dd):
351 { 350 {
352 VertexShader::SubmitSwizzleDataChange(registers.vs_swizzle_patterns.offset, value); 351 g_state.vs.swizzle_data[regs.vs_swizzle_patterns.offset] = value;
353 registers.vs_swizzle_patterns.offset++; 352 regs.vs_swizzle_patterns.offset++;
354 break; 353 break;
355 } 354 }
356 355
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 9da44ccd6..7987b922c 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -632,7 +632,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
632 info.width = texture_config.width; 632 info.width = texture_config.width;
633 info.height = texture_config.height; 633 info.height = texture_config.height;
634 info.stride = row_stride; 634 info.stride = row_stride;
635 info.format = registers.texture0_format; 635 info.format = g_state.regs.texture0_format;
636 Math::Vec4<u8> texture_color = LookupTexture(data, x, y, info); 636 Math::Vec4<u8> texture_color = LookupTexture(data, x, y, info);
637 buf[3 * x + y * row_stride ] = texture_color.r(); 637 buf[3 * x + y * row_stride ] = texture_color.r();
638 buf[3 * x + y * row_stride + 1] = texture_color.g(); 638 buf[3 * x + y * row_stride + 1] = texture_color.g();
diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp
new file mode 100644
index 000000000..543d9c443
--- /dev/null
+++ b/src/video_core/pica.cpp
@@ -0,0 +1,20 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <string.h>
6
7#include "pica.h"
8
9namespace Pica {
10
11State g_state;
12
13void Init() {
14}
15
16void Shutdown() {
17 memset(&g_state, 0, sizeof(State));
18}
19
20}
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 503c09eca..b67dce1a9 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -16,6 +16,8 @@
16#include "common/common_types.h" 16#include "common/common_types.h"
17#include "common/logging/log.h" 17#include "common/logging/log.h"
18 18
19#include "math.h"
20
19namespace Pica { 21namespace Pica {
20 22
21// Returns index corresponding to the Regs member labeled by field_name 23// Returns index corresponding to the Regs member labeled by field_name
@@ -356,50 +358,50 @@ struct Regs {
356 tev_stage4, tev_stage5 }; 358 tev_stage4, tev_stage5 };
357 }; 359 };
358 360
359 struct { 361 enum class BlendEquation : u32 {
360 enum CompareFunc : u32 { 362 Add = 0,
361 Never = 0, 363 Subtract = 1,
362 Always = 1, 364 ReverseSubtract = 2,
363 Equal = 2, 365 Min = 3,
364 NotEqual = 3, 366 Max = 4,
365 LessThan = 4, 367 };
366 LessThanOrEqual = 5, 368
367 GreaterThan = 6, 369 enum class BlendFactor : u32 {
368 GreaterThanOrEqual = 7, 370 Zero = 0,
369 }; 371 One = 1,
372 SourceColor = 2,
373 OneMinusSourceColor = 3,
374 DestColor = 4,
375 OneMinusDestColor = 5,
376 SourceAlpha = 6,
377 OneMinusSourceAlpha = 7,
378 DestAlpha = 8,
379 OneMinusDestAlpha = 9,
380 ConstantColor = 10,
381 OneMinusConstantColor = 11,
382 ConstantAlpha = 12,
383 OneMinusConstantAlpha = 13,
384 SourceAlphaSaturate = 14,
385 };
370 386
387 enum class CompareFunc : u32 {
388 Never = 0,
389 Always = 1,
390 Equal = 2,
391 NotEqual = 3,
392 LessThan = 4,
393 LessThanOrEqual = 5,
394 GreaterThan = 6,
395 GreaterThanOrEqual = 7,
396 };
397
398 struct {
371 union { 399 union {
372 // If false, logic blending is used 400 // If false, logic blending is used
373 BitField<8, 1, u32> alphablend_enable; 401 BitField<8, 1, u32> alphablend_enable;
374 }; 402 };
375 403
376 union { 404 union {
377 enum class BlendEquation : u32 {
378 Add = 0,
379 Subtract = 1,
380 ReverseSubtract = 2,
381 Min = 3,
382 Max = 4
383 };
384
385 enum BlendFactor : u32 {
386 Zero = 0,
387 One = 1,
388 SourceColor = 2,
389 OneMinusSourceColor = 3,
390 DestColor = 4,
391 OneMinusDestColor = 5,
392 SourceAlpha = 6,
393 OneMinusSourceAlpha = 7,
394 DestAlpha = 8,
395 OneMinusDestAlpha = 9,
396 ConstantColor = 10,
397 OneMinusConstantColor = 11,
398 ConstantAlpha = 12,
399 OneMinusConstantAlpha = 13,
400 SourceAlphaSaturate = 14
401 };
402
403 BitField< 0, 8, BlendEquation> blend_equation_rgb; 405 BitField< 0, 8, BlendEquation> blend_equation_rgb;
404 BitField< 8, 8, BlendEquation> blend_equation_a; 406 BitField< 8, 8, BlendEquation> blend_equation_a;
405 407
@@ -454,49 +456,19 @@ struct Regs {
454 INSERT_PADDING_WORDS(0x8); 456 INSERT_PADDING_WORDS(0x8);
455 } output_merger; 457 } output_merger;
456 458
457 enum DepthFormat : u32 { 459 // Components are laid out in reverse byte order, most significant bits first.
458 D16 = 0, 460 enum class ColorFormat : u32 {
459 461 RGBA8 = 0,
460 D24 = 2, 462 RGB8 = 1,
461 D24S8 = 3 463 RGB5A1 = 2,
464 RGB565 = 3,
465 RGBA4 = 4,
462 }; 466 };
463 467
464 // Returns the number of bytes in the specified depth format 468 enum class DepthFormat : u32 {
465 static u32 BytesPerDepthPixel(DepthFormat format) { 469 D16 = 0,
466 switch (format) { 470 D24 = 2,
467 case DepthFormat::D16: 471 D24S8 = 3,
468 return 2;
469 case DepthFormat::D24:
470 return 3;
471 case DepthFormat::D24S8:
472 return 4;
473 default:
474 LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
475 UNIMPLEMENTED();
476 }
477 }
478
479 // Returns the number of bits per depth component of the specified depth format
480 static u32 DepthBitsPerPixel(DepthFormat format) {
481 switch (format) {
482 case DepthFormat::D16:
483 return 16;
484 case DepthFormat::D24:
485 case DepthFormat::D24S8:
486 return 24;
487 default:
488 LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
489 UNIMPLEMENTED();
490 }
491 }
492
493 // Components are laid out in reverse byte order, most significant bits first.
494 enum ColorFormat : u32 {
495 RGBA8 = 0,
496 RGB8 = 1,
497 RGB5A1 = 2,
498 RGB565 = 3,
499 RGBA4 = 4,
500 }; 472 };
501 473
502 // Returns the number of bytes in the specified color format 474 // Returns the number of bytes in the specified color format
@@ -554,6 +526,35 @@ struct Regs {
554 } 526 }
555 } framebuffer; 527 } framebuffer;
556 528
529 // Returns the number of bytes in the specified depth format
530 static u32 BytesPerDepthPixel(DepthFormat format) {
531 switch (format) {
532 case DepthFormat::D16:
533 return 2;
534 case DepthFormat::D24:
535 return 3;
536 case DepthFormat::D24S8:
537 return 4;
538 default:
539 LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
540 UNIMPLEMENTED();
541 }
542 }
543
544 // Returns the number of bits per depth component of the specified depth format
545 static u32 DepthBitsPerPixel(DepthFormat format) {
546 switch (format) {
547 case DepthFormat::D16:
548 return 16;
549 case DepthFormat::D24:
550 case DepthFormat::D24S8:
551 return 24;
552 default:
553 LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
554 UNIMPLEMENTED();
555 }
556 }
557
557 INSERT_PADDING_WORDS(0xe0); 558 INSERT_PADDING_WORDS(0xe0);
558 559
559 enum class VertexAttributeFormat : u64 { 560 enum class VertexAttributeFormat : u64 {
@@ -953,9 +954,6 @@ ASSERT_REG_POSITION(vs_swizzle_patterns, 0x2d5);
953static_assert(sizeof(Regs) <= 0x300 * sizeof(u32), "Register set structure larger than it should be"); 954static_assert(sizeof(Regs) <= 0x300 * sizeof(u32), "Register set structure larger than it should be");
954static_assert(sizeof(Regs) >= 0x300 * sizeof(u32), "Register set structure smaller than it should be"); 955static_assert(sizeof(Regs) >= 0x300 * sizeof(u32), "Register set structure smaller than it should be");
955 956
956extern Regs registers; // TODO: Not sure if we want to have one global instance for this
957
958
959struct float24 { 957struct float24 {
960 static float24 FromFloat32(float val) { 958 static float24 FromFloat32(float val) {
961 float24 ret; 959 float24 ret;
@@ -1066,4 +1064,30 @@ union CommandHeader {
1066 BitField<31, 1, u32> group_commands; 1064 BitField<31, 1, u32> group_commands;
1067}; 1065};
1068 1066
1067/// Struct used to describe current Pica state
1068struct State {
1069 Regs regs;
1070
1071 struct {
1072 struct {
1073 Math::Vec4<float24> f[96];
1074 std::array<bool, 16> b;
1075 std::array<Math::Vec4<u8>, 4> i;
1076 } uniforms;
1077
1078 Math::Vec4<float24> default_attributes[16];
1079
1080 std::array<u32, 1024> program_code;
1081 std::array<u32, 1024> swizzle_data;
1082 } vs;
1083};
1084
1085/// Initialize Pica state
1086void Init();
1087
1088/// Shutdown Pica state
1089void Shutdown();
1090
1091extern State g_state; ///< Current Pica state
1092
1069} // namespace 1093} // namespace
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 362efe52e..767ff4205 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -24,72 +24,74 @@ namespace Pica {
24namespace Rasterizer { 24namespace Rasterizer {
25 25
26static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { 26static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
27 const PAddr addr = registers.framebuffer.GetColorBufferPhysicalAddress(); 27 const auto& framebuffer = g_state.regs.framebuffer;
28 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
28 29
29 // Similarly to textures, the render framebuffer is laid out from bottom to top, too. 30 // Similarly to textures, the render framebuffer is laid out from bottom to top, too.
30 // NOTE: The framebuffer height register contains the actual FB height minus one. 31 // NOTE: The framebuffer height register contains the actual FB height minus one.
31 y = (registers.framebuffer.height - y); 32 y = framebuffer.height - y;
32 33
33 const u32 coarse_y = y & ~7; 34 const u32 coarse_y = y & ~7;
34 u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(registers.framebuffer.color_format.Value())); 35 u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value()));
35 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * registers.framebuffer.width * bytes_per_pixel; 36 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * framebuffer.width * bytes_per_pixel;
36 u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset; 37 u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset;
37 38
38 switch (registers.framebuffer.color_format) { 39 switch (framebuffer.color_format) {
39 case Pica::Regs::ColorFormat::RGBA8: 40 case Regs::ColorFormat::RGBA8:
40 Color::EncodeRGBA8(color, dst_pixel); 41 Color::EncodeRGBA8(color, dst_pixel);
41 break; 42 break;
42 43
43 case Pica::Regs::ColorFormat::RGB8: 44 case Regs::ColorFormat::RGB8:
44 Color::EncodeRGB8(color, dst_pixel); 45 Color::EncodeRGB8(color, dst_pixel);
45 break; 46 break;
46 47
47 case Pica::Regs::ColorFormat::RGB5A1: 48 case Regs::ColorFormat::RGB5A1:
48 Color::EncodeRGB5A1(color, dst_pixel); 49 Color::EncodeRGB5A1(color, dst_pixel);
49 break; 50 break;
50 51
51 case Pica::Regs::ColorFormat::RGB565: 52 case Regs::ColorFormat::RGB565:
52 Color::EncodeRGB565(color, dst_pixel); 53 Color::EncodeRGB565(color, dst_pixel);
53 break; 54 break;
54 55
55 case Pica::Regs::ColorFormat::RGBA4: 56 case Regs::ColorFormat::RGBA4:
56 Color::EncodeRGBA4(color, dst_pixel); 57 Color::EncodeRGBA4(color, dst_pixel);
57 break; 58 break;
58 59
59 default: 60 default:
60 LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", registers.framebuffer.color_format.Value()); 61 LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", framebuffer.color_format.Value());
61 UNIMPLEMENTED(); 62 UNIMPLEMENTED();
62 } 63 }
63} 64}
64 65
65static const Math::Vec4<u8> GetPixel(int x, int y) { 66static const Math::Vec4<u8> GetPixel(int x, int y) {
66 const PAddr addr = registers.framebuffer.GetColorBufferPhysicalAddress(); 67 const auto& framebuffer = g_state.regs.framebuffer;
68 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
67 69
68 y = (registers.framebuffer.height - y); 70 y = framebuffer.height - y;
69 71
70 const u32 coarse_y = y & ~7; 72 const u32 coarse_y = y & ~7;
71 u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(registers.framebuffer.color_format.Value())); 73 u32 bytes_per_pixel = GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value()));
72 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * registers.framebuffer.width * bytes_per_pixel; 74 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * framebuffer.width * bytes_per_pixel;
73 u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset; 75 u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset;
74 76
75 switch (registers.framebuffer.color_format) { 77 switch (framebuffer.color_format) {
76 case Pica::Regs::ColorFormat::RGBA8: 78 case Regs::ColorFormat::RGBA8:
77 return Color::DecodeRGBA8(src_pixel); 79 return Color::DecodeRGBA8(src_pixel);
78 80
79 case Pica::Regs::ColorFormat::RGB8: 81 case Regs::ColorFormat::RGB8:
80 return Color::DecodeRGB8(src_pixel); 82 return Color::DecodeRGB8(src_pixel);
81 83
82 case Pica::Regs::ColorFormat::RGB5A1: 84 case Regs::ColorFormat::RGB5A1:
83 return Color::DecodeRGB5A1(src_pixel); 85 return Color::DecodeRGB5A1(src_pixel);
84 86
85 case Pica::Regs::ColorFormat::RGB565: 87 case Regs::ColorFormat::RGB565:
86 return Color::DecodeRGB565(src_pixel); 88 return Color::DecodeRGB565(src_pixel);
87 89
88 case Pica::Regs::ColorFormat::RGBA4: 90 case Regs::ColorFormat::RGBA4:
89 return Color::DecodeRGBA4(src_pixel); 91 return Color::DecodeRGBA4(src_pixel);
90 92
91 default: 93 default:
92 LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", registers.framebuffer.color_format.Value()); 94 LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", framebuffer.color_format.Value());
93 UNIMPLEMENTED(); 95 UNIMPLEMENTED();
94 } 96 }
95 97
@@ -97,58 +99,60 @@ static const Math::Vec4<u8> GetPixel(int x, int y) {
97} 99}
98 100
99static u32 GetDepth(int x, int y) { 101static u32 GetDepth(int x, int y) {
100 const PAddr addr = registers.framebuffer.GetDepthBufferPhysicalAddress(); 102 const auto& framebuffer = g_state.regs.framebuffer;
103 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
101 u8* depth_buffer = Memory::GetPhysicalPointer(addr); 104 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
102 105
103 y = (registers.framebuffer.height - y); 106 y = framebuffer.height - y;
104 107
105 const u32 coarse_y = y & ~7; 108 const u32 coarse_y = y & ~7;
106 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(registers.framebuffer.depth_format); 109 u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format);
107 u32 stride = registers.framebuffer.width * bytes_per_pixel; 110 u32 stride = framebuffer.width * bytes_per_pixel;
108 111
109 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; 112 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
110 u8* src_pixel = depth_buffer + src_offset; 113 u8* src_pixel = depth_buffer + src_offset;
111 114
112 switch (registers.framebuffer.depth_format) { 115 switch (framebuffer.depth_format) {
113 case Pica::Regs::DepthFormat::D16: 116 case Regs::DepthFormat::D16:
114 return Color::DecodeD16(src_pixel); 117 return Color::DecodeD16(src_pixel);
115 case Pica::Regs::DepthFormat::D24: 118 case Regs::DepthFormat::D24:
116 return Color::DecodeD24(src_pixel); 119 return Color::DecodeD24(src_pixel);
117 case Pica::Regs::DepthFormat::D24S8: 120 case Regs::DepthFormat::D24S8:
118 return Color::DecodeD24S8(src_pixel).x; 121 return Color::DecodeD24S8(src_pixel).x;
119 default: 122 default:
120 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", registers.framebuffer.depth_format); 123 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
121 UNIMPLEMENTED(); 124 UNIMPLEMENTED();
122 return 0; 125 return 0;
123 } 126 }
124} 127}
125 128
126static void SetDepth(int x, int y, u32 value) { 129static void SetDepth(int x, int y, u32 value) {
127 const PAddr addr = registers.framebuffer.GetDepthBufferPhysicalAddress(); 130 const auto& framebuffer = g_state.regs.framebuffer;
131 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
128 u8* depth_buffer = Memory::GetPhysicalPointer(addr); 132 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
129 133
130 y = (registers.framebuffer.height - y); 134 y = framebuffer.height - y;
131 135
132 const u32 coarse_y = y & ~7; 136 const u32 coarse_y = y & ~7;
133 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(registers.framebuffer.depth_format); 137 u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format);
134 u32 stride = registers.framebuffer.width * bytes_per_pixel; 138 u32 stride = framebuffer.width * bytes_per_pixel;
135 139
136 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; 140 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
137 u8* dst_pixel = depth_buffer + dst_offset; 141 u8* dst_pixel = depth_buffer + dst_offset;
138 142
139 switch (registers.framebuffer.depth_format) { 143 switch (framebuffer.depth_format) {
140 case Pica::Regs::DepthFormat::D16: 144 case Regs::DepthFormat::D16:
141 Color::EncodeD16(value, dst_pixel); 145 Color::EncodeD16(value, dst_pixel);
142 break; 146 break;
143 case Pica::Regs::DepthFormat::D24: 147 case Regs::DepthFormat::D24:
144 Color::EncodeD24(value, dst_pixel); 148 Color::EncodeD24(value, dst_pixel);
145 break; 149 break;
146 case Pica::Regs::DepthFormat::D24S8: 150 case Regs::DepthFormat::D24S8:
147 // TODO(Subv): Implement the stencil buffer 151 // TODO(Subv): Implement the stencil buffer
148 Color::EncodeD24S8(value, 0, dst_pixel); 152 Color::EncodeD24S8(value, 0, dst_pixel);
149 break; 153 break;
150 default: 154 default:
151 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", registers.framebuffer.depth_format); 155 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
152 UNIMPLEMENTED(); 156 UNIMPLEMENTED();
153 break; 157 break;
154 } 158 }
@@ -200,6 +204,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
200 const VertexShader::OutputVertex& v2, 204 const VertexShader::OutputVertex& v2,
201 bool reversed = false) 205 bool reversed = false)
202{ 206{
207 const auto& regs = g_state.regs;
203 Common::Profiling::ScopeTimer timer(rasterization_category); 208 Common::Profiling::ScopeTimer timer(rasterization_category);
204 209
205 // vertex positions in rasterizer coordinates 210 // vertex positions in rasterizer coordinates
@@ -216,14 +221,14 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
216 ScreenToRasterizerCoordinates(v1.screenpos), 221 ScreenToRasterizerCoordinates(v1.screenpos),
217 ScreenToRasterizerCoordinates(v2.screenpos) }; 222 ScreenToRasterizerCoordinates(v2.screenpos) };
218 223
219 if (registers.cull_mode == Regs::CullMode::KeepAll) { 224 if (regs.cull_mode == Regs::CullMode::KeepAll) {
220 // Make sure we always end up with a triangle wound counter-clockwise 225 // Make sure we always end up with a triangle wound counter-clockwise
221 if (!reversed && SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) { 226 if (!reversed && SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) {
222 ProcessTriangleInternal(v0, v2, v1, true); 227 ProcessTriangleInternal(v0, v2, v1, true);
223 return; 228 return;
224 } 229 }
225 } else { 230 } else {
226 if (!reversed && registers.cull_mode == Regs::CullMode::KeepClockWise) { 231 if (!reversed && regs.cull_mode == Regs::CullMode::KeepClockWise) {
227 // Reverse vertex order and use the CCW code path. 232 // Reverse vertex order and use the CCW code path.
228 ProcessTriangleInternal(v0, v2, v1, true); 233 ProcessTriangleInternal(v0, v2, v1, true);
229 return; 234 return;
@@ -268,8 +273,8 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
268 273
269 auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w); 274 auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w);
270 275
271 auto textures = registers.GetTextures(); 276 auto textures = regs.GetTextures();
272 auto tev_stages = registers.GetTevStages(); 277 auto tev_stages = regs.GetTevStages();
273 278
274 // Enter rasterization loop, starting at the center of the topleft bounding box corner. 279 // Enter rasterization loop, starting at the center of the topleft bounding box corner.
275 // TODO: Not sure if looping through x first might be faster 280 // TODO: Not sure if looping through x first might be faster
@@ -384,8 +389,8 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
384 // analogously. 389 // analogously.
385 Math::Vec4<u8> combiner_output; 390 Math::Vec4<u8> combiner_output;
386 Math::Vec4<u8> combiner_buffer = { 391 Math::Vec4<u8> combiner_buffer = {
387 registers.tev_combiner_buffer_color.r, registers.tev_combiner_buffer_color.g, 392 regs.tev_combiner_buffer_color.r, regs.tev_combiner_buffer_color.g,
388 registers.tev_combiner_buffer_color.b, registers.tev_combiner_buffer_color.a 393 regs.tev_combiner_buffer_color.b, regs.tev_combiner_buffer_color.a
389 }; 394 };
390 395
391 for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { 396 for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) {
@@ -609,51 +614,52 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
609 combiner_output[2] = std::min((unsigned)255, color_output.b() * tev_stage.GetColorMultiplier()); 614 combiner_output[2] = std::min((unsigned)255, color_output.b() * tev_stage.GetColorMultiplier());
610 combiner_output[3] = std::min((unsigned)255, alpha_output * tev_stage.GetAlphaMultiplier()); 615 combiner_output[3] = std::min((unsigned)255, alpha_output * tev_stage.GetAlphaMultiplier());
611 616
612 if (registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index)) { 617 if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index)) {
613 combiner_buffer.r() = combiner_output.r(); 618 combiner_buffer.r() = combiner_output.r();
614 combiner_buffer.g() = combiner_output.g(); 619 combiner_buffer.g() = combiner_output.g();
615 combiner_buffer.b() = combiner_output.b(); 620 combiner_buffer.b() = combiner_output.b();
616 } 621 }
617 622
618 if (registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)) { 623 if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)) {
619 combiner_buffer.a() = combiner_output.a(); 624 combiner_buffer.a() = combiner_output.a();
620 } 625 }
621 } 626 }
622 627
623 if (registers.output_merger.alpha_test.enable) { 628 const auto& output_merger = regs.output_merger;
629 if (output_merger.alpha_test.enable) {
624 bool pass = false; 630 bool pass = false;
625 631
626 switch (registers.output_merger.alpha_test.func) { 632 switch (output_merger.alpha_test.func) {
627 case registers.output_merger.Never: 633 case Regs::CompareFunc::Never:
628 pass = false; 634 pass = false;
629 break; 635 break;
630 636
631 case registers.output_merger.Always: 637 case Regs::CompareFunc::Always:
632 pass = true; 638 pass = true;
633 break; 639 break;
634 640
635 case registers.output_merger.Equal: 641 case Regs::CompareFunc::Equal:
636 pass = combiner_output.a() == registers.output_merger.alpha_test.ref; 642 pass = combiner_output.a() == output_merger.alpha_test.ref;
637 break; 643 break;
638 644
639 case registers.output_merger.NotEqual: 645 case Regs::CompareFunc::NotEqual:
640 pass = combiner_output.a() != registers.output_merger.alpha_test.ref; 646 pass = combiner_output.a() != output_merger.alpha_test.ref;
641 break; 647 break;
642 648
643 case registers.output_merger.LessThan: 649 case Regs::CompareFunc::LessThan:
644 pass = combiner_output.a() < registers.output_merger.alpha_test.ref; 650 pass = combiner_output.a() < output_merger.alpha_test.ref;
645 break; 651 break;
646 652
647 case registers.output_merger.LessThanOrEqual: 653 case Regs::CompareFunc::LessThanOrEqual:
648 pass = combiner_output.a() <= registers.output_merger.alpha_test.ref; 654 pass = combiner_output.a() <= output_merger.alpha_test.ref;
649 break; 655 break;
650 656
651 case registers.output_merger.GreaterThan: 657 case Regs::CompareFunc::GreaterThan:
652 pass = combiner_output.a() > registers.output_merger.alpha_test.ref; 658 pass = combiner_output.a() > output_merger.alpha_test.ref;
653 break; 659 break;
654 660
655 case registers.output_merger.GreaterThanOrEqual: 661 case Regs::CompareFunc::GreaterThanOrEqual:
656 pass = combiner_output.a() >= registers.output_merger.alpha_test.ref; 662 pass = combiner_output.a() >= output_merger.alpha_test.ref;
657 break; 663 break;
658 } 664 }
659 665
@@ -662,8 +668,8 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
662 } 668 }
663 669
664 // TODO: Does depth indeed only get written even if depth testing is enabled? 670 // TODO: Does depth indeed only get written even if depth testing is enabled?
665 if (registers.output_merger.depth_test_enable) { 671 if (output_merger.depth_test_enable) {
666 unsigned num_bits = Pica::Regs::DepthBitsPerPixel(registers.framebuffer.depth_format); 672 unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format);
667 u32 z = (u32)((v0.screenpos[2].ToFloat32() * w0 + 673 u32 z = (u32)((v0.screenpos[2].ToFloat32() * w0 +
668 v1.screenpos[2].ToFloat32() * w1 + 674 v1.screenpos[2].ToFloat32() * w1 +
669 v2.screenpos[2].ToFloat32() * w2) * ((1 << num_bits) - 1) / wsum); 675 v2.screenpos[2].ToFloat32() * w2) * ((1 << num_bits) - 1) / wsum);
@@ -671,36 +677,36 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
671 677
672 bool pass = false; 678 bool pass = false;
673 679
674 switch (registers.output_merger.depth_test_func) { 680 switch (output_merger.depth_test_func) {
675 case registers.output_merger.Never: 681 case Regs::CompareFunc::Never:
676 pass = false; 682 pass = false;
677 break; 683 break;
678 684
679 case registers.output_merger.Always: 685 case Regs::CompareFunc::Always:
680 pass = true; 686 pass = true;
681 break; 687 break;
682 688
683 case registers.output_merger.Equal: 689 case Regs::CompareFunc::Equal:
684 pass = z == ref_z; 690 pass = z == ref_z;
685 break; 691 break;
686 692
687 case registers.output_merger.NotEqual: 693 case Regs::CompareFunc::NotEqual:
688 pass = z != ref_z; 694 pass = z != ref_z;
689 break; 695 break;
690 696
691 case registers.output_merger.LessThan: 697 case Regs::CompareFunc::LessThan:
692 pass = z < ref_z; 698 pass = z < ref_z;
693 break; 699 break;
694 700
695 case registers.output_merger.LessThanOrEqual: 701 case Regs::CompareFunc::LessThanOrEqual:
696 pass = z <= ref_z; 702 pass = z <= ref_z;
697 break; 703 break;
698 704
699 case registers.output_merger.GreaterThan: 705 case Regs::CompareFunc::GreaterThan:
700 pass = z > ref_z; 706 pass = z > ref_z;
701 break; 707 break;
702 708
703 case registers.output_merger.GreaterThanOrEqual: 709 case Regs::CompareFunc::GreaterThanOrEqual:
704 pass = z >= ref_z; 710 pass = z >= ref_z;
705 break; 711 break;
706 } 712 }
@@ -708,59 +714,59 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
708 if (!pass) 714 if (!pass)
709 continue; 715 continue;
710 716
711 if (registers.output_merger.depth_write_enable) 717 if (output_merger.depth_write_enable)
712 SetDepth(x >> 4, y >> 4, z); 718 SetDepth(x >> 4, y >> 4, z);
713 } 719 }
714 720
715 auto dest = GetPixel(x >> 4, y >> 4); 721 auto dest = GetPixel(x >> 4, y >> 4);
716 Math::Vec4<u8> blend_output = combiner_output; 722 Math::Vec4<u8> blend_output = combiner_output;
717 723
718 if (registers.output_merger.alphablend_enable) { 724 if (output_merger.alphablend_enable) {
719 auto params = registers.output_merger.alpha_blending; 725 auto params = output_merger.alpha_blending;
720 726
721 auto LookupFactorRGB = [&](decltype(params)::BlendFactor factor) -> Math::Vec3<u8> { 727 auto LookupFactorRGB = [&](Regs::BlendFactor factor) -> Math::Vec3<u8> {
722 switch (factor) { 728 switch (factor) {
723 case params.Zero: 729 case Regs::BlendFactor::Zero :
724 return Math::Vec3<u8>(0, 0, 0); 730 return Math::Vec3<u8>(0, 0, 0);
725 731
726 case params.One: 732 case Regs::BlendFactor::One :
727 return Math::Vec3<u8>(255, 255, 255); 733 return Math::Vec3<u8>(255, 255, 255);
728 734
729 case params.SourceColor: 735 case Regs::BlendFactor::SourceColor:
730 return combiner_output.rgb(); 736 return combiner_output.rgb();
731 737
732 case params.OneMinusSourceColor: 738 case Regs::BlendFactor::OneMinusSourceColor:
733 return Math::Vec3<u8>(255 - combiner_output.r(), 255 - combiner_output.g(), 255 - combiner_output.b()); 739 return Math::Vec3<u8>(255 - combiner_output.r(), 255 - combiner_output.g(), 255 - combiner_output.b());
734 740
735 case params.DestColor: 741 case Regs::BlendFactor::DestColor:
736 return dest.rgb(); 742 return dest.rgb();
737 743
738 case params.OneMinusDestColor: 744 case Regs::BlendFactor::OneMinusDestColor:
739 return Math::Vec3<u8>(255 - dest.r(), 255 - dest.g(), 255 - dest.b()); 745 return Math::Vec3<u8>(255 - dest.r(), 255 - dest.g(), 255 - dest.b());
740 746
741 case params.SourceAlpha: 747 case Regs::BlendFactor::SourceAlpha:
742 return Math::Vec3<u8>(combiner_output.a(), combiner_output.a(), combiner_output.a()); 748 return Math::Vec3<u8>(combiner_output.a(), combiner_output.a(), combiner_output.a());
743 749
744 case params.OneMinusSourceAlpha: 750 case Regs::BlendFactor::OneMinusSourceAlpha:
745 return Math::Vec3<u8>(255 - combiner_output.a(), 255 - combiner_output.a(), 255 - combiner_output.a()); 751 return Math::Vec3<u8>(255 - combiner_output.a(), 255 - combiner_output.a(), 255 - combiner_output.a());
746 752
747 case params.DestAlpha: 753 case Regs::BlendFactor::DestAlpha:
748 return Math::Vec3<u8>(dest.a(), dest.a(), dest.a()); 754 return Math::Vec3<u8>(dest.a(), dest.a(), dest.a());
749 755
750 case params.OneMinusDestAlpha: 756 case Regs::BlendFactor::OneMinusDestAlpha:
751 return Math::Vec3<u8>(255 - dest.a(), 255 - dest.a(), 255 - dest.a()); 757 return Math::Vec3<u8>(255 - dest.a(), 255 - dest.a(), 255 - dest.a());
752 758
753 case params.ConstantColor: 759 case Regs::BlendFactor::ConstantColor:
754 return Math::Vec3<u8>(registers.output_merger.blend_const.r, registers.output_merger.blend_const.g, registers.output_merger.blend_const.b); 760 return Math::Vec3<u8>(output_merger.blend_const.r, output_merger.blend_const.g, output_merger.blend_const.b);
755 761
756 case params.OneMinusConstantColor: 762 case Regs::BlendFactor::OneMinusConstantColor:
757 return Math::Vec3<u8>(255 - registers.output_merger.blend_const.r, 255 - registers.output_merger.blend_const.g, 255 - registers.output_merger.blend_const.b); 763 return Math::Vec3<u8>(255 - output_merger.blend_const.r, 255 - output_merger.blend_const.g, 255 - output_merger.blend_const.b);
758 764
759 case params.ConstantAlpha: 765 case Regs::BlendFactor::ConstantAlpha:
760 return Math::Vec3<u8>(registers.output_merger.blend_const.a, registers.output_merger.blend_const.a, registers.output_merger.blend_const.a); 766 return Math::Vec3<u8>(output_merger.blend_const.a, output_merger.blend_const.a, output_merger.blend_const.a);
761 767
762 case params.OneMinusConstantAlpha: 768 case Regs::BlendFactor::OneMinusConstantAlpha:
763 return Math::Vec3<u8>(255 - registers.output_merger.blend_const.a, 255 - registers.output_merger.blend_const.a, 255 - registers.output_merger.blend_const.a); 769 return Math::Vec3<u8>(255 - output_merger.blend_const.a, 255 - output_merger.blend_const.a, 255 - output_merger.blend_const.a);
764 770
765 default: 771 default:
766 LOG_CRITICAL(HW_GPU, "Unknown color blend factor %x", factor); 772 LOG_CRITICAL(HW_GPU, "Unknown color blend factor %x", factor);
@@ -769,31 +775,31 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
769 } 775 }
770 }; 776 };
771 777
772 auto LookupFactorA = [&](decltype(params)::BlendFactor factor) -> u8 { 778 auto LookupFactorA = [&](Regs::BlendFactor factor) -> u8 {
773 switch (factor) { 779 switch (factor) {
774 case params.Zero: 780 case Regs::BlendFactor::Zero:
775 return 0; 781 return 0;
776 782
777 case params.One: 783 case Regs::BlendFactor::One:
778 return 255; 784 return 255;
779 785
780 case params.SourceAlpha: 786 case Regs::BlendFactor::SourceAlpha:
781 return combiner_output.a(); 787 return combiner_output.a();
782 788
783 case params.OneMinusSourceAlpha: 789 case Regs::BlendFactor::OneMinusSourceAlpha:
784 return 255 - combiner_output.a(); 790 return 255 - combiner_output.a();
785 791
786 case params.DestAlpha: 792 case Regs::BlendFactor::DestAlpha:
787 return dest.a(); 793 return dest.a();
788 794
789 case params.OneMinusDestAlpha: 795 case Regs::BlendFactor::OneMinusDestAlpha:
790 return 255 - dest.a(); 796 return 255 - dest.a();
791 797
792 case params.ConstantAlpha: 798 case Regs::BlendFactor::ConstantAlpha:
793 return registers.output_merger.blend_const.a; 799 return output_merger.blend_const.a;
794 800
795 case params.OneMinusConstantAlpha: 801 case Regs::BlendFactor::OneMinusConstantAlpha:
796 return 255 - registers.output_merger.blend_const.a; 802 return 255 - output_merger.blend_const.a;
797 803
798 default: 804 default:
799 LOG_CRITICAL(HW_GPU, "Unknown alpha blend factor %x", factor); 805 LOG_CRITICAL(HW_GPU, "Unknown alpha blend factor %x", factor);
@@ -802,7 +808,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
802 } 808 }
803 }; 809 };
804 810
805 using BlendEquation = decltype(params)::BlendEquation; 811 using BlendEquation = Regs::BlendEquation;
806 static auto EvaluateBlendEquation = [](const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor, 812 static auto EvaluateBlendEquation = [](const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
807 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor, 813 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
808 BlendEquation equation) { 814 BlendEquation equation) {
@@ -812,29 +818,29 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
812 auto dst_result = (dest * destfactor).Cast<int>(); 818 auto dst_result = (dest * destfactor).Cast<int>();
813 819
814 switch (equation) { 820 switch (equation) {
815 case BlendEquation::Add: 821 case Regs::BlendEquation::Add:
816 result = (src_result + dst_result) / 255; 822 result = (src_result + dst_result) / 255;
817 break; 823 break;
818 824
819 case BlendEquation::Subtract: 825 case Regs::BlendEquation::Subtract:
820 result = (src_result - dst_result) / 255; 826 result = (src_result - dst_result) / 255;
821 break; 827 break;
822 828
823 case BlendEquation::ReverseSubtract: 829 case Regs::BlendEquation::ReverseSubtract:
824 result = (dst_result - src_result) / 255; 830 result = (dst_result - src_result) / 255;
825 break; 831 break;
826 832
827 // TODO: How do these two actually work? 833 // TODO: How do these two actually work?
828 // OpenGL doesn't include the blend factors in the min/max computations, 834 // OpenGL doesn't include the blend factors in the min/max computations,
829 // but is this what the 3DS actually does? 835 // but is this what the 3DS actually does?
830 case BlendEquation::Min: 836 case Regs::BlendEquation::Min:
831 result.r() = std::min(src.r(), dest.r()); 837 result.r() = std::min(src.r(), dest.r());
832 result.g() = std::min(src.g(), dest.g()); 838 result.g() = std::min(src.g(), dest.g());
833 result.b() = std::min(src.b(), dest.b()); 839 result.b() = std::min(src.b(), dest.b());
834 result.a() = std::min(src.a(), dest.a()); 840 result.a() = std::min(src.a(), dest.a());
835 break; 841 break;
836 842
837 case BlendEquation::Max: 843 case Regs::BlendEquation::Max:
838 result.r() = std::max(src.r(), dest.r()); 844 result.r() = std::max(src.r(), dest.r());
839 result.g() = std::max(src.g(), dest.g()); 845 result.g() = std::max(src.g(), dest.g());
840 result.b() = std::max(src.b(), dest.b()); 846 result.b() = std::max(src.b(), dest.b());
@@ -860,15 +866,15 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
860 blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb); 866 blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb);
861 blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a(); 867 blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a();
862 } else { 868 } else {
863 LOG_CRITICAL(HW_GPU, "logic op: %x", registers.output_merger.logic_op); 869 LOG_CRITICAL(HW_GPU, "logic op: %x", output_merger.logic_op);
864 UNIMPLEMENTED(); 870 UNIMPLEMENTED();
865 } 871 }
866 872
867 const Math::Vec4<u8> result = { 873 const Math::Vec4<u8> result = {
868 registers.output_merger.red_enable ? blend_output.r() : dest.r(), 874 output_merger.red_enable ? blend_output.r() : dest.r(),
869 registers.output_merger.green_enable ? blend_output.g() : dest.g(), 875 output_merger.green_enable ? blend_output.g() : dest.g(),
870 registers.output_merger.blue_enable ? blend_output.b() : dest.b(), 876 output_merger.blue_enable ? blend_output.b() : dest.b(),
871 registers.output_merger.alpha_enable ? blend_output.a() : dest.a() 877 output_merger.alpha_enable ? blend_output.a() : dest.a()
872 }; 878 };
873 879
874 DrawPixel(x >> 4, y >> 4, result); 880 DrawPixel(x >> 4, y >> 4, result);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index e44375547..4b7d099a5 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -46,7 +46,7 @@ void RasterizerOpenGL::InitObjects() {
46 46
47 uniform_tev_combiner_buffer_color = glGetUniformLocation(shader.handle, "tev_combiner_buffer_color"); 47 uniform_tev_combiner_buffer_color = glGetUniformLocation(shader.handle, "tev_combiner_buffer_color");
48 48
49 const auto tev_stages = Pica::registers.GetTevStages(); 49 const auto tev_stages = Pica::g_state.regs.GetTevStages();
50 for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { 50 for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) {
51 auto& uniform_tev_cfg = uniform_tev_cfgs[tev_stage_index]; 51 auto& uniform_tev_cfg = uniform_tev_cfgs[tev_stage_index];
52 52
@@ -128,6 +128,8 @@ void RasterizerOpenGL::InitObjects() {
128} 128}
129 129
130void RasterizerOpenGL::Reset() { 130void RasterizerOpenGL::Reset() {
131 const auto& regs = Pica::g_state.regs;
132
131 SyncCullMode(); 133 SyncCullMode();
132 SyncBlendEnabled(); 134 SyncBlendEnabled();
133 SyncBlendFuncs(); 135 SyncBlendFuncs();
@@ -137,46 +139,46 @@ void RasterizerOpenGL::Reset() {
137 SyncDepthTest(); 139 SyncDepthTest();
138 140
139 // TEV stage 0 141 // TEV stage 0
140 SyncTevSources(0, Pica::registers.tev_stage0); 142 SyncTevSources(0, regs.tev_stage0);
141 SyncTevModifiers(0, Pica::registers.tev_stage0); 143 SyncTevModifiers(0, regs.tev_stage0);
142 SyncTevOps(0, Pica::registers.tev_stage0); 144 SyncTevOps(0, regs.tev_stage0);
143 SyncTevColor(0, Pica::registers.tev_stage0); 145 SyncTevColor(0, regs.tev_stage0);
144 SyncTevMultipliers(0, Pica::registers.tev_stage0); 146 SyncTevMultipliers(0, regs.tev_stage0);
145 147
146 // TEV stage 1 148 // TEV stage 1
147 SyncTevSources(1, Pica::registers.tev_stage1); 149 SyncTevSources(1, regs.tev_stage1);
148 SyncTevModifiers(1, Pica::registers.tev_stage1); 150 SyncTevModifiers(1, regs.tev_stage1);
149 SyncTevOps(1, Pica::registers.tev_stage1); 151 SyncTevOps(1, regs.tev_stage1);
150 SyncTevColor(1, Pica::registers.tev_stage1); 152 SyncTevColor(1, regs.tev_stage1);
151 SyncTevMultipliers(1, Pica::registers.tev_stage1); 153 SyncTevMultipliers(1, regs.tev_stage1);
152 154
153 // TEV stage 2 155 // TEV stage 2
154 SyncTevSources(2, Pica::registers.tev_stage2); 156 SyncTevSources(2, regs.tev_stage2);
155 SyncTevModifiers(2, Pica::registers.tev_stage2); 157 SyncTevModifiers(2, regs.tev_stage2);
156 SyncTevOps(2, Pica::registers.tev_stage2); 158 SyncTevOps(2, regs.tev_stage2);
157 SyncTevColor(2, Pica::registers.tev_stage2); 159 SyncTevColor(2, regs.tev_stage2);
158 SyncTevMultipliers(2, Pica::registers.tev_stage2); 160 SyncTevMultipliers(2, regs.tev_stage2);
159 161
160 // TEV stage 3 162 // TEV stage 3
161 SyncTevSources(3, Pica::registers.tev_stage3); 163 SyncTevSources(3, regs.tev_stage3);
162 SyncTevModifiers(3, Pica::registers.tev_stage3); 164 SyncTevModifiers(3, regs.tev_stage3);
163 SyncTevOps(3, Pica::registers.tev_stage3); 165 SyncTevOps(3, regs.tev_stage3);
164 SyncTevColor(3, Pica::registers.tev_stage3); 166 SyncTevColor(3, regs.tev_stage3);
165 SyncTevMultipliers(3, Pica::registers.tev_stage3); 167 SyncTevMultipliers(3, regs.tev_stage3);
166 168
167 // TEV stage 4 169 // TEV stage 4
168 SyncTevSources(4, Pica::registers.tev_stage4); 170 SyncTevSources(4, regs.tev_stage4);
169 SyncTevModifiers(4, Pica::registers.tev_stage4); 171 SyncTevModifiers(4, regs.tev_stage4);
170 SyncTevOps(4, Pica::registers.tev_stage4); 172 SyncTevOps(4, regs.tev_stage4);
171 SyncTevColor(4, Pica::registers.tev_stage4); 173 SyncTevColor(4, regs.tev_stage4);
172 SyncTevMultipliers(4, Pica::registers.tev_stage4); 174 SyncTevMultipliers(4, regs.tev_stage4);
173 175
174 // TEV stage 5 176 // TEV stage 5
175 SyncTevSources(5, Pica::registers.tev_stage5); 177 SyncTevSources(5, regs.tev_stage5);
176 SyncTevModifiers(5, Pica::registers.tev_stage5); 178 SyncTevModifiers(5, regs.tev_stage5);
177 SyncTevOps(5, Pica::registers.tev_stage5); 179 SyncTevOps(5, regs.tev_stage5);
178 SyncTevColor(5, Pica::registers.tev_stage5); 180 SyncTevColor(5, regs.tev_stage5);
179 SyncTevMultipliers(5, Pica::registers.tev_stage5); 181 SyncTevMultipliers(5, regs.tev_stage5);
180 182
181 SyncCombinerColor(); 183 SyncCombinerColor();
182 SyncCombinerWriteFlags(); 184 SyncCombinerWriteFlags();
@@ -210,6 +212,8 @@ void RasterizerOpenGL::CommitFramebuffer() {
210} 212}
211 213
212void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { 214void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
215 const auto& regs = Pica::g_state.regs;
216
213 if (!Settings::values.use_hw_renderer) 217 if (!Settings::values.use_hw_renderer)
214 return; 218 return;
215 219
@@ -247,104 +251,104 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
247 251
248 // TEV stage 0 252 // TEV stage 0
249 case PICA_REG_INDEX(tev_stage0.color_source1): 253 case PICA_REG_INDEX(tev_stage0.color_source1):
250 SyncTevSources(0, Pica::registers.tev_stage0); 254 SyncTevSources(0, regs.tev_stage0);
251 break; 255 break;
252 case PICA_REG_INDEX(tev_stage0.color_modifier1): 256 case PICA_REG_INDEX(tev_stage0.color_modifier1):
253 SyncTevModifiers(0, Pica::registers.tev_stage0); 257 SyncTevModifiers(0, regs.tev_stage0);
254 break; 258 break;
255 case PICA_REG_INDEX(tev_stage0.color_op): 259 case PICA_REG_INDEX(tev_stage0.color_op):
256 SyncTevOps(0, Pica::registers.tev_stage0); 260 SyncTevOps(0, regs.tev_stage0);
257 break; 261 break;
258 case PICA_REG_INDEX(tev_stage0.const_r): 262 case PICA_REG_INDEX(tev_stage0.const_r):
259 SyncTevColor(0, Pica::registers.tev_stage0); 263 SyncTevColor(0, regs.tev_stage0);
260 break; 264 break;
261 case PICA_REG_INDEX(tev_stage0.color_scale): 265 case PICA_REG_INDEX(tev_stage0.color_scale):
262 SyncTevMultipliers(0, Pica::registers.tev_stage0); 266 SyncTevMultipliers(0, regs.tev_stage0);
263 break; 267 break;
264 268
265 // TEV stage 1 269 // TEV stage 1
266 case PICA_REG_INDEX(tev_stage1.color_source1): 270 case PICA_REG_INDEX(tev_stage1.color_source1):
267 SyncTevSources(1, Pica::registers.tev_stage1); 271 SyncTevSources(1, regs.tev_stage1);
268 break; 272 break;
269 case PICA_REG_INDEX(tev_stage1.color_modifier1): 273 case PICA_REG_INDEX(tev_stage1.color_modifier1):
270 SyncTevModifiers(1, Pica::registers.tev_stage1); 274 SyncTevModifiers(1, regs.tev_stage1);
271 break; 275 break;
272 case PICA_REG_INDEX(tev_stage1.color_op): 276 case PICA_REG_INDEX(tev_stage1.color_op):
273 SyncTevOps(1, Pica::registers.tev_stage1); 277 SyncTevOps(1, regs.tev_stage1);
274 break; 278 break;
275 case PICA_REG_INDEX(tev_stage1.const_r): 279 case PICA_REG_INDEX(tev_stage1.const_r):
276 SyncTevColor(1, Pica::registers.tev_stage1); 280 SyncTevColor(1, regs.tev_stage1);
277 break; 281 break;
278 case PICA_REG_INDEX(tev_stage1.color_scale): 282 case PICA_REG_INDEX(tev_stage1.color_scale):
279 SyncTevMultipliers(1, Pica::registers.tev_stage1); 283 SyncTevMultipliers(1, regs.tev_stage1);
280 break; 284 break;
281 285
282 // TEV stage 2 286 // TEV stage 2
283 case PICA_REG_INDEX(tev_stage2.color_source1): 287 case PICA_REG_INDEX(tev_stage2.color_source1):
284 SyncTevSources(2, Pica::registers.tev_stage2); 288 SyncTevSources(2, regs.tev_stage2);
285 break; 289 break;
286 case PICA_REG_INDEX(tev_stage2.color_modifier1): 290 case PICA_REG_INDEX(tev_stage2.color_modifier1):
287 SyncTevModifiers(2, Pica::registers.tev_stage2); 291 SyncTevModifiers(2, regs.tev_stage2);
288 break; 292 break;
289 case PICA_REG_INDEX(tev_stage2.color_op): 293 case PICA_REG_INDEX(tev_stage2.color_op):
290 SyncTevOps(2, Pica::registers.tev_stage2); 294 SyncTevOps(2, regs.tev_stage2);
291 break; 295 break;
292 case PICA_REG_INDEX(tev_stage2.const_r): 296 case PICA_REG_INDEX(tev_stage2.const_r):
293 SyncTevColor(2, Pica::registers.tev_stage2); 297 SyncTevColor(2, regs.tev_stage2);
294 break; 298 break;
295 case PICA_REG_INDEX(tev_stage2.color_scale): 299 case PICA_REG_INDEX(tev_stage2.color_scale):
296 SyncTevMultipliers(2, Pica::registers.tev_stage2); 300 SyncTevMultipliers(2, regs.tev_stage2);
297 break; 301 break;
298 302
299 // TEV stage 3 303 // TEV stage 3
300 case PICA_REG_INDEX(tev_stage3.color_source1): 304 case PICA_REG_INDEX(tev_stage3.color_source1):
301 SyncTevSources(3, Pica::registers.tev_stage3); 305 SyncTevSources(3, regs.tev_stage3);
302 break; 306 break;
303 case PICA_REG_INDEX(tev_stage3.color_modifier1): 307 case PICA_REG_INDEX(tev_stage3.color_modifier1):
304 SyncTevModifiers(3, Pica::registers.tev_stage3); 308 SyncTevModifiers(3, regs.tev_stage3);
305 break; 309 break;
306 case PICA_REG_INDEX(tev_stage3.color_op): 310 case PICA_REG_INDEX(tev_stage3.color_op):
307 SyncTevOps(3, Pica::registers.tev_stage3); 311 SyncTevOps(3, regs.tev_stage3);
308 break; 312 break;
309 case PICA_REG_INDEX(tev_stage3.const_r): 313 case PICA_REG_INDEX(tev_stage3.const_r):
310 SyncTevColor(3, Pica::registers.tev_stage3); 314 SyncTevColor(3, regs.tev_stage3);
311 break; 315 break;
312 case PICA_REG_INDEX(tev_stage3.color_scale): 316 case PICA_REG_INDEX(tev_stage3.color_scale):
313 SyncTevMultipliers(3, Pica::registers.tev_stage3); 317 SyncTevMultipliers(3, regs.tev_stage3);
314 break; 318 break;
315 319
316 // TEV stage 4 320 // TEV stage 4
317 case PICA_REG_INDEX(tev_stage4.color_source1): 321 case PICA_REG_INDEX(tev_stage4.color_source1):
318 SyncTevSources(4, Pica::registers.tev_stage4); 322 SyncTevSources(4, regs.tev_stage4);
319 break; 323 break;
320 case PICA_REG_INDEX(tev_stage4.color_modifier1): 324 case PICA_REG_INDEX(tev_stage4.color_modifier1):
321 SyncTevModifiers(4, Pica::registers.tev_stage4); 325 SyncTevModifiers(4, regs.tev_stage4);
322 break; 326 break;
323 case PICA_REG_INDEX(tev_stage4.color_op): 327 case PICA_REG_INDEX(tev_stage4.color_op):
324 SyncTevOps(4, Pica::registers.tev_stage4); 328 SyncTevOps(4, regs.tev_stage4);
325 break; 329 break;
326 case PICA_REG_INDEX(tev_stage4.const_r): 330 case PICA_REG_INDEX(tev_stage4.const_r):
327 SyncTevColor(4, Pica::registers.tev_stage4); 331 SyncTevColor(4, regs.tev_stage4);
328 break; 332 break;
329 case PICA_REG_INDEX(tev_stage4.color_scale): 333 case PICA_REG_INDEX(tev_stage4.color_scale):
330 SyncTevMultipliers(4, Pica::registers.tev_stage4); 334 SyncTevMultipliers(4, regs.tev_stage4);
331 break; 335 break;
332 336
333 // TEV stage 5 337 // TEV stage 5
334 case PICA_REG_INDEX(tev_stage5.color_source1): 338 case PICA_REG_INDEX(tev_stage5.color_source1):
335 SyncTevSources(5, Pica::registers.tev_stage5); 339 SyncTevSources(5, regs.tev_stage5);
336 break; 340 break;
337 case PICA_REG_INDEX(tev_stage5.color_modifier1): 341 case PICA_REG_INDEX(tev_stage5.color_modifier1):
338 SyncTevModifiers(5, Pica::registers.tev_stage5); 342 SyncTevModifiers(5, regs.tev_stage5);
339 break; 343 break;
340 case PICA_REG_INDEX(tev_stage5.color_op): 344 case PICA_REG_INDEX(tev_stage5.color_op):
341 SyncTevOps(5, Pica::registers.tev_stage5); 345 SyncTevOps(5, regs.tev_stage5);
342 break; 346 break;
343 case PICA_REG_INDEX(tev_stage5.const_r): 347 case PICA_REG_INDEX(tev_stage5.const_r):
344 SyncTevColor(5, Pica::registers.tev_stage5); 348 SyncTevColor(5, regs.tev_stage5);
345 break; 349 break;
346 case PICA_REG_INDEX(tev_stage5.color_scale): 350 case PICA_REG_INDEX(tev_stage5.color_scale):
347 SyncTevMultipliers(5, Pica::registers.tev_stage5); 351 SyncTevMultipliers(5, regs.tev_stage5);
348 break; 352 break;
349 353
350 // TEV combiner buffer color 354 // TEV combiner buffer color
@@ -360,16 +364,18 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
360} 364}
361 365
362void RasterizerOpenGL::NotifyPreRead(PAddr addr, u32 size) { 366void RasterizerOpenGL::NotifyPreRead(PAddr addr, u32 size) {
367 const auto& regs = Pica::g_state.regs;
368
363 if (!Settings::values.use_hw_renderer) 369 if (!Settings::values.use_hw_renderer)
364 return; 370 return;
365 371
366 PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); 372 PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress();
367 u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(Pica::registers.framebuffer.color_format) 373 u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format)
368 * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); 374 * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
369 375
370 PAddr cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress(); 376 PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress();
371 u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(Pica::registers.framebuffer.depth_format) 377 u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(regs.framebuffer.depth_format)
372 * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); 378 * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
373 379
374 // If source memory region overlaps 3DS framebuffers, commit them before the copy happens 380 // If source memory region overlaps 3DS framebuffers, commit them before the copy happens
375 if (MathUtil::IntervalsIntersect(addr, size, cur_fb_color_addr, cur_fb_color_size)) 381 if (MathUtil::IntervalsIntersect(addr, size, cur_fb_color_addr, cur_fb_color_size))
@@ -380,16 +386,18 @@ void RasterizerOpenGL::NotifyPreRead(PAddr addr, u32 size) {
380} 386}
381 387
382void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) { 388void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) {
389 const auto& regs = Pica::g_state.regs;
390
383 if (!Settings::values.use_hw_renderer) 391 if (!Settings::values.use_hw_renderer)
384 return; 392 return;
385 393
386 PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); 394 PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress();
387 u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(Pica::registers.framebuffer.color_format) 395 u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format)
388 * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); 396 * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
389 397
390 PAddr cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress(); 398 PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress();
391 u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(Pica::registers.framebuffer.depth_format) 399 u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(regs.framebuffer.depth_format)
392 * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); 400 * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
393 401
394 // If modified memory region overlaps 3DS framebuffers, reload their contents into OpenGL 402 // If modified memory region overlaps 3DS framebuffers, reload their contents into OpenGL
395 if (MathUtil::IntervalsIntersect(addr, size, cur_fb_color_addr, cur_fb_color_size)) 403 if (MathUtil::IntervalsIntersect(addr, size, cur_fb_color_addr, cur_fb_color_size))
@@ -501,14 +509,16 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::
501} 509}
502 510
503void RasterizerOpenGL::SyncFramebuffer() { 511void RasterizerOpenGL::SyncFramebuffer() {
504 PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); 512 const auto& regs = Pica::g_state.regs;
505 Pica::Regs::ColorFormat new_fb_color_format = Pica::registers.framebuffer.color_format;
506 513
507 PAddr cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress(); 514 PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress();
508 Pica::Regs::DepthFormat new_fb_depth_format = Pica::registers.framebuffer.depth_format; 515 Pica::Regs::ColorFormat new_fb_color_format = regs.framebuffer.color_format;
509 516
510 bool fb_size_changed = fb_color_texture.width != Pica::registers.framebuffer.GetWidth() || 517 PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress();
511 fb_color_texture.height != Pica::registers.framebuffer.GetHeight(); 518 Pica::Regs::DepthFormat new_fb_depth_format = regs.framebuffer.depth_format;
519
520 bool fb_size_changed = fb_color_texture.width != regs.framebuffer.GetWidth() ||
521 fb_color_texture.height != regs.framebuffer.GetHeight();
512 522
513 bool color_fb_prop_changed = fb_color_texture.format != new_fb_color_format || 523 bool color_fb_prop_changed = fb_color_texture.format != new_fb_color_format ||
514 fb_size_changed; 524 fb_size_changed;
@@ -532,12 +542,12 @@ void RasterizerOpenGL::SyncFramebuffer() {
532 // Reconfigure framebuffer textures if any property has changed 542 // Reconfigure framebuffer textures if any property has changed
533 if (color_fb_prop_changed) { 543 if (color_fb_prop_changed) {
534 ReconfigureColorTexture(fb_color_texture, new_fb_color_format, 544 ReconfigureColorTexture(fb_color_texture, new_fb_color_format,
535 Pica::registers.framebuffer.GetWidth(), Pica::registers.framebuffer.GetHeight()); 545 regs.framebuffer.GetWidth(), regs.framebuffer.GetHeight());
536 } 546 }
537 547
538 if (depth_fb_prop_changed) { 548 if (depth_fb_prop_changed) {
539 ReconfigureDepthTexture(fb_depth_texture, new_fb_depth_format, 549 ReconfigureDepthTexture(fb_depth_texture, new_fb_depth_format,
540 Pica::registers.framebuffer.GetWidth(), Pica::registers.framebuffer.GetHeight()); 550 regs.framebuffer.GetWidth(), regs.framebuffer.GetHeight());
541 551
542 // Only attach depth buffer as stencil if it supports stencil 552 // Only attach depth buffer as stencil if it supports stencil
543 switch (new_fb_depth_format) { 553 switch (new_fb_depth_format) {
@@ -572,7 +582,9 @@ void RasterizerOpenGL::SyncFramebuffer() {
572} 582}
573 583
574void RasterizerOpenGL::SyncCullMode() { 584void RasterizerOpenGL::SyncCullMode() {
575 switch (Pica::registers.cull_mode) { 585 const auto& regs = Pica::g_state.regs;
586
587 switch (regs.cull_mode) {
576 case Pica::Regs::CullMode::KeepAll: 588 case Pica::Regs::CullMode::KeepAll:
577 state.cull.enabled = false; 589 state.cull.enabled = false;
578 break; 590 break;
@@ -588,25 +600,26 @@ void RasterizerOpenGL::SyncCullMode() {
588 break; 600 break;
589 601
590 default: 602 default:
591 LOG_CRITICAL(Render_OpenGL, "Unknown cull mode %d", Pica::registers.cull_mode.Value()); 603 LOG_CRITICAL(Render_OpenGL, "Unknown cull mode %d", regs.cull_mode.Value());
592 UNIMPLEMENTED(); 604 UNIMPLEMENTED();
593 break; 605 break;
594 } 606 }
595} 607}
596 608
597void RasterizerOpenGL::SyncBlendEnabled() { 609void RasterizerOpenGL::SyncBlendEnabled() {
598 state.blend.enabled = Pica::registers.output_merger.alphablend_enable; 610 state.blend.enabled = (Pica::g_state.regs.output_merger.alphablend_enable == 1);
599} 611}
600 612
601void RasterizerOpenGL::SyncBlendFuncs() { 613void RasterizerOpenGL::SyncBlendFuncs() {
602 state.blend.src_rgb_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_source_rgb); 614 const auto& regs = Pica::g_state.regs;
603 state.blend.dst_rgb_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_dest_rgb); 615 state.blend.src_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb);
604 state.blend.src_a_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_source_a); 616 state.blend.dst_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb);
605 state.blend.dst_a_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_dest_a); 617 state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a);
618 state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a);
606} 619}
607 620
608void RasterizerOpenGL::SyncBlendColor() { 621void RasterizerOpenGL::SyncBlendColor() {
609 auto blend_color = PicaToGL::ColorRGBA8((u8*)&Pica::registers.output_merger.blend_const.r); 622 auto blend_color = PicaToGL::ColorRGBA8((u8*)&Pica::g_state.regs.output_merger.blend_const.r);
610 state.blend.color.red = blend_color[0]; 623 state.blend.color.red = blend_color[0];
611 state.blend.color.green = blend_color[1]; 624 state.blend.color.green = blend_color[1];
612 state.blend.color.blue = blend_color[2]; 625 state.blend.color.blue = blend_color[2];
@@ -614,9 +627,10 @@ void RasterizerOpenGL::SyncBlendColor() {
614} 627}
615 628
616void RasterizerOpenGL::SyncAlphaTest() { 629void RasterizerOpenGL::SyncAlphaTest() {
617 glUniform1i(uniform_alphatest_enabled, Pica::registers.output_merger.alpha_test.enable); 630 const auto& regs = Pica::g_state.regs;
618 glUniform1i(uniform_alphatest_func, Pica::registers.output_merger.alpha_test.func); 631 glUniform1i(uniform_alphatest_enabled, regs.output_merger.alpha_test.enable);
619 glUniform1f(uniform_alphatest_ref, Pica::registers.output_merger.alpha_test.ref / 255.0f); 632 glUniform1i(uniform_alphatest_func, (GLint)regs.output_merger.alpha_test.func.Value());
633 glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f);
620} 634}
621 635
622void RasterizerOpenGL::SyncStencilTest() { 636void RasterizerOpenGL::SyncStencilTest() {
@@ -624,9 +638,10 @@ void RasterizerOpenGL::SyncStencilTest() {
624} 638}
625 639
626void RasterizerOpenGL::SyncDepthTest() { 640void RasterizerOpenGL::SyncDepthTest() {
627 state.depth.test_enabled = Pica::registers.output_merger.depth_test_enable; 641 const auto& regs = Pica::g_state.regs;
628 state.depth.test_func = PicaToGL::CompareFunc(Pica::registers.output_merger.depth_test_func); 642 state.depth.test_enabled = (regs.output_merger.depth_test_enable == 1);
629 state.depth.write_mask = Pica::registers.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE; 643 state.depth.test_func = PicaToGL::CompareFunc(regs.output_merger.depth_test_func);
644 state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE;
630} 645}
631 646
632void RasterizerOpenGL::SyncTevSources(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { 647void RasterizerOpenGL::SyncTevSources(unsigned stage_index, const Pica::Regs::TevStageConfig& config) {
@@ -667,34 +682,37 @@ void RasterizerOpenGL::SyncTevMultipliers(unsigned stage_index, const Pica::Regs
667} 682}
668 683
669void RasterizerOpenGL::SyncCombinerColor() { 684void RasterizerOpenGL::SyncCombinerColor() {
670 auto combiner_color = PicaToGL::ColorRGBA8((u8*)&Pica::registers.tev_combiner_buffer_color.r); 685 auto combiner_color = PicaToGL::ColorRGBA8((u8*)&Pica::g_state.regs.tev_combiner_buffer_color.r);
671 glUniform4fv(uniform_tev_combiner_buffer_color, 1, combiner_color.data()); 686 glUniform4fv(uniform_tev_combiner_buffer_color, 1, combiner_color.data());
672} 687}
673 688
674void RasterizerOpenGL::SyncCombinerWriteFlags() { 689void RasterizerOpenGL::SyncCombinerWriteFlags() {
675 const auto tev_stages = Pica::registers.GetTevStages(); 690 const auto& regs = Pica::g_state.regs;
691 const auto tev_stages = regs.GetTevStages();
676 for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { 692 for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) {
677 glUniform2i(uniform_tev_cfgs[tev_stage_index].updates_combiner_buffer_color_alpha, 693 glUniform2i(uniform_tev_cfgs[tev_stage_index].updates_combiner_buffer_color_alpha,
678 Pica::registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index), 694 regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index),
679 Pica::registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)); 695 regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index));
680 } 696 }
681} 697}
682 698
683void RasterizerOpenGL::SyncDrawState() { 699void RasterizerOpenGL::SyncDrawState() {
700 const auto& regs = Pica::g_state.regs;
701
684 // Sync the viewport 702 // Sync the viewport
685 GLsizei viewport_width = (GLsizei)Pica::float24::FromRawFloat24(Pica::registers.viewport_size_x).ToFloat32() * 2; 703 GLsizei viewport_width = (GLsizei)Pica::float24::FromRawFloat24(regs.viewport_size_x).ToFloat32() * 2;
686 GLsizei viewport_height = (GLsizei)Pica::float24::FromRawFloat24(Pica::registers.viewport_size_y).ToFloat32() * 2; 704 GLsizei viewport_height = (GLsizei)Pica::float24::FromRawFloat24(regs.viewport_size_y).ToFloat32() * 2;
687 705
688 // OpenGL uses different y coordinates, so negate corner offset and flip origin 706 // OpenGL uses different y coordinates, so negate corner offset and flip origin
689 // TODO: Ensure viewport_corner.x should not be negated or origin flipped 707 // TODO: Ensure viewport_corner.x should not be negated or origin flipped
690 // TODO: Use floating-point viewports for accuracy if supported 708 // TODO: Use floating-point viewports for accuracy if supported
691 glViewport((GLsizei)static_cast<float>(Pica::registers.viewport_corner.x), 709 glViewport((GLsizei)static_cast<float>(regs.viewport_corner.x),
692 -(GLsizei)static_cast<float>(Pica::registers.viewport_corner.y) 710 -(GLsizei)static_cast<float>(regs.viewport_corner.y)
693 + Pica::registers.framebuffer.GetHeight() - viewport_height, 711 + regs.framebuffer.GetHeight() - viewport_height,
694 viewport_width, viewport_height); 712 viewport_width, viewport_height);
695 713
696 // Sync bound texture(s), upload if not cached 714 // Sync bound texture(s), upload if not cached
697 const auto pica_textures = Pica::registers.GetTextures(); 715 const auto pica_textures = regs.GetTextures();
698 for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) { 716 for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
699 const auto& texture = pica_textures[texture_index]; 717 const auto& texture = pica_textures[texture_index];
700 718
@@ -707,7 +725,7 @@ void RasterizerOpenGL::SyncDrawState() {
707 } 725 }
708 726
709 // Skip processing TEV stages that simply pass the previous stage results through 727 // Skip processing TEV stages that simply pass the previous stage results through
710 const auto tev_stages = Pica::registers.GetTevStages(); 728 const auto tev_stages = regs.GetTevStages();
711 for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { 729 for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) {
712 glUniform1i(uniform_tev_cfgs[tev_stage_index].enabled, !IsPassThroughTevStage(tev_stages[tev_stage_index])); 730 glUniform1i(uniform_tev_cfgs[tev_stage_index].enabled, !IsPassThroughTevStage(tev_stages[tev_stage_index]));
713 } 731 }
@@ -716,7 +734,7 @@ void RasterizerOpenGL::SyncDrawState() {
716} 734}
717 735
718void RasterizerOpenGL::ReloadColorBuffer() { 736void RasterizerOpenGL::ReloadColorBuffer() {
719 u8* color_buffer = Memory::GetPhysicalPointer(Pica::registers.framebuffer.GetColorBufferPhysicalAddress()); 737 u8* color_buffer = Memory::GetPhysicalPointer(Pica::g_state.regs.framebuffer.GetColorBufferPhysicalAddress());
720 738
721 if (color_buffer == nullptr) 739 if (color_buffer == nullptr)
722 return; 740 return;
@@ -748,7 +766,7 @@ void RasterizerOpenGL::ReloadColorBuffer() {
748 766
749void RasterizerOpenGL::ReloadDepthBuffer() { 767void RasterizerOpenGL::ReloadDepthBuffer() {
750 // TODO: Appears to work, but double-check endianness of depth values and order of depth-stencil 768 // TODO: Appears to work, but double-check endianness of depth values and order of depth-stencil
751 u8* depth_buffer = Memory::GetPhysicalPointer(Pica::registers.framebuffer.GetDepthBufferPhysicalAddress()); 769 u8* depth_buffer = Memory::GetPhysicalPointer(Pica::g_state.regs.framebuffer.GetDepthBufferPhysicalAddress());
752 770
753 if (depth_buffer == nullptr) { 771 if (depth_buffer == nullptr) {
754 return; 772 return;
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index 8369c649e..f8763e71b 100644
--- a/src/video_core/renderer_opengl/pica_to_gl.h
+++ b/src/video_core/renderer_opengl/pica_to_gl.h
@@ -41,7 +41,7 @@ inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) {
41 return gl_mode; 41 return gl_mode;
42} 42}
43 43
44inline GLenum BlendFunc(u32 factor) { 44inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) {
45 static const GLenum blend_func_table[] = { 45 static const GLenum blend_func_table[] = {
46 GL_ZERO, // BlendFactor::Zero 46 GL_ZERO, // BlendFactor::Zero
47 GL_ONE, // BlendFactor::One 47 GL_ONE, // BlendFactor::One
@@ -61,17 +61,17 @@ inline GLenum BlendFunc(u32 factor) {
61 }; 61 };
62 62
63 // Range check table for input 63 // Range check table for input
64 if (factor >= ARRAY_SIZE(blend_func_table)) { 64 if ((unsigned)factor >= ARRAY_SIZE(blend_func_table)) {
65 LOG_CRITICAL(Render_OpenGL, "Unknown blend factor %d", factor); 65 LOG_CRITICAL(Render_OpenGL, "Unknown blend factor %d", factor);
66 UNREACHABLE(); 66 UNREACHABLE();
67 67
68 return GL_ONE; 68 return GL_ONE;
69 } 69 }
70 70
71 return blend_func_table[factor]; 71 return blend_func_table[(unsigned)factor];
72} 72}
73 73
74inline GLenum CompareFunc(u32 func) { 74inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
75 static const GLenum compare_func_table[] = { 75 static const GLenum compare_func_table[] = {
76 GL_NEVER, // CompareFunc::Never 76 GL_NEVER, // CompareFunc::Never
77 GL_ALWAYS, // CompareFunc::Always 77 GL_ALWAYS, // CompareFunc::Always
@@ -84,14 +84,14 @@ inline GLenum CompareFunc(u32 func) {
84 }; 84 };
85 85
86 // Range check table for input 86 // Range check table for input
87 if (func >= ARRAY_SIZE(compare_func_table)) { 87 if ((unsigned)func >= ARRAY_SIZE(compare_func_table)) {
88 LOG_CRITICAL(Render_OpenGL, "Unknown compare function %d", func); 88 LOG_CRITICAL(Render_OpenGL, "Unknown compare function %d", func);
89 UNREACHABLE(); 89 UNREACHABLE();
90 90
91 return GL_ALWAYS; 91 return GL_ALWAYS;
92 } 92 }
93 93
94 return compare_func_table[func]; 94 return compare_func_table[(unsigned)func];
95} 95}
96 96
97inline std::array<GLfloat, 4> ColorRGBA8(const u8* bytes) { 97inline std::array<GLfloat, 4> ColorRGBA8(const u8* bytes) {
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp
index 981d1a356..7d68998f1 100644
--- a/src/video_core/vertex_shader.cpp
+++ b/src/video_core/vertex_shader.cpp
@@ -26,55 +26,8 @@ namespace Pica {
26 26
27namespace VertexShader { 27namespace VertexShader {
28 28
29static struct {
30 Math::Vec4<float24> f[96];
31
32 std::array<bool,16> b;
33
34 std::array<Math::Vec4<u8>,4> i;
35} shader_uniforms;
36
37static Math::Vec4<float24> vs_default_attributes[16];
38
39// TODO: Not sure where the shader binary and swizzle patterns are supposed to be loaded to!
40// For now, we just keep these local arrays around.
41static std::array<u32, 1024> shader_memory;
42static std::array<u32, 1024> swizzle_data;
43
44void SubmitShaderMemoryChange(u32 addr, u32 value) {
45 shader_memory[addr] = value;
46}
47
48void SubmitSwizzleDataChange(u32 addr, u32 value) {
49 swizzle_data[addr] = value;
50}
51
52Math::Vec4<float24>& GetFloatUniform(u32 index) {
53 return shader_uniforms.f[index];
54}
55
56bool& GetBoolUniform(u32 index) {
57 return shader_uniforms.b[index];
58}
59
60Math::Vec4<u8>& GetIntUniform(u32 index) {
61 return shader_uniforms.i[index];
62}
63
64Math::Vec4<float24>& GetDefaultAttribute(u32 index) {
65 return vs_default_attributes[index];
66}
67
68const std::array<u32, 1024>& GetShaderBinary() {
69 return shader_memory;
70}
71
72const std::array<u32, 1024>& GetSwizzlePatterns() {
73 return swizzle_data;
74}
75
76struct VertexShaderState { 29struct VertexShaderState {
77 u32* program_counter; 30 const u32* program_counter;
78 31
79 const float24* input_register_table[16]; 32 const float24* input_register_table[16];
80 Math::Vec4<float24> output_registers[16]; 33 Math::Vec4<float24> output_registers[16];
@@ -109,6 +62,9 @@ struct VertexShaderState {
109}; 62};
110 63
111static void ProcessShaderCode(VertexShaderState& state) { 64static void ProcessShaderCode(VertexShaderState& state) {
65 const auto& uniforms = g_state.vs.uniforms;
66 const auto& swizzle_data = g_state.vs.swizzle_data;
67 const auto& program_code = g_state.vs.program_code;
112 68
113 // Placeholder for invalid inputs 69 // Placeholder for invalid inputs
114 static float24 dummy_vec4_float24[4]; 70 static float24 dummy_vec4_float24[4];
@@ -116,14 +72,14 @@ static void ProcessShaderCode(VertexShaderState& state) {
116 while (true) { 72 while (true) {
117 if (!state.call_stack.empty()) { 73 if (!state.call_stack.empty()) {
118 auto& top = state.call_stack.top(); 74 auto& top = state.call_stack.top();
119 if (state.program_counter - shader_memory.data() == top.final_address) { 75 if (state.program_counter - program_code.data() == top.final_address) {
120 state.address_registers[2] += top.loop_increment; 76 state.address_registers[2] += top.loop_increment;
121 77
122 if (top.repeat_counter-- == 0) { 78 if (top.repeat_counter-- == 0) {
123 state.program_counter = &shader_memory[top.return_address]; 79 state.program_counter = &program_code[top.return_address];
124 state.call_stack.pop(); 80 state.call_stack.pop();
125 } else { 81 } else {
126 state.program_counter = &shader_memory[top.loop_address]; 82 state.program_counter = &program_code[top.loop_address];
127 } 83 }
128 84
129 // TODO: Is "trying again" accurate to hardware? 85 // TODO: Is "trying again" accurate to hardware?
@@ -135,12 +91,12 @@ static void ProcessShaderCode(VertexShaderState& state) {
135 const Instruction& instr = *(const Instruction*)state.program_counter; 91 const Instruction& instr = *(const Instruction*)state.program_counter;
136 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id]; 92 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id];
137 93
138 static auto call = [](VertexShaderState& state, u32 offset, u32 num_instructions, 94 static auto call = [&program_code](VertexShaderState& state, u32 offset, u32 num_instructions,
139 u32 return_offset, u8 repeat_count, u8 loop_increment) { 95 u32 return_offset, u8 repeat_count, u8 loop_increment) {
140 state.program_counter = &shader_memory[offset] - 1; // -1 to make sure when incrementing the PC we end up at the correct offset 96 state.program_counter = &program_code[offset] - 1; // -1 to make sure when incrementing the PC we end up at the correct offset
141 state.call_stack.push({ offset + num_instructions, return_offset, repeat_count, loop_increment, offset }); 97 state.call_stack.push({ offset + num_instructions, return_offset, repeat_count, loop_increment, offset });
142 }; 98 };
143 u32 binary_offset = state.program_counter - shader_memory.data(); 99 u32 binary_offset = state.program_counter - program_code.data();
144 100
145 state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + binary_offset); 101 state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + binary_offset);
146 102
@@ -153,7 +109,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
153 return &state.temporary_registers[source_reg.GetIndex()].x; 109 return &state.temporary_registers[source_reg.GetIndex()].x;
154 110
155 case RegisterType::FloatUniform: 111 case RegisterType::FloatUniform:
156 return &shader_uniforms.f[source_reg.GetIndex()].x; 112 return &uniforms.f[source_reg.GetIndex()].x;
157 113
158 default: 114 default:
159 return dummy_vec4_float24; 115 return dummy_vec4_float24;
@@ -471,13 +427,13 @@ static void ProcessShaderCode(VertexShaderState& state) {
471 427
472 case OpCode::Id::JMPC: 428 case OpCode::Id::JMPC:
473 if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) { 429 if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) {
474 state.program_counter = &shader_memory[instr.flow_control.dest_offset] - 1; 430 state.program_counter = &program_code[instr.flow_control.dest_offset] - 1;
475 } 431 }
476 break; 432 break;
477 433
478 case OpCode::Id::JMPU: 434 case OpCode::Id::JMPU:
479 if (shader_uniforms.b[instr.flow_control.bool_uniform_id]) { 435 if (uniforms.b[instr.flow_control.bool_uniform_id]) {
480 state.program_counter = &shader_memory[instr.flow_control.dest_offset] - 1; 436 state.program_counter = &program_code[instr.flow_control.dest_offset] - 1;
481 } 437 }
482 break; 438 break;
483 439
@@ -489,7 +445,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
489 break; 445 break;
490 446
491 case OpCode::Id::CALLU: 447 case OpCode::Id::CALLU:
492 if (shader_uniforms.b[instr.flow_control.bool_uniform_id]) { 448 if (uniforms.b[instr.flow_control.bool_uniform_id]) {
493 call(state, 449 call(state,
494 instr.flow_control.dest_offset, 450 instr.flow_control.dest_offset,
495 instr.flow_control.num_instructions, 451 instr.flow_control.num_instructions,
@@ -510,7 +466,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
510 break; 466 break;
511 467
512 case OpCode::Id::IFU: 468 case OpCode::Id::IFU:
513 if (shader_uniforms.b[instr.flow_control.bool_uniform_id]) { 469 if (uniforms.b[instr.flow_control.bool_uniform_id]) {
514 call(state, 470 call(state,
515 binary_offset + 1, 471 binary_offset + 1,
516 instr.flow_control.dest_offset - binary_offset - 1, 472 instr.flow_control.dest_offset - binary_offset - 1,
@@ -545,14 +501,14 @@ static void ProcessShaderCode(VertexShaderState& state) {
545 501
546 case OpCode::Id::LOOP: 502 case OpCode::Id::LOOP:
547 { 503 {
548 state.address_registers[2] = shader_uniforms.i[instr.flow_control.int_uniform_id].y; 504 state.address_registers[2] = uniforms.i[instr.flow_control.int_uniform_id].y;
549 505
550 call(state, 506 call(state,
551 binary_offset + 1, 507 binary_offset + 1,
552 instr.flow_control.dest_offset - binary_offset + 1, 508 instr.flow_control.dest_offset - binary_offset + 1,
553 instr.flow_control.dest_offset + 1, 509 instr.flow_control.dest_offset + 1,
554 shader_uniforms.i[instr.flow_control.int_uniform_id].x, 510 uniforms.i[instr.flow_control.int_uniform_id].x,
555 shader_uniforms.i[instr.flow_control.int_uniform_id].z); 511 uniforms.i[instr.flow_control.int_uniform_id].z);
556 break; 512 break;
557 } 513 }
558 514
@@ -578,15 +534,17 @@ static Common::Profiling::TimingCategory shader_category("Vertex Shader");
578OutputVertex RunShader(const InputVertex& input, int num_attributes) { 534OutputVertex RunShader(const InputVertex& input, int num_attributes) {
579 Common::Profiling::ScopeTimer timer(shader_category); 535 Common::Profiling::ScopeTimer timer(shader_category);
580 536
537 const auto& regs = g_state.regs;
538 const auto& vs = g_state.vs;
581 VertexShaderState state; 539 VertexShaderState state;
582 540
583 const u32* main = &shader_memory[registers.vs_main_offset]; 541 const u32* main = &vs.program_code[regs.vs_main_offset];
584 state.program_counter = (u32*)main; 542 state.program_counter = (u32*)main;
585 state.debug.max_offset = 0; 543 state.debug.max_offset = 0;
586 state.debug.max_opdesc_id = 0; 544 state.debug.max_opdesc_id = 0;
587 545
588 // Setup input register table 546 // Setup input register table
589 const auto& attribute_register_map = registers.vs_input_register_map; 547 const auto& attribute_register_map = regs.vs_input_register_map;
590 float24 dummy_register; 548 float24 dummy_register;
591 boost::fill(state.input_register_table, &dummy_register); 549 boost::fill(state.input_register_table, &dummy_register);
592 550
@@ -611,16 +569,16 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes) {
611 state.conditional_code[1] = false; 569 state.conditional_code[1] = false;
612 570
613 ProcessShaderCode(state); 571 ProcessShaderCode(state);
614 DebugUtils::DumpShader(shader_memory.data(), state.debug.max_offset, swizzle_data.data(), 572 DebugUtils::DumpShader(vs.program_code.data(), state.debug.max_offset, vs.swizzle_data.data(),
615 state.debug.max_opdesc_id, registers.vs_main_offset, 573 state.debug.max_opdesc_id, regs.vs_main_offset,
616 registers.vs_output_attributes); 574 regs.vs_output_attributes);
617 575
618 // Setup output data 576 // Setup output data
619 OutputVertex ret; 577 OutputVertex ret;
620 // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to 578 // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to
621 // figure out what those circumstances are and enable the remaining outputs then. 579 // figure out what those circumstances are and enable the remaining outputs then.
622 for (int i = 0; i < 7; ++i) { 580 for (int i = 0; i < 7; ++i) {
623 const auto& output_register_map = registers.vs_output_attributes[i]; 581 const auto& output_register_map = regs.vs_output_attributes[i];
624 582
625 u32 semantics[4] = { 583 u32 semantics[4] = {
626 output_register_map.map_x, output_register_map.map_y, 584 output_register_map.map_x, output_register_map.map_y,
diff --git a/src/video_core/vertex_shader.h b/src/video_core/vertex_shader.h
index c26709bbc..7471a6de8 100644
--- a/src/video_core/vertex_shader.h
+++ b/src/video_core/vertex_shader.h
@@ -66,19 +66,8 @@ struct OutputVertex {
66static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); 66static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
67static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size"); 67static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size");
68 68
69void SubmitShaderMemoryChange(u32 addr, u32 value);
70void SubmitSwizzleDataChange(u32 addr, u32 value);
71
72OutputVertex RunShader(const InputVertex& input, int num_attributes); 69OutputVertex RunShader(const InputVertex& input, int num_attributes);
73 70
74Math::Vec4<float24>& GetFloatUniform(u32 index);
75bool& GetBoolUniform(u32 index);
76Math::Vec4<u8>& GetIntUniform(u32 index);
77Math::Vec4<float24>& GetDefaultAttribute(u32 index);
78
79const std::array<u32, 1024>& GetShaderBinary();
80const std::array<u32, 1024>& GetSwizzlePatterns();
81
82} // namespace 71} // namespace
83 72
84} // namespace 73} // namespace
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index d4d907d5e..3becc4261 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -8,9 +8,11 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/settings.h" 9#include "core/settings.h"
10 10
11#include "video_core/video_core.h" 11#include "video_core.h"
12#include "video_core/renderer_base.h" 12#include "renderer_base.h"
13#include "video_core/renderer_opengl/renderer_opengl.h" 13#include "renderer_opengl/renderer_opengl.h"
14
15#include "pica.h"
14 16
15//////////////////////////////////////////////////////////////////////////////////////////////////// 17////////////////////////////////////////////////////////////////////////////////////////////////////
16// Video Core namespace 18// Video Core namespace
@@ -24,6 +26,8 @@ std::atomic<bool> g_hw_renderer_enabled;
24 26
25/// Initialize the video core 27/// Initialize the video core
26void Init(EmuWindow* emu_window) { 28void Init(EmuWindow* emu_window) {
29 Pica::Init();
30
27 g_emu_window = emu_window; 31 g_emu_window = emu_window;
28 g_renderer = new RendererOpenGL(); 32 g_renderer = new RendererOpenGL();
29 g_renderer->SetWindow(g_emu_window); 33 g_renderer->SetWindow(g_emu_window);
@@ -34,7 +38,10 @@ void Init(EmuWindow* emu_window) {
34 38
35/// Shutdown the video core 39/// Shutdown the video core
36void Shutdown() { 40void Shutdown() {
41 Pica::Shutdown();
42
37 delete g_renderer; 43 delete g_renderer;
44
38 LOG_DEBUG(Render, "shutdown OK"); 45 LOG_DEBUG(Render, "shutdown OK");
39} 46}
40 47