summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2017-02-08 22:07:34 -0800
committerGravatar GitHub2017-02-08 22:07:34 -0800
commit2889372e47624e368df0d0361cb38b8100f047dd (patch)
tree183cd1cd6edb60ab566bd1fe181b712643bef30c /src
parentMerge pull request #2539 from Kloen/re-killing-warnings (diff)
parentVideoCore: Move Regs to its own file (diff)
downloadyuzu-2889372e47624e368df0d0361cb38b8100f047dd.tar.gz
yuzu-2889372e47624e368df0d0361cb38b8100f047dd.tar.xz
yuzu-2889372e47624e368df0d0361cb38b8100f047dd.zip
Merge pull request #2482 from yuriks/pica-refactor
Split up monolithic Regs struct
Diffstat (limited to 'src')
-rw-r--r--src/citra_qt/debugger/graphics/graphics_cmdlists.cpp24
-rw-r--r--src/citra_qt/debugger/graphics/graphics_surface.cpp33
-rw-r--r--src/citra_qt/debugger/graphics/graphics_tracing.cpp1
-rw-r--r--src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp3
-rw-r--r--src/video_core/CMakeLists.txt8
-rw-r--r--src/video_core/clipper.cpp10
-rw-r--r--src/video_core/command_processor.cpp82
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp43
-rw-r--r--src/video_core/debug_utils/debug_utils.h14
-rw-r--r--src/video_core/pica.cpp487
-rw-r--r--src/video_core/pica.h1393
-rw-r--r--src/video_core/pica_state.h2
-rw-r--r--src/video_core/primitive_assembly.cpp18
-rw-r--r--src/video_core/primitive_assembly.h9
-rw-r--r--src/video_core/rasterizer.cpp307
-rw-r--r--src/video_core/regs.cpp493
-rw-r--r--src/video_core/regs.h164
-rw-r--r--src/video_core/regs_framebuffer.h284
-rw-r--r--src/video_core/regs_lighting.h294
-rw-r--r--src/video_core/regs_pipeline.h224
-rw-r--r--src/video_core/regs_rasterizer.h129
-rw-r--r--src/video_core/regs_shader.h104
-rw-r--r--src/video_core/regs_texturing.h328
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp294
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h51
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp17
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h12
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp99
-rw-r--r--src/video_core/renderer_opengl/pica_to_gl.h18
-rw-r--r--src/video_core/shader/shader.cpp14
-rw-r--r--src/video_core/shader/shader.h24
-rw-r--r--src/video_core/shader/shader_interpreter.cpp2
-rw-r--r--src/video_core/shader/shader_interpreter.h2
-rw-r--r--src/video_core/texture/texture_decode.cpp38
-rw-r--r--src/video_core/texture/texture_decode.h12
-rw-r--r--src/video_core/vertex_loader.cpp17
-rw-r--r--src/video_core/vertex_loader.h8
37 files changed, 2635 insertions, 2427 deletions
diff --git a/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp
index ee79f0edf..536548f36 100644
--- a/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp
@@ -18,8 +18,8 @@
18#include "citra_qt/util/util.h" 18#include "citra_qt/util/util.h"
19#include "common/vector_math.h" 19#include "common/vector_math.h"
20#include "video_core/debug_utils/debug_utils.h" 20#include "video_core/debug_utils/debug_utils.h"
21#include "video_core/pica.h"
22#include "video_core/pica_state.h" 21#include "video_core/pica_state.h"
22#include "video_core/regs.h"
23#include "video_core/texture/texture_decode.h" 23#include "video_core/texture/texture_decode.h"
24 24
25namespace { 25namespace {
@@ -123,15 +123,16 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&
123void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) { 123void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
124 const unsigned int command_id = 124 const unsigned int command_id =
125 list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt(); 125 list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt();
126 if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) || 126 if (COMMAND_IN_RANGE(command_id, texturing.texture0) ||
127 COMMAND_IN_RANGE(command_id, texture2)) { 127 COMMAND_IN_RANGE(command_id, texturing.texture1) ||
128 COMMAND_IN_RANGE(command_id, texturing.texture2)) {
128 129
129 unsigned texture_index; 130 unsigned texture_index;
130 if (COMMAND_IN_RANGE(command_id, texture0)) { 131 if (COMMAND_IN_RANGE(command_id, texturing.texture0)) {
131 texture_index = 0; 132 texture_index = 0;
132 } else if (COMMAND_IN_RANGE(command_id, texture1)) { 133 } else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) {
133 texture_index = 1; 134 texture_index = 1;
134 } else if (COMMAND_IN_RANGE(command_id, texture2)) { 135 } else if (COMMAND_IN_RANGE(command_id, texturing.texture2)) {
135 texture_index = 2; 136 texture_index = 2;
136 } else { 137 } else {
137 UNREACHABLE_MSG("Unknown texture command"); 138 UNREACHABLE_MSG("Unknown texture command");
@@ -146,19 +147,20 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
146 147
147 const unsigned int command_id = 148 const unsigned int command_id =
148 list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt(); 149 list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt();
149 if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) || 150 if (COMMAND_IN_RANGE(command_id, texturing.texture0) ||
150 COMMAND_IN_RANGE(command_id, texture2)) { 151 COMMAND_IN_RANGE(command_id, texturing.texture1) ||
152 COMMAND_IN_RANGE(command_id, texturing.texture2)) {
151 153
152 unsigned texture_index; 154 unsigned texture_index;
153 if (COMMAND_IN_RANGE(command_id, texture0)) { 155 if (COMMAND_IN_RANGE(command_id, texturing.texture0)) {
154 texture_index = 0; 156 texture_index = 0;
155 } else if (COMMAND_IN_RANGE(command_id, texture1)) { 157 } else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) {
156 texture_index = 1; 158 texture_index = 1;
157 } else { 159 } else {
158 texture_index = 2; 160 texture_index = 2;
159 } 161 }
160 162
161 const auto texture = Pica::g_state.regs.GetTextures()[texture_index]; 163 const auto texture = Pica::g_state.regs.texturing.GetTextures()[texture_index];
162 const auto config = texture.config; 164 const auto config = texture.config;
163 const auto format = texture.format; 165 const auto format = texture.format;
164 166
diff --git a/src/citra_qt/debugger/graphics/graphics_surface.cpp b/src/citra_qt/debugger/graphics/graphics_surface.cpp
index bd82b00d4..f83c1f96c 100644
--- a/src/citra_qt/debugger/graphics/graphics_surface.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_surface.cpp
@@ -16,8 +16,8 @@
16#include "common/color.h" 16#include "common/color.h"
17#include "core/hw/gpu.h" 17#include "core/hw/gpu.h"
18#include "core/memory.h" 18#include "core/memory.h"
19#include "video_core/pica.h"
20#include "video_core/pica_state.h" 19#include "video_core/pica_state.h"
20#include "video_core/regs.h"
21#include "video_core/texture/texture_decode.h" 21#include "video_core/texture/texture_decode.h"
22#include "video_core/utils.h" 22#include "video_core/utils.h"
23 23
@@ -414,30 +414,30 @@ void GraphicsSurfaceWidget::OnUpdate() {
414 // TODO: Store a reference to the registers in the debug context instead of accessing them 414 // TODO: Store a reference to the registers in the debug context instead of accessing them
415 // directly... 415 // directly...
416 416
417 const auto& framebuffer = Pica::g_state.regs.framebuffer; 417 const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer;
418 418
419 surface_address = framebuffer.GetColorBufferPhysicalAddress(); 419 surface_address = framebuffer.GetColorBufferPhysicalAddress();
420 surface_width = framebuffer.GetWidth(); 420 surface_width = framebuffer.GetWidth();
421 surface_height = framebuffer.GetHeight(); 421 surface_height = framebuffer.GetHeight();
422 422
423 switch (framebuffer.color_format) { 423 switch (framebuffer.color_format) {
424 case Pica::Regs::ColorFormat::RGBA8: 424 case Pica::FramebufferRegs::ColorFormat::RGBA8:
425 surface_format = Format::RGBA8; 425 surface_format = Format::RGBA8;
426 break; 426 break;
427 427
428 case Pica::Regs::ColorFormat::RGB8: 428 case Pica::FramebufferRegs::ColorFormat::RGB8:
429 surface_format = Format::RGB8; 429 surface_format = Format::RGB8;
430 break; 430 break;
431 431
432 case Pica::Regs::ColorFormat::RGB5A1: 432 case Pica::FramebufferRegs::ColorFormat::RGB5A1:
433 surface_format = Format::RGB5A1; 433 surface_format = Format::RGB5A1;
434 break; 434 break;
435 435
436 case Pica::Regs::ColorFormat::RGB565: 436 case Pica::FramebufferRegs::ColorFormat::RGB565:
437 surface_format = Format::RGB565; 437 surface_format = Format::RGB565;
438 break; 438 break;
439 439
440 case Pica::Regs::ColorFormat::RGBA4: 440 case Pica::FramebufferRegs::ColorFormat::RGBA4:
441 surface_format = Format::RGBA4; 441 surface_format = Format::RGBA4;
442 break; 442 break;
443 443
@@ -450,22 +450,22 @@ void GraphicsSurfaceWidget::OnUpdate() {
450 } 450 }
451 451
452 case Source::DepthBuffer: { 452 case Source::DepthBuffer: {
453 const auto& framebuffer = Pica::g_state.regs.framebuffer; 453 const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer;
454 454
455 surface_address = framebuffer.GetDepthBufferPhysicalAddress(); 455 surface_address = framebuffer.GetDepthBufferPhysicalAddress();
456 surface_width = framebuffer.GetWidth(); 456 surface_width = framebuffer.GetWidth();
457 surface_height = framebuffer.GetHeight(); 457 surface_height = framebuffer.GetHeight();
458 458
459 switch (framebuffer.depth_format) { 459 switch (framebuffer.depth_format) {
460 case Pica::Regs::DepthFormat::D16: 460 case Pica::FramebufferRegs::DepthFormat::D16:
461 surface_format = Format::D16; 461 surface_format = Format::D16;
462 break; 462 break;
463 463
464 case Pica::Regs::DepthFormat::D24: 464 case Pica::FramebufferRegs::DepthFormat::D24:
465 surface_format = Format::D24; 465 surface_format = Format::D24;
466 break; 466 break;
467 467
468 case Pica::Regs::DepthFormat::D24S8: 468 case Pica::FramebufferRegs::DepthFormat::D24S8:
469 surface_format = Format::D24X8; 469 surface_format = Format::D24X8;
470 break; 470 break;
471 471
@@ -478,14 +478,14 @@ void GraphicsSurfaceWidget::OnUpdate() {
478 } 478 }
479 479
480 case Source::StencilBuffer: { 480 case Source::StencilBuffer: {
481 const auto& framebuffer = Pica::g_state.regs.framebuffer; 481 const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer;
482 482
483 surface_address = framebuffer.GetDepthBufferPhysicalAddress(); 483 surface_address = framebuffer.GetDepthBufferPhysicalAddress();
484 surface_width = framebuffer.GetWidth(); 484 surface_width = framebuffer.GetWidth();
485 surface_height = framebuffer.GetHeight(); 485 surface_height = framebuffer.GetHeight();
486 486
487 switch (framebuffer.depth_format) { 487 switch (framebuffer.depth_format) {
488 case Pica::Regs::DepthFormat::D24S8: 488 case Pica::FramebufferRegs::DepthFormat::D24S8:
489 surface_format = Format::X24S8; 489 surface_format = Format::X24S8;
490 break; 490 break;
491 491
@@ -512,7 +512,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
512 break; 512 break;
513 } 513 }
514 514
515 const auto texture = Pica::g_state.regs.GetTextures()[texture_index]; 515 const auto texture = Pica::g_state.regs.texturing.GetTextures()[texture_index];
516 auto info = Pica::Texture::TextureInfo::FromPicaRegister(texture.config, texture.format); 516 auto info = Pica::Texture::TextureInfo::FromPicaRegister(texture.config, texture.format);
517 517
518 surface_address = info.physical_address; 518 surface_address = info.physical_address;
@@ -574,7 +574,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
574 info.physical_address = surface_address; 574 info.physical_address = surface_address;
575 info.width = surface_width; 575 info.width = surface_width;
576 info.height = surface_height; 576 info.height = surface_height;
577 info.format = static_cast<Pica::Regs::TextureFormat>(surface_format); 577 info.format = static_cast<Pica::TexturingRegs::TextureFormat>(surface_format);
578 info.SetDefaultStride(); 578 info.SetDefaultStride();
579 579
580 for (unsigned int y = 0; y < surface_height; ++y) { 580 for (unsigned int y = 0; y < surface_height; ++y) {
@@ -689,7 +689,8 @@ void GraphicsSurfaceWidget::SaveSurface() {
689 689
690unsigned int GraphicsSurfaceWidget::NibblesPerPixel(GraphicsSurfaceWidget::Format format) { 690unsigned int GraphicsSurfaceWidget::NibblesPerPixel(GraphicsSurfaceWidget::Format format) {
691 if (format <= Format::MaxTextureFormat) { 691 if (format <= Format::MaxTextureFormat) {
692 return Pica::Regs::NibblesPerPixel(static_cast<Pica::Regs::TextureFormat>(format)); 692 return Pica::TexturingRegs::NibblesPerPixel(
693 static_cast<Pica::TexturingRegs::TextureFormat>(format));
693 } 694 }
694 695
695 switch (format) { 696 switch (format) {
diff --git a/src/citra_qt/debugger/graphics/graphics_tracing.cpp b/src/citra_qt/debugger/graphics/graphics_tracing.cpp
index 17f1c5ce2..40d5bed51 100644
--- a/src/citra_qt/debugger/graphics/graphics_tracing.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_tracing.cpp
@@ -18,7 +18,6 @@
18#include "core/hw/lcd.h" 18#include "core/hw/lcd.h"
19#include "core/tracer/recorder.h" 19#include "core/tracer/recorder.h"
20#include "nihstro/float24.h" 20#include "nihstro/float24.h"
21#include "video_core/pica.h"
22#include "video_core/pica_state.h" 21#include "video_core/pica_state.h"
23 22
24GraphicsTracingWidget::GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context, 23GraphicsTracingWidget::GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context,
diff --git a/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp
index 489ec5f21..e3f3194db 100644
--- a/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp
@@ -16,7 +16,6 @@
16#include <QTreeView> 16#include <QTreeView>
17#include "citra_qt/debugger/graphics/graphics_vertex_shader.h" 17#include "citra_qt/debugger/graphics/graphics_vertex_shader.h"
18#include "citra_qt/util/util.h" 18#include "citra_qt/util/util.h"
19#include "video_core/pica.h"
20#include "video_core/pica_state.h" 19#include "video_core/pica_state.h"
21#include "video_core/shader/debug_data.h" 20#include "video_core/shader/debug_data.h"
22#include "video_core/shader/shader.h" 21#include "video_core/shader/shader.h"
@@ -359,7 +358,7 @@ void GraphicsVertexShaderWidget::DumpShader() {
359 auto& config = Pica::g_state.regs.vs; 358 auto& config = Pica::g_state.regs.vs;
360 359
361 Pica::DebugUtils::DumpShader(filename.toStdString(), config, setup, 360 Pica::DebugUtils::DumpShader(filename.toStdString(), config, setup,
362 Pica::g_state.regs.vs_output_attributes); 361 Pica::g_state.regs.rasterizer.vs_output_attributes);
363} 362}
364 363
365GraphicsVertexShaderWidget::GraphicsVertexShaderWidget( 364GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index ad984cd94..11bc61e14 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -5,6 +5,7 @@ set(SRCS
5 pica.cpp 5 pica.cpp
6 primitive_assembly.cpp 6 primitive_assembly.cpp
7 rasterizer.cpp 7 rasterizer.cpp
8 regs.cpp
8 renderer_base.cpp 9 renderer_base.cpp
9 renderer_opengl/gl_rasterizer.cpp 10 renderer_opengl/gl_rasterizer.cpp
10 renderer_opengl/gl_rasterizer_cache.cpp 11 renderer_opengl/gl_rasterizer_cache.cpp
@@ -32,6 +33,13 @@ set(HEADERS
32 primitive_assembly.h 33 primitive_assembly.h
33 rasterizer.h 34 rasterizer.h
34 rasterizer_interface.h 35 rasterizer_interface.h
36 regs.h
37 regs_framebuffer.h
38 regs_lighting.h
39 regs_pipeline.h
40 regs_rasterizer.h
41 regs_shader.h
42 regs_texturing.h
35 renderer_base.h 43 renderer_base.h
36 renderer_opengl/gl_rasterizer.h 44 renderer_opengl/gl_rasterizer.h
37 renderer_opengl/gl_rasterizer_cache.h 45 renderer_opengl/gl_rasterizer_cache.h
diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp
index 0774ffc53..0f71bbd06 100644
--- a/src/video_core/clipper.cpp
+++ b/src/video_core/clipper.cpp
@@ -12,10 +12,10 @@
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/vector_math.h" 13#include "common/vector_math.h"
14#include "video_core/clipper.h" 14#include "video_core/clipper.h"
15#include "video_core/pica.h"
16#include "video_core/pica_state.h" 15#include "video_core/pica_state.h"
17#include "video_core/pica_types.h" 16#include "video_core/pica_types.h"
18#include "video_core/rasterizer.h" 17#include "video_core/rasterizer.h"
18#include "video_core/regs.h"
19#include "video_core/shader/shader.h" 19#include "video_core/shader/shader.h"
20 20
21using Pica::Rasterizer::Vertex; 21using Pica::Rasterizer::Vertex;
@@ -64,10 +64,10 @@ static void InitScreenCoordinates(Vertex& vtx) {
64 } viewport; 64 } viewport;
65 65
66 const auto& regs = g_state.regs; 66 const auto& regs = g_state.regs;
67 viewport.halfsize_x = float24::FromRaw(regs.viewport_size_x); 67 viewport.halfsize_x = float24::FromRaw(regs.rasterizer.viewport_size_x);
68 viewport.halfsize_y = float24::FromRaw(regs.viewport_size_y); 68 viewport.halfsize_y = float24::FromRaw(regs.rasterizer.viewport_size_y);
69 viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.viewport_corner.x)); 69 viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.rasterizer.viewport_corner.x));
70 viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.viewport_corner.y)); 70 viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.rasterizer.viewport_corner.y));
71 71
72 float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w; 72 float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w;
73 vtx.color *= inv_w; 73 vtx.color *= inv_w;
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 4955ff9f9..91c0ca4e6 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -16,11 +16,11 @@
16#include "core/tracer/recorder.h" 16#include "core/tracer/recorder.h"
17#include "video_core/command_processor.h" 17#include "video_core/command_processor.h"
18#include "video_core/debug_utils/debug_utils.h" 18#include "video_core/debug_utils/debug_utils.h"
19#include "video_core/pica.h"
20#include "video_core/pica_state.h" 19#include "video_core/pica_state.h"
21#include "video_core/pica_types.h" 20#include "video_core/pica_types.h"
22#include "video_core/primitive_assembly.h" 21#include "video_core/primitive_assembly.h"
23#include "video_core/rasterizer_interface.h" 22#include "video_core/rasterizer_interface.h"
23#include "video_core/regs.h"
24#include "video_core/renderer_base.h" 24#include "video_core/renderer_base.h"
25#include "video_core/shader/shader.h" 25#include "video_core/shader/shader.h"
26#include "video_core/vertex_loader.h" 26#include "video_core/vertex_loader.h"
@@ -74,23 +74,23 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
74 Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D); 74 Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D);
75 break; 75 break;
76 76
77 case PICA_REG_INDEX_WORKAROUND(triangle_topology, 0x25E): 77 case PICA_REG_INDEX(pipeline.triangle_topology):
78 g_state.primitive_assembler.Reconfigure(regs.triangle_topology); 78 g_state.primitive_assembler.Reconfigure(regs.pipeline.triangle_topology);
79 break; 79 break;
80 80
81 case PICA_REG_INDEX_WORKAROUND(restart_primitive, 0x25F): 81 case PICA_REG_INDEX(pipeline.restart_primitive):
82 g_state.primitive_assembler.Reset(); 82 g_state.primitive_assembler.Reset();
83 break; 83 break;
84 84
85 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.index, 0x232): 85 case PICA_REG_INDEX(pipeline.vs_default_attributes_setup.index):
86 g_state.immediate.current_attribute = 0; 86 g_state.immediate.current_attribute = 0;
87 default_attr_counter = 0; 87 default_attr_counter = 0;
88 break; 88 break;
89 89
90 // Load default vertex input attributes 90 // Load default vertex input attributes
91 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233): 91 case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[0], 0x233):
92 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234): 92 case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[1], 0x234):
93 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235): { 93 case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[2], 0x235): {
94 // TODO: Does actual hardware indeed keep an intermediate buffer or does 94 // TODO: Does actual hardware indeed keep an intermediate buffer or does
95 // it directly write the values? 95 // it directly write the values?
96 default_attr_write_buffer[default_attr_counter++] = value; 96 default_attr_write_buffer[default_attr_counter++] = value;
@@ -102,7 +102,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
102 if (default_attr_counter >= 3) { 102 if (default_attr_counter >= 3) {
103 default_attr_counter = 0; 103 default_attr_counter = 0;
104 104
105 auto& setup = regs.vs_default_attributes_setup; 105 auto& setup = regs.pipeline.vs_default_attributes_setup;
106 106
107 if (setup.index >= 16) { 107 if (setup.index >= 16) {
108 LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index); 108 LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index);
@@ -137,7 +137,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
137 137
138 immediate_input.attr[immediate_attribute_id] = attribute; 138 immediate_input.attr[immediate_attribute_id] = attribute;
139 139
140 if (immediate_attribute_id < regs.max_input_attrib_index) { 140 if (immediate_attribute_id < regs.pipeline.max_input_attrib_index) {
141 immediate_attribute_id += 1; 141 immediate_attribute_id += 1;
142 } else { 142 } else {
143 MICROPROFILE_SCOPE(GPU_Drawing); 143 MICROPROFILE_SCOPE(GPU_Drawing);
@@ -165,15 +165,16 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
165 }; 165 };
166 166
167 g_state.primitive_assembler.SubmitVertex( 167 g_state.primitive_assembler.SubmitVertex(
168 Shader::OutputVertex::FromAttributeBuffer(regs, output), AddTriangle); 168 Shader::OutputVertex::FromAttributeBuffer(regs.rasterizer, output),
169 AddTriangle);
169 } 170 }
170 } 171 }
171 } 172 }
172 break; 173 break;
173 } 174 }
174 175
175 case PICA_REG_INDEX(gpu_mode): 176 case PICA_REG_INDEX(pipeline.gpu_mode):
176 if (regs.gpu_mode == Regs::GPUMode::Configuring) { 177 if (regs.pipeline.gpu_mode == PipelineRegs::GPUMode::Configuring) {
177 MICROPROFILE_SCOPE(GPU_Drawing); 178 MICROPROFILE_SCOPE(GPU_Drawing);
178 179
179 // Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring 180 // Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring
@@ -185,19 +186,20 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
185 } 186 }
186 break; 187 break;
187 188
188 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c): 189 case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[0], 0x23c):
189 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): { 190 case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[1], 0x23d): {
190 unsigned index = static_cast<unsigned>(id - PICA_REG_INDEX(command_buffer.trigger[0])); 191 unsigned index =
191 u32* head_ptr = 192 static_cast<unsigned>(id - PICA_REG_INDEX(pipeline.command_buffer.trigger[0]));
192 (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index)); 193 u32* head_ptr = (u32*)Memory::GetPhysicalPointer(
194 regs.pipeline.command_buffer.GetPhysicalAddress(index));
193 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr; 195 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
194 g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32); 196 g_state.cmd_list.length = regs.pipeline.command_buffer.GetSize(index) / sizeof(u32);
195 break; 197 break;
196 } 198 }
197 199
198 // It seems like these trigger vertex rendering 200 // It seems like these trigger vertex rendering
199 case PICA_REG_INDEX(trigger_draw): 201 case PICA_REG_INDEX(pipeline.trigger_draw):
200 case PICA_REG_INDEX(trigger_draw_indexed): { 202 case PICA_REG_INDEX(pipeline.trigger_draw_indexed): {
201 MICROPROFILE_SCOPE(GPU_Drawing); 203 MICROPROFILE_SCOPE(GPU_Drawing);
202 204
203#if PICA_LOG_TEV 205#if PICA_LOG_TEV
@@ -209,13 +211,13 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
209 // Processes information about internal vertex attributes to figure out how a vertex is 211 // Processes information about internal vertex attributes to figure out how a vertex is
210 // loaded. 212 // loaded.
211 // Later, these can be compiled and cached. 213 // Later, these can be compiled and cached.
212 const u32 base_address = regs.vertex_attributes.GetPhysicalBaseAddress(); 214 const u32 base_address = regs.pipeline.vertex_attributes.GetPhysicalBaseAddress();
213 VertexLoader loader(regs); 215 VertexLoader loader(regs.pipeline);
214 216
215 // Load vertices 217 // Load vertices
216 bool is_indexed = (id == PICA_REG_INDEX(trigger_draw_indexed)); 218 bool is_indexed = (id == PICA_REG_INDEX(pipeline.trigger_draw_indexed));
217 219
218 const auto& index_info = regs.index_array; 220 const auto& index_info = regs.pipeline.index_array;
219 const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset); 221 const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset);
220 const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8); 222 const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8);
221 bool index_u16 = index_info.format != 0; 223 bool index_u16 = index_info.format != 0;
@@ -224,13 +226,13 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
224 226
225 if (g_debug_context && g_debug_context->recorder) { 227 if (g_debug_context && g_debug_context->recorder) {
226 for (int i = 0; i < 3; ++i) { 228 for (int i = 0; i < 3; ++i) {
227 const auto texture = regs.GetTextures()[i]; 229 const auto texture = regs.texturing.GetTextures()[i];
228 if (!texture.enabled) 230 if (!texture.enabled)
229 continue; 231 continue;
230 232
231 u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress()); 233 u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
232 g_debug_context->recorder->MemoryAccessed( 234 g_debug_context->recorder->MemoryAccessed(
233 texture_data, Pica::Regs::NibblesPerPixel(texture.format) * 235 texture_data, Pica::TexturingRegs::NibblesPerPixel(texture.format) *
234 texture.config.width / 2 * texture.config.height, 236 texture.config.width / 2 * texture.config.height,
235 texture.config.GetPhysicalAddress()); 237 texture.config.GetPhysicalAddress());
236 } 238 }
@@ -253,11 +255,11 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
253 255
254 shader_engine->SetupBatch(g_state.vs, regs.vs.main_offset); 256 shader_engine->SetupBatch(g_state.vs, regs.vs.main_offset);
255 257
256 for (unsigned int index = 0; index < regs.num_vertices; ++index) { 258 for (unsigned int index = 0; index < regs.pipeline.num_vertices; ++index) {
257 // Indexed rendering doesn't use the start offset 259 // Indexed rendering doesn't use the start offset
258 unsigned int vertex = 260 unsigned int vertex =
259 is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) 261 is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index])
260 : (index + regs.vertex_offset); 262 : (index + regs.pipeline.vertex_offset);
261 263
262 // -1 is a common special value used for primitive restart. Since it's unknown if 264 // -1 is a common special value used for primitive restart. Since it's unknown if
263 // the PICA supports it, and it would mess up the caching, guard against it here. 265 // the PICA supports it, and it would mess up the caching, guard against it here.
@@ -295,7 +297,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
295 shader_unit.WriteOutput(regs.vs, output); 297 shader_unit.WriteOutput(regs.vs, output);
296 298
297 // Retrieve vertex from register data 299 // Retrieve vertex from register data
298 output_vertex = Shader::OutputVertex::FromAttributeBuffer(regs, output); 300 output_vertex = Shader::OutputVertex::FromAttributeBuffer(regs.rasterizer, output);
299 301
300 if (is_indexed) { 302 if (is_indexed) {
301 vertex_cache[vertex_cache_pos] = output_vertex; 303 vertex_cache[vertex_cache_pos] = output_vertex;
@@ -437,16 +439,16 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
437 break; 439 break;
438 } 440 }
439 441
440 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[0], 0xe8): 442 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[0], 0xe8):
441 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[1], 0xe9): 443 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[1], 0xe9):
442 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[2], 0xea): 444 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[2], 0xea):
443 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[3], 0xeb): 445 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[3], 0xeb):
444 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[4], 0xec): 446 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[4], 0xec):
445 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[5], 0xed): 447 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[5], 0xed):
446 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[6], 0xee): 448 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[6], 0xee):
447 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[7], 0xef): { 449 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[7], 0xef): {
448 g_state.fog.lut[regs.fog_lut_offset % 128].raw = value; 450 g_state.fog.lut[regs.texturing.fog_lut_offset % 128].raw = value;
449 regs.fog_lut_offset.Assign(regs.fog_lut_offset + 1); 451 regs.texturing.fog_lut_offset.Assign(regs.texturing.fog_lut_offset + 1);
450 break; 452 break;
451 } 453 }
452 454
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 2d40f7d4f..e164e83a1 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -29,10 +29,10 @@
29#include "common/math_util.h" 29#include "common/math_util.h"
30#include "common/vector_math.h" 30#include "common/vector_math.h"
31#include "video_core/debug_utils/debug_utils.h" 31#include "video_core/debug_utils/debug_utils.h"
32#include "video_core/pica.h"
33#include "video_core/pica_state.h" 32#include "video_core/pica_state.h"
34#include "video_core/pica_types.h" 33#include "video_core/pica_types.h"
35#include "video_core/rasterizer_interface.h" 34#include "video_core/rasterizer_interface.h"
35#include "video_core/regs.h"
36#include "video_core/renderer_base.h" 36#include "video_core/renderer_base.h"
37#include "video_core/shader/shader.h" 37#include "video_core/shader/shader.h"
38#include "video_core/texture/texture_decode.h" 38#include "video_core/texture/texture_decode.h"
@@ -88,9 +88,9 @@ std::shared_ptr<DebugContext> g_debug_context; // TODO: Get rid of this global
88 88
89namespace DebugUtils { 89namespace DebugUtils {
90 90
91void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, 91void DumpShader(const std::string& filename, const ShaderRegs& config,
92 const Shader::ShaderSetup& setup, 92 const Shader::ShaderSetup& setup,
93 const Regs::VSOutputAttributes* output_attributes) { 93 const RasterizerRegs::VSOutputAttributes* output_attributes) {
94 struct StuffToWrite { 94 struct StuffToWrite {
95 const u8* pointer; 95 const u8* pointer;
96 u32 size; 96 u32 size;
@@ -129,7 +129,7 @@ void DumpShader(const std::string& filename, const Regs::ShaderConfig& config,
129 // This is put into a try-catch block to make sure we notice unknown configurations. 129 // This is put into a try-catch block to make sure we notice unknown configurations.
130 std::vector<OutputRegisterInfo> output_info_table; 130 std::vector<OutputRegisterInfo> output_info_table;
131 for (unsigned i = 0; i < 7; ++i) { 131 for (unsigned i = 0; i < 7; ++i) {
132 using OutputAttributes = Pica::Regs::VSOutputAttributes; 132 using OutputAttributes = Pica::RasterizerRegs::VSOutputAttributes;
133 133
134 // TODO: It's still unclear how the attribute components map to the register! 134 // TODO: It's still unclear how the attribute components map to the register!
135 // Once we know that, this code probably will not make much sense anymore. 135 // Once we know that, this code probably will not make much sense anymore.
@@ -331,7 +331,7 @@ static void FlushIOFile(png_structp png_ptr) {
331} 331}
332#endif 332#endif
333 333
334void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { 334void DumpTexture(const TexturingRegs::TextureConfig& texture_config, u8* data) {
335#ifndef HAVE_PNG 335#ifndef HAVE_PNG
336 return; 336 return;
337#else 337#else
@@ -396,7 +396,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
396 info.width = texture_config.width; 396 info.width = texture_config.width;
397 info.height = texture_config.height; 397 info.height = texture_config.height;
398 info.stride = row_stride; 398 info.stride = row_stride;
399 info.format = g_state.regs.texture0_format; 399 info.format = g_state.regs.texturing.texture0_format;
400 Math::Vec4<u8> texture_color = Pica::Texture::LookupTexture(data, x, y, info); 400 Math::Vec4<u8> texture_color = Pica::Texture::LookupTexture(data, x, y, info);
401 buf[3 * x + y * row_stride] = texture_color.r(); 401 buf[3 * x + y * row_stride] = texture_color.r();
402 buf[3 * x + y * row_stride + 1] = texture_color.g(); 402 buf[3 * x + y * row_stride + 1] = texture_color.g();
@@ -434,8 +434,10 @@ static std::string ReplacePattern(const std::string& input, const std::string& p
434 return ret; 434 return ret;
435} 435}
436 436
437static std::string GetTevStageConfigSourceString(const Pica::Regs::TevStageConfig::Source& source) { 437static std::string GetTevStageConfigSourceString(
438 using Source = Pica::Regs::TevStageConfig::Source; 438 const TexturingRegs::TevStageConfig::Source& source) {
439
440 using Source = TexturingRegs::TevStageConfig::Source;
439 static const std::map<Source, std::string> source_map = { 441 static const std::map<Source, std::string> source_map = {
440 {Source::PrimaryColor, "PrimaryColor"}, 442 {Source::PrimaryColor, "PrimaryColor"},
441 {Source::PrimaryFragmentColor, "PrimaryFragmentColor"}, 443 {Source::PrimaryFragmentColor, "PrimaryFragmentColor"},
@@ -457,9 +459,10 @@ static std::string GetTevStageConfigSourceString(const Pica::Regs::TevStageConfi
457} 459}
458 460
459static std::string GetTevStageConfigColorSourceString( 461static std::string GetTevStageConfigColorSourceString(
460 const Pica::Regs::TevStageConfig::Source& source, 462 const TexturingRegs::TevStageConfig::Source& source,
461 const Pica::Regs::TevStageConfig::ColorModifier modifier) { 463 const TexturingRegs::TevStageConfig::ColorModifier modifier) {
462 using ColorModifier = Pica::Regs::TevStageConfig::ColorModifier; 464
465 using ColorModifier = TexturingRegs::TevStageConfig::ColorModifier;
463 static const std::map<ColorModifier, std::string> color_modifier_map = { 466 static const std::map<ColorModifier, std::string> color_modifier_map = {
464 {ColorModifier::SourceColor, "%source.rgb"}, 467 {ColorModifier::SourceColor, "%source.rgb"},
465 {ColorModifier::OneMinusSourceColor, "(1.0 - %source.rgb)"}, 468 {ColorModifier::OneMinusSourceColor, "(1.0 - %source.rgb)"},
@@ -483,9 +486,10 @@ static std::string GetTevStageConfigColorSourceString(
483} 486}
484 487
485static std::string GetTevStageConfigAlphaSourceString( 488static std::string GetTevStageConfigAlphaSourceString(
486 const Pica::Regs::TevStageConfig::Source& source, 489 const TexturingRegs::TevStageConfig::Source& source,
487 const Pica::Regs::TevStageConfig::AlphaModifier modifier) { 490 const TexturingRegs::TevStageConfig::AlphaModifier modifier) {
488 using AlphaModifier = Pica::Regs::TevStageConfig::AlphaModifier; 491
492 using AlphaModifier = TexturingRegs::TevStageConfig::AlphaModifier;
489 static const std::map<AlphaModifier, std::string> alpha_modifier_map = { 493 static const std::map<AlphaModifier, std::string> alpha_modifier_map = {
490 {AlphaModifier::SourceAlpha, "%source.a"}, 494 {AlphaModifier::SourceAlpha, "%source.a"},
491 {AlphaModifier::OneMinusSourceAlpha, "(1.0 - %source.a)"}, 495 {AlphaModifier::OneMinusSourceAlpha, "(1.0 - %source.a)"},
@@ -507,8 +511,9 @@ static std::string GetTevStageConfigAlphaSourceString(
507} 511}
508 512
509static std::string GetTevStageConfigOperationString( 513static std::string GetTevStageConfigOperationString(
510 const Pica::Regs::TevStageConfig::Operation& operation) { 514 const TexturingRegs::TevStageConfig::Operation& operation) {
511 using Operation = Pica::Regs::TevStageConfig::Operation; 515
516 using Operation = TexturingRegs::TevStageConfig::Operation;
512 static const std::map<Operation, std::string> combiner_map = { 517 static const std::map<Operation, std::string> combiner_map = {
513 {Operation::Replace, "%source1"}, 518 {Operation::Replace, "%source1"},
514 {Operation::Modulate, "(%source1 * %source2)"}, 519 {Operation::Modulate, "(%source1 * %source2)"},
@@ -528,7 +533,7 @@ static std::string GetTevStageConfigOperationString(
528 return op_it->second; 533 return op_it->second;
529} 534}
530 535
531std::string GetTevStageConfigColorCombinerString(const Pica::Regs::TevStageConfig& tev_stage) { 536std::string GetTevStageConfigColorCombinerString(const TexturingRegs::TevStageConfig& tev_stage) {
532 auto op_str = GetTevStageConfigOperationString(tev_stage.color_op); 537 auto op_str = GetTevStageConfigOperationString(tev_stage.color_op);
533 op_str = ReplacePattern( 538 op_str = ReplacePattern(
534 op_str, "%source1", 539 op_str, "%source1",
@@ -541,7 +546,7 @@ std::string GetTevStageConfigColorCombinerString(const Pica::Regs::TevStageConfi
541 GetTevStageConfigColorSourceString(tev_stage.color_source3, tev_stage.color_modifier3)); 546 GetTevStageConfigColorSourceString(tev_stage.color_source3, tev_stage.color_modifier3));
542} 547}
543 548
544std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfig& tev_stage) { 549std::string GetTevStageConfigAlphaCombinerString(const TexturingRegs::TevStageConfig& tev_stage) {
545 auto op_str = GetTevStageConfigOperationString(tev_stage.alpha_op); 550 auto op_str = GetTevStageConfigOperationString(tev_stage.alpha_op);
546 op_str = ReplacePattern( 551 op_str = ReplacePattern(
547 op_str, "%source1", 552 op_str, "%source1",
@@ -554,7 +559,7 @@ std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfi
554 GetTevStageConfigAlphaSourceString(tev_stage.alpha_source3, tev_stage.alpha_modifier3)); 559 GetTevStageConfigAlphaSourceString(tev_stage.alpha_source3, tev_stage.alpha_modifier3));
555} 560}
556 561
557void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig, 6>& stages) { 562void DumpTevStageConfig(const std::array<TexturingRegs::TevStageConfig, 6>& stages) {
558 std::string stage_info = "Tev setup:\n"; 563 std::string stage_info = "Tev setup:\n";
559 for (size_t index = 0; index < stages.size(); ++index) { 564 for (size_t index = 0; index < stages.size(); ++index) {
560 const auto& tev_stage = stages[index]; 565 const auto& tev_stage = stages[index];
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index 938a2e1b5..fd94bdbb8 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -17,7 +17,7 @@
17#include <vector> 17#include <vector>
18#include "common/common_types.h" 18#include "common/common_types.h"
19#include "common/vector_math.h" 19#include "common/vector_math.h"
20#include "video_core/pica.h" 20#include "video_core/regs.h"
21 21
22namespace CiTrace { 22namespace CiTrace {
23class Recorder; 23class Recorder;
@@ -182,9 +182,9 @@ namespace DebugUtils {
182#define PICA_DUMP_TEXTURES 0 182#define PICA_DUMP_TEXTURES 0
183#define PICA_LOG_TEV 0 183#define PICA_LOG_TEV 0
184 184
185void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, 185void DumpShader(const std::string& filename, const ShaderRegs& config,
186 const Shader::ShaderSetup& setup, 186 const Shader::ShaderSetup& setup,
187 const Regs::VSOutputAttributes* output_attributes); 187 const RasterizerRegs::VSOutputAttributes* output_attributes);
188 188
189// Utility class to log Pica commands. 189// Utility class to log Pica commands.
190struct PicaTrace { 190struct PicaTrace {
@@ -205,13 +205,13 @@ inline bool IsPicaTracing() {
205void OnPicaRegWrite(PicaTrace::Write write); 205void OnPicaRegWrite(PicaTrace::Write write);
206std::unique_ptr<PicaTrace> FinishPicaTracing(); 206std::unique_ptr<PicaTrace> FinishPicaTracing();
207 207
208void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data); 208void DumpTexture(const TexturingRegs::TextureConfig& texture_config, u8* data);
209 209
210std::string GetTevStageConfigColorCombinerString(const Pica::Regs::TevStageConfig& tev_stage); 210std::string GetTevStageConfigColorCombinerString(const TexturingRegs::TevStageConfig& tev_stage);
211std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfig& tev_stage); 211std::string GetTevStageConfigAlphaCombinerString(const TexturingRegs::TevStageConfig& tev_stage);
212 212
213/// Dumps the Tev stage config to log at trace level 213/// Dumps the Tev stage config to log at trace level
214void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig, 6>& stages); 214void DumpTevStageConfig(const std::array<TexturingRegs::TevStageConfig, 6>& stages);
215 215
216/** 216/**
217 * Used in the vertex loader to merge access records. TODO: Investigate if actually useful. 217 * Used in the vertex loader to merge access records. TODO: Investigate if actually useful.
diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp
index b4a77c632..13f0a4ab9 100644
--- a/src/video_core/pica.cpp
+++ b/src/video_core/pica.cpp
@@ -3,497 +3,14 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring> 5#include <cstring>
6#include <iterator>
7#include <unordered_map>
8#include <utility>
9#include "video_core/pica.h" 6#include "video_core/pica.h"
10#include "video_core/pica_state.h" 7#include "video_core/pica_state.h"
11#include "video_core/primitive_assembly.h" 8#include "video_core/regs.h"
12#include "video_core/shader/shader.h"
13 9
14namespace Pica { 10namespace Pica {
15 11
16State g_state; 12State g_state;
17 13
18static const std::pair<u16, const char*> register_names[] = {
19 {0x010, "GPUREG_FINALIZE"},
20
21 {0x040, "GPUREG_FACECULLING_CONFIG"},
22 {0x041, "GPUREG_VIEWPORT_WIDTH"},
23 {0x042, "GPUREG_VIEWPORT_INVW"},
24 {0x043, "GPUREG_VIEWPORT_HEIGHT"},
25 {0x044, "GPUREG_VIEWPORT_INVH"},
26
27 {0x047, "GPUREG_FRAGOP_CLIP"},
28 {0x048, "GPUREG_FRAGOP_CLIP_DATA0"},
29 {0x049, "GPUREG_FRAGOP_CLIP_DATA1"},
30 {0x04A, "GPUREG_FRAGOP_CLIP_DATA2"},
31 {0x04B, "GPUREG_FRAGOP_CLIP_DATA3"},
32
33 {0x04D, "GPUREG_DEPTHMAP_SCALE"},
34 {0x04E, "GPUREG_DEPTHMAP_OFFSET"},
35 {0x04F, "GPUREG_SH_OUTMAP_TOTAL"},
36 {0x050, "GPUREG_SH_OUTMAP_O0"},
37 {0x051, "GPUREG_SH_OUTMAP_O1"},
38 {0x052, "GPUREG_SH_OUTMAP_O2"},
39 {0x053, "GPUREG_SH_OUTMAP_O3"},
40 {0x054, "GPUREG_SH_OUTMAP_O4"},
41 {0x055, "GPUREG_SH_OUTMAP_O5"},
42 {0x056, "GPUREG_SH_OUTMAP_O6"},
43
44 {0x061, "GPUREG_EARLYDEPTH_FUNC"},
45 {0x062, "GPUREG_EARLYDEPTH_TEST1"},
46 {0x063, "GPUREG_EARLYDEPTH_CLEAR"},
47 {0x064, "GPUREG_SH_OUTATTR_MODE"},
48 {0x065, "GPUREG_SCISSORTEST_MODE"},
49 {0x066, "GPUREG_SCISSORTEST_POS"},
50 {0x067, "GPUREG_SCISSORTEST_DIM"},
51 {0x068, "GPUREG_VIEWPORT_XY"},
52
53 {0x06A, "GPUREG_EARLYDEPTH_DATA"},
54
55 {0x06D, "GPUREG_DEPTHMAP_ENABLE"},
56 {0x06E, "GPUREG_RENDERBUF_DIM"},
57 {0x06F, "GPUREG_SH_OUTATTR_CLOCK"},
58
59 {0x080, "GPUREG_TEXUNIT_CONFIG"},
60 {0x081, "GPUREG_TEXUNIT0_BORDER_COLOR"},
61 {0x082, "GPUREG_TEXUNIT0_DIM"},
62 {0x083, "GPUREG_TEXUNIT0_PARAM"},
63 {0x084, "GPUREG_TEXUNIT0_LOD"},
64 {0x085, "GPUREG_TEXUNIT0_ADDR1"},
65 {0x086, "GPUREG_TEXUNIT0_ADDR2"},
66 {0x087, "GPUREG_TEXUNIT0_ADDR3"},
67 {0x088, "GPUREG_TEXUNIT0_ADDR4"},
68 {0x089, "GPUREG_TEXUNIT0_ADDR5"},
69 {0x08A, "GPUREG_TEXUNIT0_ADDR6"},
70 {0x08B, "GPUREG_TEXUNIT0_SHADOW"},
71
72 {0x08E, "GPUREG_TEXUNIT0_TYPE"},
73 {0x08F, "GPUREG_LIGHTING_ENABLE0"},
74
75 {0x091, "GPUREG_TEXUNIT1_BORDER_COLOR"},
76 {0x092, "GPUREG_TEXUNIT1_DIM"},
77 {0x093, "GPUREG_TEXUNIT1_PARAM"},
78 {0x094, "GPUREG_TEXUNIT1_LOD"},
79 {0x095, "GPUREG_TEXUNIT1_ADDR"},
80 {0x096, "GPUREG_TEXUNIT1_TYPE"},
81
82 {0x099, "GPUREG_TEXUNIT2_BORDER_COLOR"},
83 {0x09A, "GPUREG_TEXUNIT2_DIM"},
84 {0x09B, "GPUREG_TEXUNIT2_PARAM"},
85 {0x09C, "GPUREG_TEXUNIT2_LOD"},
86 {0x09D, "GPUREG_TEXUNIT2_ADDR"},
87 {0x09E, "GPUREG_TEXUNIT2_TYPE"},
88
89 {0x0A8, "GPUREG_TEXUNIT3_PROCTEX0"},
90 {0x0A9, "GPUREG_TEXUNIT3_PROCTEX1"},
91 {0x0AA, "GPUREG_TEXUNIT3_PROCTEX2"},
92 {0x0AB, "GPUREG_TEXUNIT3_PROCTEX3"},
93 {0x0AC, "GPUREG_TEXUNIT3_PROCTEX4"},
94 {0x0AD, "GPUREG_TEXUNIT3_PROCTEX5"},
95
96 {0x0AF, "GPUREG_PROCTEX_LUT"},
97 {0x0B0, "GPUREG_PROCTEX_LUT_DATA0"},
98 {0x0B1, "GPUREG_PROCTEX_LUT_DATA1"},
99 {0x0B2, "GPUREG_PROCTEX_LUT_DATA2"},
100 {0x0B3, "GPUREG_PROCTEX_LUT_DATA3"},
101 {0x0B4, "GPUREG_PROCTEX_LUT_DATA4"},
102 {0x0B5, "GPUREG_PROCTEX_LUT_DATA5"},
103 {0x0B6, "GPUREG_PROCTEX_LUT_DATA6"},
104 {0x0B7, "GPUREG_PROCTEX_LUT_DATA7"},
105
106 {0x0C0, "GPUREG_TEXENV0_SOURCE"},
107 {0x0C1, "GPUREG_TEXENV0_OPERAND"},
108 {0x0C2, "GPUREG_TEXENV0_COMBINER"},
109 {0x0C3, "GPUREG_TEXENV0_COLOR"},
110 {0x0C4, "GPUREG_TEXENV0_SCALE"},
111
112 {0x0C8, "GPUREG_TEXENV1_SOURCE"},
113 {0x0C9, "GPUREG_TEXENV1_OPERAND"},
114 {0x0CA, "GPUREG_TEXENV1_COMBINER"},
115 {0x0CB, "GPUREG_TEXENV1_COLOR"},
116 {0x0CC, "GPUREG_TEXENV1_SCALE"},
117
118 {0x0D0, "GPUREG_TEXENV2_SOURCE"},
119 {0x0D1, "GPUREG_TEXENV2_OPERAND"},
120 {0x0D2, "GPUREG_TEXENV2_COMBINER"},
121 {0x0D3, "GPUREG_TEXENV2_COLOR"},
122 {0x0D4, "GPUREG_TEXENV2_SCALE"},
123
124 {0x0D8, "GPUREG_TEXENV3_SOURCE"},
125 {0x0D9, "GPUREG_TEXENV3_OPERAND"},
126 {0x0DA, "GPUREG_TEXENV3_COMBINER"},
127 {0x0DB, "GPUREG_TEXENV3_COLOR"},
128 {0x0DC, "GPUREG_TEXENV3_SCALE"},
129
130 {0x0E0, "GPUREG_TEXENV_UPDATE_BUFFER"},
131 {0x0E1, "GPUREG_FOG_COLOR"},
132
133 {0x0E4, "GPUREG_GAS_ATTENUATION"},
134 {0x0E5, "GPUREG_GAS_ACCMAX"},
135 {0x0E6, "GPUREG_FOG_LUT_INDEX"},
136
137 {0x0E8, "GPUREG_FOG_LUT_DATA0"},
138 {0x0E9, "GPUREG_FOG_LUT_DATA1"},
139 {0x0EA, "GPUREG_FOG_LUT_DATA2"},
140 {0x0EB, "GPUREG_FOG_LUT_DATA3"},
141 {0x0EC, "GPUREG_FOG_LUT_DATA4"},
142 {0x0ED, "GPUREG_FOG_LUT_DATA5"},
143 {0x0EE, "GPUREG_FOG_LUT_DATA6"},
144 {0x0EF, "GPUREG_FOG_LUT_DATA7"},
145 {0x0F0, "GPUREG_TEXENV4_SOURCE"},
146 {0x0F1, "GPUREG_TEXENV4_OPERAND"},
147 {0x0F2, "GPUREG_TEXENV4_COMBINER"},
148 {0x0F3, "GPUREG_TEXENV4_COLOR"},
149 {0x0F4, "GPUREG_TEXENV4_SCALE"},
150
151 {0x0F8, "GPUREG_TEXENV5_SOURCE"},
152 {0x0F9, "GPUREG_TEXENV5_OPERAND"},
153 {0x0FA, "GPUREG_TEXENV5_COMBINER"},
154 {0x0FB, "GPUREG_TEXENV5_COLOR"},
155 {0x0FC, "GPUREG_TEXENV5_SCALE"},
156 {0x0FD, "GPUREG_TEXENV_BUFFER_COLOR"},
157
158 {0x100, "GPUREG_COLOR_OPERATION"},
159 {0x101, "GPUREG_BLEND_FUNC"},
160 {0x102, "GPUREG_LOGIC_OP"},
161 {0x103, "GPUREG_BLEND_COLOR"},
162 {0x104, "GPUREG_FRAGOP_ALPHA_TEST"},
163 {0x105, "GPUREG_STENCIL_TEST"},
164 {0x106, "GPUREG_STENCIL_OP"},
165 {0x107, "GPUREG_DEPTH_COLOR_MASK"},
166
167 {0x110, "GPUREG_FRAMEBUFFER_INVALIDATE"},
168 {0x111, "GPUREG_FRAMEBUFFER_FLUSH"},
169 {0x112, "GPUREG_COLORBUFFER_READ"},
170 {0x113, "GPUREG_COLORBUFFER_WRITE"},
171 {0x114, "GPUREG_DEPTHBUFFER_READ"},
172 {0x115, "GPUREG_DEPTHBUFFER_WRITE"},
173 {0x116, "GPUREG_DEPTHBUFFER_FORMAT"},
174 {0x117, "GPUREG_COLORBUFFER_FORMAT"},
175 {0x118, "GPUREG_EARLYDEPTH_TEST2"},
176
177 {0x11B, "GPUREG_FRAMEBUFFER_BLOCK32"},
178 {0x11C, "GPUREG_DEPTHBUFFER_LOC"},
179 {0x11D, "GPUREG_COLORBUFFER_LOC"},
180 {0x11E, "GPUREG_FRAMEBUFFER_DIM"},
181
182 {0x120, "GPUREG_GAS_LIGHT_XY"},
183 {0x121, "GPUREG_GAS_LIGHT_Z"},
184 {0x122, "GPUREG_GAS_LIGHT_Z_COLOR"},
185 {0x123, "GPUREG_GAS_LUT_INDEX"},
186 {0x124, "GPUREG_GAS_LUT_DATA"},
187
188 {0x126, "GPUREG_GAS_DELTAZ_DEPTH"},
189
190 {0x130, "GPUREG_FRAGOP_SHADOW"},
191
192 {0x140, "GPUREG_LIGHT0_SPECULAR0"},
193 {0x141, "GPUREG_LIGHT0_SPECULAR1"},
194 {0x142, "GPUREG_LIGHT0_DIFFUSE"},
195 {0x143, "GPUREG_LIGHT0_AMBIENT"},
196 {0x144, "GPUREG_LIGHT0_XY"},
197 {0x145, "GPUREG_LIGHT0_Z"},
198 {0x146, "GPUREG_LIGHT0_SPOTDIR_XY"},
199 {0x147, "GPUREG_LIGHT0_SPOTDIR_Z"},
200
201 {0x149, "GPUREG_LIGHT0_CONFIG"},
202 {0x14A, "GPUREG_LIGHT0_ATTENUATION_BIAS"},
203 {0x14B, "GPUREG_LIGHT0_ATTENUATION_SCALE"},
204
205 {0x150, "GPUREG_LIGHT1_SPECULAR0"},
206 {0x151, "GPUREG_LIGHT1_SPECULAR1"},
207 {0x152, "GPUREG_LIGHT1_DIFFUSE"},
208 {0x153, "GPUREG_LIGHT1_AMBIENT"},
209 {0x154, "GPUREG_LIGHT1_XY"},
210 {0x155, "GPUREG_LIGHT1_Z"},
211 {0x156, "GPUREG_LIGHT1_SPOTDIR_XY"},
212 {0x157, "GPUREG_LIGHT1_SPOTDIR_Z"},
213
214 {0x159, "GPUREG_LIGHT1_CONFIG"},
215 {0x15A, "GPUREG_LIGHT1_ATTENUATION_BIAS"},
216 {0x15B, "GPUREG_LIGHT1_ATTENUATION_SCALE"},
217
218 {0x160, "GPUREG_LIGHT2_SPECULAR0"},
219 {0x161, "GPUREG_LIGHT2_SPECULAR1"},
220 {0x162, "GPUREG_LIGHT2_DIFFUSE"},
221 {0x163, "GPUREG_LIGHT2_AMBIENT"},
222 {0x164, "GPUREG_LIGHT2_XY"},
223 {0x165, "GPUREG_LIGHT2_Z"},
224 {0x166, "GPUREG_LIGHT2_SPOTDIR_XY"},
225 {0x167, "GPUREG_LIGHT2_SPOTDIR_Z"},
226
227 {0x169, "GPUREG_LIGHT2_CONFIG"},
228 {0x16A, "GPUREG_LIGHT2_ATTENUATION_BIAS"},
229 {0x16B, "GPUREG_LIGHT2_ATTENUATION_SCALE"},
230
231 {0x170, "GPUREG_LIGHT3_SPECULAR0"},
232 {0x171, "GPUREG_LIGHT3_SPECULAR1"},
233 {0x172, "GPUREG_LIGHT3_DIFFUSE"},
234 {0x173, "GPUREG_LIGHT3_AMBIENT"},
235 {0x174, "GPUREG_LIGHT3_XY"},
236 {0x175, "GPUREG_LIGHT3_Z"},
237 {0x176, "GPUREG_LIGHT3_SPOTDIR_XY"},
238 {0x177, "GPUREG_LIGHT3_SPOTDIR_Z"},
239
240 {0x179, "GPUREG_LIGHT3_CONFIG"},
241 {0x17A, "GPUREG_LIGHT3_ATTENUATION_BIAS"},
242 {0x17B, "GPUREG_LIGHT3_ATTENUATION_SCALE"},
243
244 {0x180, "GPUREG_LIGHT4_SPECULAR0"},
245 {0x181, "GPUREG_LIGHT4_SPECULAR1"},
246 {0x182, "GPUREG_LIGHT4_DIFFUSE"},
247 {0x183, "GPUREG_LIGHT4_AMBIENT"},
248 {0x184, "GPUREG_LIGHT4_XY"},
249 {0x185, "GPUREG_LIGHT4_Z"},
250 {0x186, "GPUREG_LIGHT4_SPOTDIR_XY"},
251 {0x187, "GPUREG_LIGHT4_SPOTDIR_Z"},
252
253 {0x189, "GPUREG_LIGHT4_CONFIG"},
254 {0x18A, "GPUREG_LIGHT4_ATTENUATION_BIAS"},
255 {0x18B, "GPUREG_LIGHT4_ATTENUATION_SCALE"},
256
257 {0x190, "GPUREG_LIGHT5_SPECULAR0"},
258 {0x191, "GPUREG_LIGHT5_SPECULAR1"},
259 {0x192, "GPUREG_LIGHT5_DIFFUSE"},
260 {0x193, "GPUREG_LIGHT5_AMBIENT"},
261 {0x194, "GPUREG_LIGHT5_XY"},
262 {0x195, "GPUREG_LIGHT5_Z"},
263 {0x196, "GPUREG_LIGHT5_SPOTDIR_XY"},
264 {0x197, "GPUREG_LIGHT5_SPOTDIR_Z"},
265
266 {0x199, "GPUREG_LIGHT5_CONFIG"},
267 {0x19A, "GPUREG_LIGHT5_ATTENUATION_BIAS"},
268 {0x19B, "GPUREG_LIGHT5_ATTENUATION_SCALE"},
269
270 {0x1A0, "GPUREG_LIGHT6_SPECULAR0"},
271 {0x1A1, "GPUREG_LIGHT6_SPECULAR1"},
272 {0x1A2, "GPUREG_LIGHT6_DIFFUSE"},
273 {0x1A3, "GPUREG_LIGHT6_AMBIENT"},
274 {0x1A4, "GPUREG_LIGHT6_XY"},
275 {0x1A5, "GPUREG_LIGHT6_Z"},
276 {0x1A6, "GPUREG_LIGHT6_SPOTDIR_XY"},
277 {0x1A7, "GPUREG_LIGHT6_SPOTDIR_Z"},
278
279 {0x1A9, "GPUREG_LIGHT6_CONFIG"},
280 {0x1AA, "GPUREG_LIGHT6_ATTENUATION_BIAS"},
281 {0x1AB, "GPUREG_LIGHT6_ATTENUATION_SCALE"},
282
283 {0x1B0, "GPUREG_LIGHT7_SPECULAR0"},
284 {0x1B1, "GPUREG_LIGHT7_SPECULAR1"},
285 {0x1B2, "GPUREG_LIGHT7_DIFFUSE"},
286 {0x1B3, "GPUREG_LIGHT7_AMBIENT"},
287 {0x1B4, "GPUREG_LIGHT7_XY"},
288 {0x1B5, "GPUREG_LIGHT7_Z"},
289 {0x1B6, "GPUREG_LIGHT7_SPOTDIR_XY"},
290 {0x1B7, "GPUREG_LIGHT7_SPOTDIR_Z"},
291
292 {0x1B9, "GPUREG_LIGHT7_CONFIG"},
293 {0x1BA, "GPUREG_LIGHT7_ATTENUATION_BIAS"},
294 {0x1BB, "GPUREG_LIGHT7_ATTENUATION_SCALE"},
295
296 {0x1C0, "GPUREG_LIGHTING_AMBIENT"},
297
298 {0x1C2, "GPUREG_LIGHTING_NUM_LIGHTS"},
299 {0x1C3, "GPUREG_LIGHTING_CONFIG0"},
300 {0x1C4, "GPUREG_LIGHTING_CONFIG1"},
301 {0x1C5, "GPUREG_LIGHTING_LUT_INDEX"},
302 {0x1C6, "GPUREG_LIGHTING_ENABLE1"},
303
304 {0x1C8, "GPUREG_LIGHTING_LUT_DATA0"},
305 {0x1C9, "GPUREG_LIGHTING_LUT_DATA1"},
306 {0x1CA, "GPUREG_LIGHTING_LUT_DATA2"},
307 {0x1CB, "GPUREG_LIGHTING_LUT_DATA3"},
308 {0x1CC, "GPUREG_LIGHTING_LUT_DATA4"},
309 {0x1CD, "GPUREG_LIGHTING_LUT_DATA5"},
310 {0x1CE, "GPUREG_LIGHTING_LUT_DATA6"},
311 {0x1CF, "GPUREG_LIGHTING_LUT_DATA7"},
312 {0x1D0, "GPUREG_LIGHTING_LUTINPUT_ABS"},
313 {0x1D1, "GPUREG_LIGHTING_LUTINPUT_SELECT"},
314 {0x1D2, "GPUREG_LIGHTING_LUTINPUT_SCALE"},
315
316 {0x1D9, "GPUREG_LIGHTING_LIGHT_PERMUTATION"},
317
318 {0x200, "GPUREG_ATTRIBBUFFERS_LOC"},
319 {0x201, "GPUREG_ATTRIBBUFFERS_FORMAT_LOW"},
320 {0x202, "GPUREG_ATTRIBBUFFERS_FORMAT_HIGH"},
321 {0x203, "GPUREG_ATTRIBBUFFER0_OFFSET"},
322 {0x204, "GPUREG_ATTRIBBUFFER0_CONFIG1"},
323 {0x205, "GPUREG_ATTRIBBUFFER0_CONFIG2"},
324 {0x206, "GPUREG_ATTRIBBUFFER1_OFFSET"},
325 {0x207, "GPUREG_ATTRIBBUFFER1_CONFIG1"},
326 {0x208, "GPUREG_ATTRIBBUFFER1_CONFIG2"},
327 {0x209, "GPUREG_ATTRIBBUFFER2_OFFSET"},
328 {0x20A, "GPUREG_ATTRIBBUFFER2_CONFIG1"},
329 {0x20B, "GPUREG_ATTRIBBUFFER2_CONFIG2"},
330 {0x20C, "GPUREG_ATTRIBBUFFER3_OFFSET"},
331 {0x20D, "GPUREG_ATTRIBBUFFER3_CONFIG1"},
332 {0x20E, "GPUREG_ATTRIBBUFFER3_CONFIG2"},
333 {0x20F, "GPUREG_ATTRIBBUFFER4_OFFSET"},
334 {0x210, "GPUREG_ATTRIBBUFFER4_CONFIG1"},
335 {0x211, "GPUREG_ATTRIBBUFFER4_CONFIG2"},
336 {0x212, "GPUREG_ATTRIBBUFFER5_OFFSET"},
337 {0x213, "GPUREG_ATTRIBBUFFER5_CONFIG1"},
338 {0x214, "GPUREG_ATTRIBBUFFER5_CONFIG2"},
339 {0x215, "GPUREG_ATTRIBBUFFER6_OFFSET"},
340 {0x216, "GPUREG_ATTRIBBUFFER6_CONFIG1"},
341 {0x217, "GPUREG_ATTRIBBUFFER6_CONFIG2"},
342 {0x218, "GPUREG_ATTRIBBUFFER7_OFFSET"},
343 {0x219, "GPUREG_ATTRIBBUFFER7_CONFIG1"},
344 {0x21A, "GPUREG_ATTRIBBUFFER7_CONFIG2"},
345 {0x21B, "GPUREG_ATTRIBBUFFER8_OFFSET"},
346 {0x21C, "GPUREG_ATTRIBBUFFER8_CONFIG1"},
347 {0x21D, "GPUREG_ATTRIBBUFFER8_CONFIG2"},
348 {0x21E, "GPUREG_ATTRIBBUFFER9_OFFSET"},
349 {0x21F, "GPUREG_ATTRIBBUFFER9_CONFIG1"},
350 {0x220, "GPUREG_ATTRIBBUFFER9_CONFIG2"},
351 {0x221, "GPUREG_ATTRIBBUFFER10_OFFSET"},
352 {0x222, "GPUREG_ATTRIBBUFFER10_CONFIG1"},
353 {0x223, "GPUREG_ATTRIBBUFFER10_CONFIG2"},
354 {0x224, "GPUREG_ATTRIBBUFFER11_OFFSET"},
355 {0x225, "GPUREG_ATTRIBBUFFER11_CONFIG1"},
356 {0x226, "GPUREG_ATTRIBBUFFER11_CONFIG2"},
357 {0x227, "GPUREG_INDEXBUFFER_CONFIG"},
358 {0x228, "GPUREG_NUMVERTICES"},
359 {0x229, "GPUREG_GEOSTAGE_CONFIG"},
360 {0x22A, "GPUREG_VERTEX_OFFSET"},
361
362 {0x22D, "GPUREG_POST_VERTEX_CACHE_NUM"},
363 {0x22E, "GPUREG_DRAWARRAYS"},
364 {0x22F, "GPUREG_DRAWELEMENTS"},
365
366 {0x231, "GPUREG_VTX_FUNC"},
367 {0x232, "GPUREG_FIXEDATTRIB_INDEX"},
368 {0x233, "GPUREG_FIXEDATTRIB_DATA0"},
369 {0x234, "GPUREG_FIXEDATTRIB_DATA1"},
370 {0x235, "GPUREG_FIXEDATTRIB_DATA2"},
371
372 {0x238, "GPUREG_CMDBUF_SIZE0"},
373 {0x239, "GPUREG_CMDBUF_SIZE1"},
374 {0x23A, "GPUREG_CMDBUF_ADDR0"},
375 {0x23B, "GPUREG_CMDBUF_ADDR1"},
376 {0x23C, "GPUREG_CMDBUF_JUMP0"},
377 {0x23D, "GPUREG_CMDBUF_JUMP1"},
378
379 {0x242, "GPUREG_VSH_NUM_ATTR"},
380
381 {0x244, "GPUREG_VSH_COM_MODE"},
382 {0x245, "GPUREG_START_DRAW_FUNC0"},
383
384 {0x24A, "GPUREG_VSH_OUTMAP_TOTAL1"},
385
386 {0x251, "GPUREG_VSH_OUTMAP_TOTAL2"},
387 {0x252, "GPUREG_GSH_MISC0"},
388 {0x253, "GPUREG_GEOSTAGE_CONFIG2"},
389 {0x254, "GPUREG_GSH_MISC1"},
390
391 {0x25E, "GPUREG_PRIMITIVE_CONFIG"},
392 {0x25F, "GPUREG_RESTART_PRIMITIVE"},
393
394 {0x280, "GPUREG_GSH_BOOLUNIFORM"},
395 {0x281, "GPUREG_GSH_INTUNIFORM_I0"},
396 {0x282, "GPUREG_GSH_INTUNIFORM_I1"},
397 {0x283, "GPUREG_GSH_INTUNIFORM_I2"},
398 {0x284, "GPUREG_GSH_INTUNIFORM_I3"},
399
400 {0x289, "GPUREG_GSH_INPUTBUFFER_CONFIG"},
401 {0x28A, "GPUREG_GSH_ENTRYPOINT"},
402 {0x28B, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_LOW"},
403 {0x28C, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_HIGH"},
404 {0x28D, "GPUREG_GSH_OUTMAP_MASK"},
405
406 {0x28F, "GPUREG_GSH_CODETRANSFER_END"},
407 {0x290, "GPUREG_GSH_FLOATUNIFORM_INDEX"},
408 {0x291, "GPUREG_GSH_FLOATUNIFORM_DATA0"},
409 {0x292, "GPUREG_GSH_FLOATUNIFORM_DATA1"},
410 {0x293, "GPUREG_GSH_FLOATUNIFORM_DATA2"},
411 {0x294, "GPUREG_GSH_FLOATUNIFORM_DATA3"},
412 {0x295, "GPUREG_GSH_FLOATUNIFORM_DATA4"},
413 {0x296, "GPUREG_GSH_FLOATUNIFORM_DATA5"},
414 {0x297, "GPUREG_GSH_FLOATUNIFORM_DATA6"},
415 {0x298, "GPUREG_GSH_FLOATUNIFORM_DATA7"},
416
417 {0x29B, "GPUREG_GSH_CODETRANSFER_INDEX"},
418 {0x29C, "GPUREG_GSH_CODETRANSFER_DATA0"},
419 {0x29D, "GPUREG_GSH_CODETRANSFER_DATA1"},
420 {0x29E, "GPUREG_GSH_CODETRANSFER_DATA2"},
421 {0x29F, "GPUREG_GSH_CODETRANSFER_DATA3"},
422 {0x2A0, "GPUREG_GSH_CODETRANSFER_DATA4"},
423 {0x2A1, "GPUREG_GSH_CODETRANSFER_DATA5"},
424 {0x2A2, "GPUREG_GSH_CODETRANSFER_DATA6"},
425 {0x2A3, "GPUREG_GSH_CODETRANSFER_DATA7"},
426
427 {0x2A5, "GPUREG_GSH_OPDESCS_INDEX"},
428 {0x2A6, "GPUREG_GSH_OPDESCS_DATA0"},
429 {0x2A7, "GPUREG_GSH_OPDESCS_DATA1"},
430 {0x2A8, "GPUREG_GSH_OPDESCS_DATA2"},
431 {0x2A9, "GPUREG_GSH_OPDESCS_DATA3"},
432 {0x2AA, "GPUREG_GSH_OPDESCS_DATA4"},
433 {0x2AB, "GPUREG_GSH_OPDESCS_DATA5"},
434 {0x2AC, "GPUREG_GSH_OPDESCS_DATA6"},
435 {0x2AD, "GPUREG_GSH_OPDESCS_DATA7"},
436
437 {0x2B0, "GPUREG_VSH_BOOLUNIFORM"},
438 {0x2B1, "GPUREG_VSH_INTUNIFORM_I0"},
439 {0x2B2, "GPUREG_VSH_INTUNIFORM_I1"},
440 {0x2B3, "GPUREG_VSH_INTUNIFORM_I2"},
441 {0x2B4, "GPUREG_VSH_INTUNIFORM_I3"},
442
443 {0x2B9, "GPUREG_VSH_INPUTBUFFER_CONFIG"},
444 {0x2BA, "GPUREG_VSH_ENTRYPOINT"},
445 {0x2BB, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW"},
446 {0x2BC, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_HIGH"},
447 {0x2BD, "GPUREG_VSH_OUTMAP_MASK"},
448
449 {0x2BF, "GPUREG_VSH_CODETRANSFER_END"},
450 {0x2C0, "GPUREG_VSH_FLOATUNIFORM_INDEX"},
451 {0x2C1, "GPUREG_VSH_FLOATUNIFORM_DATA0"},
452 {0x2C2, "GPUREG_VSH_FLOATUNIFORM_DATA1"},
453 {0x2C3, "GPUREG_VSH_FLOATUNIFORM_DATA2"},
454 {0x2C4, "GPUREG_VSH_FLOATUNIFORM_DATA3"},
455 {0x2C5, "GPUREG_VSH_FLOATUNIFORM_DATA4"},
456 {0x2C6, "GPUREG_VSH_FLOATUNIFORM_DATA5"},
457 {0x2C7, "GPUREG_VSH_FLOATUNIFORM_DATA6"},
458 {0x2C8, "GPUREG_VSH_FLOATUNIFORM_DATA7"},
459
460 {0x2CB, "GPUREG_VSH_CODETRANSFER_INDEX"},
461 {0x2CC, "GPUREG_VSH_CODETRANSFER_DATA0"},
462 {0x2CD, "GPUREG_VSH_CODETRANSFER_DATA1"},
463 {0x2CE, "GPUREG_VSH_CODETRANSFER_DATA2"},
464 {0x2CF, "GPUREG_VSH_CODETRANSFER_DATA3"},
465 {0x2D0, "GPUREG_VSH_CODETRANSFER_DATA4"},
466 {0x2D1, "GPUREG_VSH_CODETRANSFER_DATA5"},
467 {0x2D2, "GPUREG_VSH_CODETRANSFER_DATA6"},
468 {0x2D3, "GPUREG_VSH_CODETRANSFER_DATA7"},
469
470 {0x2D5, "GPUREG_VSH_OPDESCS_INDEX"},
471 {0x2D6, "GPUREG_VSH_OPDESCS_DATA0"},
472 {0x2D7, "GPUREG_VSH_OPDESCS_DATA1"},
473 {0x2D8, "GPUREG_VSH_OPDESCS_DATA2"},
474 {0x2D9, "GPUREG_VSH_OPDESCS_DATA3"},
475 {0x2DA, "GPUREG_VSH_OPDESCS_DATA4"},
476 {0x2DB, "GPUREG_VSH_OPDESCS_DATA5"},
477 {0x2DC, "GPUREG_VSH_OPDESCS_DATA6"},
478 {0x2DD, "GPUREG_VSH_OPDESCS_DATA7"},
479};
480
481std::string Regs::GetCommandName(int index) {
482 static std::unordered_map<u32, const char*> map;
483
484 if (map.empty()) {
485 map.insert(std::begin(register_names), std::end(register_names));
486 }
487
488 // Return empty string if no match is found
489 auto it = map.find(index);
490 if (it != map.end()) {
491 return it->second;
492 } else {
493 return std::string();
494 }
495}
496
497void Init() { 14void Init() {
498 g_state.Reset(); 15 g_state.Reset();
499} 16}
@@ -513,6 +30,6 @@ void State::Reset() {
513 Zero(gs); 30 Zero(gs);
514 Zero(cmd_list); 31 Zero(cmd_list);
515 Zero(immediate); 32 Zero(immediate);
516 primitive_assembler.Reconfigure(Regs::TriangleTopology::List); 33 primitive_assembler.Reconfigure(PipelineRegs::TriangleTopology::List);
517} 34}
518} 35}
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 731540b99..dc8aa6670 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -4,1400 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array> 7#include "video_core/regs_texturing.h"
8#include <cstddef>
9#include <string>
10
11#ifndef _MSC_VER
12#include <type_traits> // for std::enable_if
13#endif
14
15#include "common/assert.h"
16#include "common/bit_field.h"
17#include "common/common_funcs.h"
18#include "common/common_types.h"
19#include "common/logging/log.h"
20#include "common/vector_math.h"
21
22namespace Pica { 8namespace Pica {
23 9
24// Returns index corresponding to the Regs member labeled by field_name
25// TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions
26// when used with array elements (e.g. PICA_REG_INDEX(vs_uniform_setup.set_value[1])).
27// For details cf.
28// https://connect.microsoft.com/VisualStudio/feedback/details/209229/offsetof-does-not-produce-a-constant-expression-for-array-members
29// Hopefully, this will be fixed sometime in the future.
30// For lack of better alternatives, we currently hardcode the offsets when constant
31// expressions are needed via PICA_REG_INDEX_WORKAROUND (on sane compilers, static_asserts
32// will then make sure the offsets indeed match the automatically calculated ones).
33#define PICA_REG_INDEX(field_name) (offsetof(Pica::Regs, field_name) / sizeof(u32))
34#if defined(_MSC_VER)
35#define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) (backup_workaround_index)
36#else
37// NOTE: Yeah, hacking in a static_assert here just to workaround the lacking MSVC compiler
38// really is this annoying. This macro just forwards its first argument to PICA_REG_INDEX
39// and then performs a (no-op) cast to size_t iff the second argument matches the expected
40// field offset. Otherwise, the compiler will fail to compile this code.
41#define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) \
42 ((typename std::enable_if<backup_workaround_index == PICA_REG_INDEX(field_name), \
43 size_t>::type)PICA_REG_INDEX(field_name))
44#endif // _MSC_VER
45
46struct Regs {
47
48 INSERT_PADDING_WORDS(0x10);
49
50 u32 trigger_irq;
51
52 INSERT_PADDING_WORDS(0x2f);
53
54 enum class CullMode : u32 {
55 // Select which polygons are considered to be "frontfacing".
56 KeepAll = 0,
57 KeepClockWise = 1,
58 KeepCounterClockWise = 2,
59 // TODO: What does the third value imply?
60 };
61
62 union {
63 BitField<0, 2, CullMode> cull_mode;
64 };
65
66 BitField<0, 24, u32> viewport_size_x;
67
68 INSERT_PADDING_WORDS(0x1);
69
70 BitField<0, 24, u32> viewport_size_y;
71
72 INSERT_PADDING_WORDS(0x9);
73
74 BitField<0, 24, u32> viewport_depth_range; // float24
75 BitField<0, 24, u32> viewport_depth_near_plane; // float24
76
77 BitField<0, 3, u32> vs_output_total;
78
79 union VSOutputAttributes {
80 // Maps components of output vertex attributes to semantics
81 enum Semantic : u32 {
82 POSITION_X = 0,
83 POSITION_Y = 1,
84 POSITION_Z = 2,
85 POSITION_W = 3,
86
87 QUATERNION_X = 4,
88 QUATERNION_Y = 5,
89 QUATERNION_Z = 6,
90 QUATERNION_W = 7,
91
92 COLOR_R = 8,
93 COLOR_G = 9,
94 COLOR_B = 10,
95 COLOR_A = 11,
96
97 TEXCOORD0_U = 12,
98 TEXCOORD0_V = 13,
99 TEXCOORD1_U = 14,
100 TEXCOORD1_V = 15,
101
102 TEXCOORD0_W = 16,
103
104 VIEW_X = 18,
105 VIEW_Y = 19,
106 VIEW_Z = 20,
107
108 TEXCOORD2_U = 22,
109 TEXCOORD2_V = 23,
110
111 INVALID = 31,
112 };
113
114 BitField<0, 5, Semantic> map_x;
115 BitField<8, 5, Semantic> map_y;
116 BitField<16, 5, Semantic> map_z;
117 BitField<24, 5, Semantic> map_w;
118 } vs_output_attributes[7];
119
120 INSERT_PADDING_WORDS(0xe);
121
122 enum class ScissorMode : u32 {
123 Disabled = 0,
124 Exclude = 1, // Exclude pixels inside the scissor box
125
126 Include = 3 // Exclude pixels outside the scissor box
127 };
128
129 struct {
130 BitField<0, 2, ScissorMode> mode;
131
132 union {
133 BitField<0, 16, u32> x1;
134 BitField<16, 16, u32> y1;
135 };
136
137 union {
138 BitField<0, 16, u32> x2;
139 BitField<16, 16, u32> y2;
140 };
141 } scissor_test;
142
143 union {
144 BitField<0, 10, s32> x;
145 BitField<16, 10, s32> y;
146 } viewport_corner;
147
148 INSERT_PADDING_WORDS(0x1);
149
150 // TODO: early depth
151 INSERT_PADDING_WORDS(0x1);
152
153 INSERT_PADDING_WORDS(0x2);
154
155 enum DepthBuffering : u32 {
156 WBuffering = 0,
157 ZBuffering = 1,
158 };
159 BitField<0, 1, DepthBuffering> depthmap_enable;
160
161 INSERT_PADDING_WORDS(0x12);
162
163 struct TextureConfig {
164 enum TextureType : u32 {
165 Texture2D = 0,
166 TextureCube = 1,
167 Shadow2D = 2,
168 Projection2D = 3,
169 ShadowCube = 4,
170 Disabled = 5,
171 };
172
173 enum WrapMode : u32 {
174 ClampToEdge = 0,
175 ClampToBorder = 1,
176 Repeat = 2,
177 MirroredRepeat = 3,
178 };
179
180 enum TextureFilter : u32 {
181 Nearest = 0,
182 Linear = 1,
183 };
184
185 union {
186 u32 raw;
187 BitField<0, 8, u32> r;
188 BitField<8, 8, u32> g;
189 BitField<16, 8, u32> b;
190 BitField<24, 8, u32> a;
191 } border_color;
192
193 union {
194 BitField<0, 16, u32> height;
195 BitField<16, 16, u32> width;
196 };
197
198 union {
199 BitField<1, 1, TextureFilter> mag_filter;
200 BitField<2, 1, TextureFilter> min_filter;
201 BitField<8, 2, WrapMode> wrap_t;
202 BitField<12, 2, WrapMode> wrap_s;
203 BitField<28, 2, TextureType>
204 type; ///< @note Only valid for texture 0 according to 3DBrew.
205 };
206
207 INSERT_PADDING_WORDS(0x1);
208
209 u32 address;
210
211 u32 GetPhysicalAddress() const {
212 return DecodeAddressRegister(address);
213 }
214
215 // texture1 and texture2 store the texture format directly after the address
216 // whereas texture0 inserts some additional flags inbetween.
217 // Hence, we store the format separately so that all other parameters can be described
218 // in a single structure.
219 };
220
221 enum class TextureFormat : u32 {
222 RGBA8 = 0,
223 RGB8 = 1,
224 RGB5A1 = 2,
225 RGB565 = 3,
226 RGBA4 = 4,
227 IA8 = 5,
228 RG8 = 6, ///< @note Also called HILO8 in 3DBrew.
229 I8 = 7,
230 A8 = 8,
231 IA4 = 9,
232 I4 = 10,
233 A4 = 11,
234 ETC1 = 12, // compressed
235 ETC1A4 = 13, // compressed
236 };
237
238 enum class LogicOp : u32 {
239 Clear = 0,
240 And = 1,
241 AndReverse = 2,
242 Copy = 3,
243 Set = 4,
244 CopyInverted = 5,
245 NoOp = 6,
246 Invert = 7,
247 Nand = 8,
248 Or = 9,
249 Nor = 10,
250 Xor = 11,
251 Equiv = 12,
252 AndInverted = 13,
253 OrReverse = 14,
254 OrInverted = 15,
255 };
256
257 static unsigned NibblesPerPixel(TextureFormat format) {
258 switch (format) {
259 case TextureFormat::RGBA8:
260 return 8;
261
262 case TextureFormat::RGB8:
263 return 6;
264
265 case TextureFormat::RGB5A1:
266 case TextureFormat::RGB565:
267 case TextureFormat::RGBA4:
268 case TextureFormat::IA8:
269 case TextureFormat::RG8:
270 return 4;
271
272 case TextureFormat::I4:
273 case TextureFormat::A4:
274 return 1;
275
276 case TextureFormat::I8:
277 case TextureFormat::A8:
278 case TextureFormat::IA4:
279 return 2;
280
281 default: // placeholder for yet unknown formats
282 UNIMPLEMENTED();
283 return 0;
284 }
285 }
286
287 union {
288 BitField<0, 1, u32> texture0_enable;
289 BitField<1, 1, u32> texture1_enable;
290 BitField<2, 1, u32> texture2_enable;
291 };
292 TextureConfig texture0;
293 INSERT_PADDING_WORDS(0x8);
294 BitField<0, 4, TextureFormat> texture0_format;
295 BitField<0, 1, u32> fragment_lighting_enable;
296 INSERT_PADDING_WORDS(0x1);
297 TextureConfig texture1;
298 BitField<0, 4, TextureFormat> texture1_format;
299 INSERT_PADDING_WORDS(0x2);
300 TextureConfig texture2;
301 BitField<0, 4, TextureFormat> texture2_format;
302 INSERT_PADDING_WORDS(0x21);
303
304 struct FullTextureConfig {
305 const bool enabled;
306 const TextureConfig config;
307 const TextureFormat format;
308 };
309 const std::array<FullTextureConfig, 3> GetTextures() const {
310 return {{
311 {texture0_enable.ToBool(), texture0, texture0_format},
312 {texture1_enable.ToBool(), texture1, texture1_format},
313 {texture2_enable.ToBool(), texture2, texture2_format},
314 }};
315 }
316
317 // 0xc0-0xff: Texture Combiner (akin to glTexEnv)
318 struct TevStageConfig {
319 enum class Source : u32 {
320 PrimaryColor = 0x0,
321 PrimaryFragmentColor = 0x1,
322 SecondaryFragmentColor = 0x2,
323
324 Texture0 = 0x3,
325 Texture1 = 0x4,
326 Texture2 = 0x5,
327 Texture3 = 0x6,
328
329 PreviousBuffer = 0xd,
330 Constant = 0xe,
331 Previous = 0xf,
332 };
333
334 enum class ColorModifier : u32 {
335 SourceColor = 0x0,
336 OneMinusSourceColor = 0x1,
337 SourceAlpha = 0x2,
338 OneMinusSourceAlpha = 0x3,
339 SourceRed = 0x4,
340 OneMinusSourceRed = 0x5,
341
342 SourceGreen = 0x8,
343 OneMinusSourceGreen = 0x9,
344
345 SourceBlue = 0xc,
346 OneMinusSourceBlue = 0xd,
347 };
348
349 enum class AlphaModifier : u32 {
350 SourceAlpha = 0x0,
351 OneMinusSourceAlpha = 0x1,
352 SourceRed = 0x2,
353 OneMinusSourceRed = 0x3,
354 SourceGreen = 0x4,
355 OneMinusSourceGreen = 0x5,
356 SourceBlue = 0x6,
357 OneMinusSourceBlue = 0x7,
358 };
359
360 enum class Operation : u32 {
361 Replace = 0,
362 Modulate = 1,
363 Add = 2,
364 AddSigned = 3,
365 Lerp = 4,
366 Subtract = 5,
367 Dot3_RGB = 6,
368
369 MultiplyThenAdd = 8,
370 AddThenMultiply = 9,
371 };
372
373 union {
374 u32 sources_raw;
375 BitField<0, 4, Source> color_source1;
376 BitField<4, 4, Source> color_source2;
377 BitField<8, 4, Source> color_source3;
378 BitField<16, 4, Source> alpha_source1;
379 BitField<20, 4, Source> alpha_source2;
380 BitField<24, 4, Source> alpha_source3;
381 };
382
383 union {
384 u32 modifiers_raw;
385 BitField<0, 4, ColorModifier> color_modifier1;
386 BitField<4, 4, ColorModifier> color_modifier2;
387 BitField<8, 4, ColorModifier> color_modifier3;
388 BitField<12, 3, AlphaModifier> alpha_modifier1;
389 BitField<16, 3, AlphaModifier> alpha_modifier2;
390 BitField<20, 3, AlphaModifier> alpha_modifier3;
391 };
392
393 union {
394 u32 ops_raw;
395 BitField<0, 4, Operation> color_op;
396 BitField<16, 4, Operation> alpha_op;
397 };
398
399 union {
400 u32 const_color;
401 BitField<0, 8, u32> const_r;
402 BitField<8, 8, u32> const_g;
403 BitField<16, 8, u32> const_b;
404 BitField<24, 8, u32> const_a;
405 };
406
407 union {
408 u32 scales_raw;
409 BitField<0, 2, u32> color_scale;
410 BitField<16, 2, u32> alpha_scale;
411 };
412
413 inline unsigned GetColorMultiplier() const {
414 return (color_scale < 3) ? (1 << color_scale) : 1;
415 }
416
417 inline unsigned GetAlphaMultiplier() const {
418 return (alpha_scale < 3) ? (1 << alpha_scale) : 1;
419 }
420 };
421
422 TevStageConfig tev_stage0;
423 INSERT_PADDING_WORDS(0x3);
424 TevStageConfig tev_stage1;
425 INSERT_PADDING_WORDS(0x3);
426 TevStageConfig tev_stage2;
427 INSERT_PADDING_WORDS(0x3);
428 TevStageConfig tev_stage3;
429 INSERT_PADDING_WORDS(0x3);
430
431 enum class FogMode : u32 {
432 None = 0,
433 Fog = 5,
434 Gas = 7,
435 };
436
437 union {
438 BitField<0, 3, FogMode> fog_mode;
439 BitField<16, 1, u32> fog_flip;
440
441 union {
442 // Tev stages 0-3 write their output to the combiner buffer if the corresponding bit in
443 // these masks are set
444 BitField<8, 4, u32> update_mask_rgb;
445 BitField<12, 4, u32> update_mask_a;
446
447 bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const {
448 return (stage_index < 4) && (update_mask_rgb & (1 << stage_index));
449 }
450
451 bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const {
452 return (stage_index < 4) && (update_mask_a & (1 << stage_index));
453 }
454 } tev_combiner_buffer_input;
455 };
456
457 union {
458 u32 raw;
459 BitField<0, 8, u32> r;
460 BitField<8, 8, u32> g;
461 BitField<16, 8, u32> b;
462 } fog_color;
463
464 INSERT_PADDING_WORDS(0x4);
465
466 BitField<0, 16, u32> fog_lut_offset;
467
468 INSERT_PADDING_WORDS(0x1);
469
470 u32 fog_lut_data[8];
471
472 TevStageConfig tev_stage4;
473 INSERT_PADDING_WORDS(0x3);
474 TevStageConfig tev_stage5;
475
476 union {
477 u32 raw;
478 BitField<0, 8, u32> r;
479 BitField<8, 8, u32> g;
480 BitField<16, 8, u32> b;
481 BitField<24, 8, u32> a;
482 } tev_combiner_buffer_color;
483
484 INSERT_PADDING_WORDS(0x2);
485
486 const std::array<Regs::TevStageConfig, 6> GetTevStages() const {
487 return {{tev_stage0, tev_stage1, tev_stage2, tev_stage3, tev_stage4, tev_stage5}};
488 };
489
490 enum class BlendEquation : u32 {
491 Add = 0,
492 Subtract = 1,
493 ReverseSubtract = 2,
494 Min = 3,
495 Max = 4,
496 };
497
498 enum class BlendFactor : u32 {
499 Zero = 0,
500 One = 1,
501 SourceColor = 2,
502 OneMinusSourceColor = 3,
503 DestColor = 4,
504 OneMinusDestColor = 5,
505 SourceAlpha = 6,
506 OneMinusSourceAlpha = 7,
507 DestAlpha = 8,
508 OneMinusDestAlpha = 9,
509 ConstantColor = 10,
510 OneMinusConstantColor = 11,
511 ConstantAlpha = 12,
512 OneMinusConstantAlpha = 13,
513 SourceAlphaSaturate = 14,
514 };
515
516 enum class CompareFunc : u32 {
517 Never = 0,
518 Always = 1,
519 Equal = 2,
520 NotEqual = 3,
521 LessThan = 4,
522 LessThanOrEqual = 5,
523 GreaterThan = 6,
524 GreaterThanOrEqual = 7,
525 };
526
527 enum class StencilAction : u32 {
528 Keep = 0,
529 Zero = 1,
530 Replace = 2,
531 Increment = 3,
532 Decrement = 4,
533 Invert = 5,
534 IncrementWrap = 6,
535 DecrementWrap = 7,
536 };
537
538 struct {
539 union {
540 // If false, logic blending is used
541 BitField<8, 1, u32> alphablend_enable;
542 };
543
544 union {
545 BitField<0, 8, BlendEquation> blend_equation_rgb;
546 BitField<8, 8, BlendEquation> blend_equation_a;
547
548 BitField<16, 4, BlendFactor> factor_source_rgb;
549 BitField<20, 4, BlendFactor> factor_dest_rgb;
550
551 BitField<24, 4, BlendFactor> factor_source_a;
552 BitField<28, 4, BlendFactor> factor_dest_a;
553 } alpha_blending;
554
555 union {
556 BitField<0, 4, LogicOp> logic_op;
557 };
558
559 union {
560 u32 raw;
561 BitField<0, 8, u32> r;
562 BitField<8, 8, u32> g;
563 BitField<16, 8, u32> b;
564 BitField<24, 8, u32> a;
565 } blend_const;
566
567 union {
568 BitField<0, 1, u32> enable;
569 BitField<4, 3, CompareFunc> func;
570 BitField<8, 8, u32> ref;
571 } alpha_test;
572
573 struct {
574 union {
575 // Raw value of this register
576 u32 raw_func;
577
578 // If true, enable stencil testing
579 BitField<0, 1, u32> enable;
580
581 // Comparison operation for stencil testing
582 BitField<4, 3, CompareFunc> func;
583
584 // Mask used to control writing to the stencil buffer
585 BitField<8, 8, u32> write_mask;
586
587 // Value to compare against for stencil testing
588 BitField<16, 8, u32> reference_value;
589
590 // Mask to apply on stencil test inputs
591 BitField<24, 8, u32> input_mask;
592 };
593
594 union {
595 // Raw value of this register
596 u32 raw_op;
597
598 // Action to perform when the stencil test fails
599 BitField<0, 3, StencilAction> action_stencil_fail;
600
601 // Action to perform when stencil testing passed but depth testing fails
602 BitField<4, 3, StencilAction> action_depth_fail;
603
604 // Action to perform when both stencil and depth testing pass
605 BitField<8, 3, StencilAction> action_depth_pass;
606 };
607 } stencil_test;
608
609 union {
610 BitField<0, 1, u32> depth_test_enable;
611 BitField<4, 3, CompareFunc> depth_test_func;
612 BitField<8, 1, u32> red_enable;
613 BitField<9, 1, u32> green_enable;
614 BitField<10, 1, u32> blue_enable;
615 BitField<11, 1, u32> alpha_enable;
616 BitField<12, 1, u32> depth_write_enable;
617 };
618
619 INSERT_PADDING_WORDS(0x8);
620 } output_merger;
621
622 // Components are laid out in reverse byte order, most significant bits first.
623 enum class ColorFormat : u32 {
624 RGBA8 = 0,
625 RGB8 = 1,
626 RGB5A1 = 2,
627 RGB565 = 3,
628 RGBA4 = 4,
629 };
630
631 enum class DepthFormat : u32 {
632 D16 = 0,
633 D24 = 2,
634 D24S8 = 3,
635 };
636
637 // Returns the number of bytes in the specified color format
638 static unsigned BytesPerColorPixel(ColorFormat format) {
639 switch (format) {
640 case ColorFormat::RGBA8:
641 return 4;
642 case ColorFormat::RGB8:
643 return 3;
644 case ColorFormat::RGB5A1:
645 case ColorFormat::RGB565:
646 case ColorFormat::RGBA4:
647 return 2;
648 default:
649 LOG_CRITICAL(HW_GPU, "Unknown color format %u", format);
650 UNIMPLEMENTED();
651 }
652 }
653
654 struct FramebufferConfig {
655 INSERT_PADDING_WORDS(0x3);
656
657 union {
658 BitField<0, 4, u32> allow_color_write; // 0 = disable, else enable
659 };
660
661 INSERT_PADDING_WORDS(0x1);
662
663 union {
664 BitField<0, 2, u32> allow_depth_stencil_write; // 0 = disable, else enable
665 };
666
667 DepthFormat depth_format; // TODO: Should be a BitField!
668 BitField<16, 3, ColorFormat> color_format;
669
670 INSERT_PADDING_WORDS(0x4);
671
672 u32 depth_buffer_address;
673 u32 color_buffer_address;
674
675 union {
676 // Apparently, the framebuffer width is stored as expected,
677 // while the height is stored as the actual height minus one.
678 // Hence, don't access these fields directly but use the accessors
679 // GetWidth() and GetHeight() instead.
680 BitField<0, 11, u32> width;
681 BitField<12, 10, u32> height;
682 };
683
684 INSERT_PADDING_WORDS(0x1);
685
686 inline u32 GetColorBufferPhysicalAddress() const {
687 return DecodeAddressRegister(color_buffer_address);
688 }
689 inline u32 GetDepthBufferPhysicalAddress() const {
690 return DecodeAddressRegister(depth_buffer_address);
691 }
692
693 inline u32 GetWidth() const {
694 return width;
695 }
696
697 inline u32 GetHeight() const {
698 return height + 1;
699 }
700 } framebuffer;
701
702 // Returns the number of bytes in the specified depth format
703 static u32 BytesPerDepthPixel(DepthFormat format) {
704 switch (format) {
705 case DepthFormat::D16:
706 return 2;
707 case DepthFormat::D24:
708 return 3;
709 case DepthFormat::D24S8:
710 return 4;
711 default:
712 LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
713 UNIMPLEMENTED();
714 }
715 }
716
717 // Returns the number of bits per depth component of the specified depth format
718 static u32 DepthBitsPerPixel(DepthFormat format) {
719 switch (format) {
720 case DepthFormat::D16:
721 return 16;
722 case DepthFormat::D24:
723 case DepthFormat::D24S8:
724 return 24;
725 default:
726 LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
727 UNIMPLEMENTED();
728 }
729 }
730
731 INSERT_PADDING_WORDS(0x20);
732
733 enum class LightingSampler {
734 Distribution0 = 0,
735 Distribution1 = 1,
736 Fresnel = 3,
737 ReflectBlue = 4,
738 ReflectGreen = 5,
739 ReflectRed = 6,
740 SpotlightAttenuation = 8,
741 DistanceAttenuation = 16,
742 };
743
744 /**
745 * Pica fragment lighting supports using different LUTs for each lighting component:
746 * Reflectance R, G, and B channels, distribution function for specular components 0 and 1,
747 * fresnel factor, and spotlight attenuation. Furthermore, which LUTs are used for each channel
748 * (or whether a channel is enabled at all) is specified by various pre-defined lighting
749 * configurations. With configurations that require more LUTs, more cycles are required on HW to
750 * perform lighting computations.
751 */
752 enum class LightingConfig {
753 Config0 = 0, ///< Reflect Red, Distribution 0, Spotlight
754 Config1 = 1, ///< Reflect Red, Fresnel, Spotlight
755 Config2 = 2, ///< Reflect Red, Distribution 0/1
756 Config3 = 3, ///< Distribution 0/1, Fresnel
757 Config4 = 4, ///< Reflect Red/Green/Blue, Distribution 0/1, Spotlight
758 Config5 = 5, ///< Reflect Red/Green/Blue, Distribution 0, Fresnel, Spotlight
759 Config6 = 6, ///< Reflect Red, Distribution 0/1, Fresnel, Spotlight
760 Config7 = 8, ///< Reflect Red/Green/Blue, Distribution 0/1, Fresnel, Spotlight
761 ///< NOTE: '8' is intentional, '7' does not appear to be a valid configuration
762 };
763
764 /// Selects which lighting components are affected by fresnel
765 enum class LightingFresnelSelector {
766 None = 0, ///< Fresnel is disabled
767 PrimaryAlpha = 1, ///< Primary (diffuse) lighting alpha is affected by fresnel
768 SecondaryAlpha = 2, ///< Secondary (specular) lighting alpha is affected by fresnel
769 Both =
770 PrimaryAlpha |
771 SecondaryAlpha, ///< Both primary and secondary lighting alphas are affected by fresnel
772 };
773
774 /// Factor used to scale the output of a lighting LUT
775 enum class LightingScale {
776 Scale1 = 0, ///< Scale is 1x
777 Scale2 = 1, ///< Scale is 2x
778 Scale4 = 2, ///< Scale is 4x
779 Scale8 = 3, ///< Scale is 8x
780 Scale1_4 = 6, ///< Scale is 0.25x
781 Scale1_2 = 7, ///< Scale is 0.5x
782 };
783
784 enum class LightingLutInput {
785 NH = 0, // Cosine of the angle between the normal and half-angle vectors
786 VH = 1, // Cosine of the angle between the view and half-angle vectors
787 NV = 2, // Cosine of the angle between the normal and the view vector
788 LN = 3, // Cosine of the angle between the light and the normal vectors
789 };
790
791 enum class LightingBumpMode : u32 {
792 None = 0,
793 NormalMap = 1,
794 TangentMap = 2,
795 };
796
797 union LightColor {
798 BitField<0, 10, u32> b;
799 BitField<10, 10, u32> g;
800 BitField<20, 10, u32> r;
801
802 Math::Vec3f ToVec3f() const {
803 // These fields are 10 bits wide, however 255 corresponds to 1.0f for each color
804 // component
805 return Math::MakeVec((f32)r / 255.f, (f32)g / 255.f, (f32)b / 255.f);
806 }
807 };
808
809 /// Returns true if the specified lighting sampler is supported by the current Pica lighting
810 /// configuration
811 static bool IsLightingSamplerSupported(LightingConfig config, LightingSampler sampler) {
812 switch (sampler) {
813 case LightingSampler::Distribution0:
814 return (config != LightingConfig::Config1);
815
816 case LightingSampler::Distribution1:
817 return (config != LightingConfig::Config0) && (config != LightingConfig::Config1) &&
818 (config != LightingConfig::Config5);
819
820 case LightingSampler::Fresnel:
821 return (config != LightingConfig::Config0) && (config != LightingConfig::Config2) &&
822 (config != LightingConfig::Config4);
823
824 case LightingSampler::ReflectRed:
825 return (config != LightingConfig::Config3);
826
827 case LightingSampler::ReflectGreen:
828 case LightingSampler::ReflectBlue:
829 return (config == LightingConfig::Config4) || (config == LightingConfig::Config5) ||
830 (config == LightingConfig::Config7);
831 default:
832 UNREACHABLE_MSG("Regs::IsLightingSamplerSupported: Reached "
833 "unreachable section, sampler should be one "
834 "of Distribution0, Distribution1, Fresnel, "
835 "ReflectRed, ReflectGreen or ReflectBlue, instead "
836 "got %i",
837 static_cast<int>(config));
838 }
839 }
840
841 struct {
842 struct LightSrc {
843 LightColor specular_0; // material.specular_0 * light.specular_0
844 LightColor specular_1; // material.specular_1 * light.specular_1
845 LightColor diffuse; // material.diffuse * light.diffuse
846 LightColor ambient; // material.ambient * light.ambient
847
848 // Encoded as 16-bit floating point
849 union {
850 BitField<0, 16, u32> x;
851 BitField<16, 16, u32> y;
852 };
853 union {
854 BitField<0, 16, u32> z;
855 };
856
857 INSERT_PADDING_WORDS(0x3);
858
859 union {
860 BitField<0, 1, u32> directional;
861 BitField<1, 1, u32> two_sided_diffuse; // When disabled, clamp dot-product to 0
862 } config;
863
864 BitField<0, 20, u32> dist_atten_bias;
865 BitField<0, 20, u32> dist_atten_scale;
866
867 INSERT_PADDING_WORDS(0x4);
868 };
869 static_assert(sizeof(LightSrc) == 0x10 * sizeof(u32),
870 "LightSrc structure must be 0x10 words");
871
872 LightSrc light[8];
873 LightColor global_ambient; // Emission + (material.ambient * lighting.ambient)
874 INSERT_PADDING_WORDS(0x1);
875 BitField<0, 3, u32> max_light_index; // Number of enabled lights - 1
876
877 union {
878 BitField<2, 2, LightingFresnelSelector> fresnel_selector;
879 BitField<4, 4, LightingConfig> config;
880 BitField<22, 2, u32> bump_selector; // 0: Texture 0, 1: Texture 1, 2: Texture 2
881 BitField<27, 1, u32> clamp_highlights;
882 BitField<28, 2, LightingBumpMode> bump_mode;
883 BitField<30, 1, u32> disable_bump_renorm;
884 } config0;
885
886 union {
887 BitField<16, 1, u32> disable_lut_d0;
888 BitField<17, 1, u32> disable_lut_d1;
889 BitField<19, 1, u32> disable_lut_fr;
890 BitField<20, 1, u32> disable_lut_rr;
891 BitField<21, 1, u32> disable_lut_rg;
892 BitField<22, 1, u32> disable_lut_rb;
893
894 // Each bit specifies whether distance attenuation should be applied for the
895 // corresponding light
896
897 BitField<24, 1, u32> disable_dist_atten_light_0;
898 BitField<25, 1, u32> disable_dist_atten_light_1;
899 BitField<26, 1, u32> disable_dist_atten_light_2;
900 BitField<27, 1, u32> disable_dist_atten_light_3;
901 BitField<28, 1, u32> disable_dist_atten_light_4;
902 BitField<29, 1, u32> disable_dist_atten_light_5;
903 BitField<30, 1, u32> disable_dist_atten_light_6;
904 BitField<31, 1, u32> disable_dist_atten_light_7;
905 } config1;
906
907 bool IsDistAttenDisabled(unsigned index) const {
908 const unsigned disable[] = {
909 config1.disable_dist_atten_light_0, config1.disable_dist_atten_light_1,
910 config1.disable_dist_atten_light_2, config1.disable_dist_atten_light_3,
911 config1.disable_dist_atten_light_4, config1.disable_dist_atten_light_5,
912 config1.disable_dist_atten_light_6, config1.disable_dist_atten_light_7};
913 return disable[index] != 0;
914 }
915
916 union {
917 BitField<0, 8, u32> index; ///< Index at which to set data in the LUT
918 BitField<8, 5, u32> type; ///< Type of LUT for which to set data
919 } lut_config;
920
921 BitField<0, 1, u32> disable;
922 INSERT_PADDING_WORDS(0x1);
923
924 // When data is written to any of these registers, it gets written to the lookup table of
925 // the selected type at the selected index, specified above in the `lut_config` register.
926 // With each write, `lut_config.index` is incremented. It does not matter which of these
927 // registers is written to, the behavior will be the same.
928 u32 lut_data[8];
929
930 // These are used to specify if absolute (abs) value should be used for each LUT index. When
931 // abs mode is disabled, LUT indexes are in the range of (-1.0, 1.0). Otherwise, they are in
932 // the range of (0.0, 1.0).
933 union {
934 BitField<1, 1, u32> disable_d0;
935 BitField<5, 1, u32> disable_d1;
936 BitField<9, 1, u32> disable_sp;
937 BitField<13, 1, u32> disable_fr;
938 BitField<17, 1, u32> disable_rb;
939 BitField<21, 1, u32> disable_rg;
940 BitField<25, 1, u32> disable_rr;
941 } abs_lut_input;
942
943 union {
944 BitField<0, 3, LightingLutInput> d0;
945 BitField<4, 3, LightingLutInput> d1;
946 BitField<8, 3, LightingLutInput> sp;
947 BitField<12, 3, LightingLutInput> fr;
948 BitField<16, 3, LightingLutInput> rb;
949 BitField<20, 3, LightingLutInput> rg;
950 BitField<24, 3, LightingLutInput> rr;
951 } lut_input;
952
953 union {
954 BitField<0, 3, LightingScale> d0;
955 BitField<4, 3, LightingScale> d1;
956 BitField<8, 3, LightingScale> sp;
957 BitField<12, 3, LightingScale> fr;
958 BitField<16, 3, LightingScale> rb;
959 BitField<20, 3, LightingScale> rg;
960 BitField<24, 3, LightingScale> rr;
961
962 static float GetScale(LightingScale scale) {
963 switch (scale) {
964 case LightingScale::Scale1:
965 return 1.0f;
966 case LightingScale::Scale2:
967 return 2.0f;
968 case LightingScale::Scale4:
969 return 4.0f;
970 case LightingScale::Scale8:
971 return 8.0f;
972 case LightingScale::Scale1_4:
973 return 0.25f;
974 case LightingScale::Scale1_2:
975 return 0.5f;
976 }
977 return 0.0f;
978 }
979 } lut_scale;
980
981 INSERT_PADDING_WORDS(0x6);
982
983 union {
984 // There are 8 light enable "slots", corresponding to the total number of lights
985 // supported by Pica. For N enabled lights (specified by register 0x1c2, or 'src_num'
986 // above), the first N slots below will be set to integers within the range of 0-7,
987 // corresponding to the actual light that is enabled for each slot.
988
989 BitField<0, 3, u32> slot_0;
990 BitField<4, 3, u32> slot_1;
991 BitField<8, 3, u32> slot_2;
992 BitField<12, 3, u32> slot_3;
993 BitField<16, 3, u32> slot_4;
994 BitField<20, 3, u32> slot_5;
995 BitField<24, 3, u32> slot_6;
996 BitField<28, 3, u32> slot_7;
997
998 unsigned GetNum(unsigned index) const {
999 const unsigned enable_slots[] = {slot_0, slot_1, slot_2, slot_3,
1000 slot_4, slot_5, slot_6, slot_7};
1001 return enable_slots[index];
1002 }
1003 } light_enable;
1004 } lighting;
1005
1006 INSERT_PADDING_WORDS(0x26);
1007
1008 enum class VertexAttributeFormat : u64 {
1009 BYTE = 0,
1010 UBYTE = 1,
1011 SHORT = 2,
1012 FLOAT = 3,
1013 };
1014
1015 struct {
1016 BitField<0, 29, u32> base_address;
1017
1018 u32 GetPhysicalBaseAddress() const {
1019 return DecodeAddressRegister(base_address);
1020 }
1021
1022 // Descriptor for internal vertex attributes
1023 union {
1024 BitField<0, 2, VertexAttributeFormat> format0; // size of one element
1025 BitField<2, 2, u64> size0; // number of elements minus 1
1026 BitField<4, 2, VertexAttributeFormat> format1;
1027 BitField<6, 2, u64> size1;
1028 BitField<8, 2, VertexAttributeFormat> format2;
1029 BitField<10, 2, u64> size2;
1030 BitField<12, 2, VertexAttributeFormat> format3;
1031 BitField<14, 2, u64> size3;
1032 BitField<16, 2, VertexAttributeFormat> format4;
1033 BitField<18, 2, u64> size4;
1034 BitField<20, 2, VertexAttributeFormat> format5;
1035 BitField<22, 2, u64> size5;
1036 BitField<24, 2, VertexAttributeFormat> format6;
1037 BitField<26, 2, u64> size6;
1038 BitField<28, 2, VertexAttributeFormat> format7;
1039 BitField<30, 2, u64> size7;
1040 BitField<32, 2, VertexAttributeFormat> format8;
1041 BitField<34, 2, u64> size8;
1042 BitField<36, 2, VertexAttributeFormat> format9;
1043 BitField<38, 2, u64> size9;
1044 BitField<40, 2, VertexAttributeFormat> format10;
1045 BitField<42, 2, u64> size10;
1046 BitField<44, 2, VertexAttributeFormat> format11;
1047 BitField<46, 2, u64> size11;
1048
1049 BitField<48, 12, u64> attribute_mask;
1050
1051 // number of total attributes minus 1
1052 BitField<60, 4, u64> max_attribute_index;
1053 };
1054
1055 inline VertexAttributeFormat GetFormat(int n) const {
1056 VertexAttributeFormat formats[] = {format0, format1, format2, format3,
1057 format4, format5, format6, format7,
1058 format8, format9, format10, format11};
1059 return formats[n];
1060 }
1061
1062 inline int GetNumElements(int n) const {
1063 u64 sizes[] = {size0, size1, size2, size3, size4, size5,
1064 size6, size7, size8, size9, size10, size11};
1065 return (int)sizes[n] + 1;
1066 }
1067
1068 inline int GetElementSizeInBytes(int n) const {
1069 return (GetFormat(n) == VertexAttributeFormat::FLOAT)
1070 ? 4
1071 : (GetFormat(n) == VertexAttributeFormat::SHORT) ? 2 : 1;
1072 }
1073
1074 inline int GetStride(int n) const {
1075 return GetNumElements(n) * GetElementSizeInBytes(n);
1076 }
1077
1078 inline bool IsDefaultAttribute(int id) const {
1079 return (id >= 12) || (attribute_mask & (1ULL << id)) != 0;
1080 }
1081
1082 inline int GetNumTotalAttributes() const {
1083 return (int)max_attribute_index + 1;
1084 }
1085
1086 // Attribute loaders map the source vertex data to input attributes
1087 // This e.g. allows to load different attributes from different memory locations
1088 struct {
1089 // Source attribute data offset from the base address
1090 u32 data_offset;
1091
1092 union {
1093 BitField<0, 4, u64> comp0;
1094 BitField<4, 4, u64> comp1;
1095 BitField<8, 4, u64> comp2;
1096 BitField<12, 4, u64> comp3;
1097 BitField<16, 4, u64> comp4;
1098 BitField<20, 4, u64> comp5;
1099 BitField<24, 4, u64> comp6;
1100 BitField<28, 4, u64> comp7;
1101 BitField<32, 4, u64> comp8;
1102 BitField<36, 4, u64> comp9;
1103 BitField<40, 4, u64> comp10;
1104 BitField<44, 4, u64> comp11;
1105
1106 // bytes for a single vertex in this loader
1107 BitField<48, 8, u64> byte_count;
1108
1109 BitField<60, 4, u64> component_count;
1110 };
1111
1112 inline int GetComponent(int n) const {
1113 u64 components[] = {comp0, comp1, comp2, comp3, comp4, comp5,
1114 comp6, comp7, comp8, comp9, comp10, comp11};
1115 return (int)components[n];
1116 }
1117 } attribute_loaders[12];
1118 } vertex_attributes;
1119
1120 struct {
1121 enum IndexFormat : u32 {
1122 BYTE = 0,
1123 SHORT = 1,
1124 };
1125
1126 union {
1127 BitField<0, 31, u32> offset; // relative to base attribute address
1128 BitField<31, 1, IndexFormat> format;
1129 };
1130 } index_array;
1131
1132 // Number of vertices to render
1133 u32 num_vertices;
1134
1135 INSERT_PADDING_WORDS(0x1);
1136
1137 // The index of the first vertex to render
1138 u32 vertex_offset;
1139
1140 INSERT_PADDING_WORDS(0x3);
1141
1142 // These two trigger rendering of triangles
1143 u32 trigger_draw;
1144 u32 trigger_draw_indexed;
1145
1146 INSERT_PADDING_WORDS(0x2);
1147
1148 // These registers are used to setup the default "fall-back" vertex shader attributes
1149 struct {
1150 // Index of the current default attribute
1151 u32 index;
1152
1153 // Writing to these registers sets the "current" default attribute.
1154 u32 set_value[3];
1155 } vs_default_attributes_setup;
1156
1157 INSERT_PADDING_WORDS(0x2);
1158
1159 struct {
1160 // There are two channels that can be used to configure the next command buffer, which
1161 // can be then executed by writing to the "trigger" registers. There are two reasons why a
1162 // game might use this feature:
1163 // 1) With this, an arbitrary number of additional command buffers may be executed in
1164 // sequence without requiring any intervention of the CPU after the initial one is
1165 // kicked off.
1166 // 2) Games can configure these registers to provide a command list subroutine mechanism.
1167
1168 BitField<0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer
1169 BitField<0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer
1170 u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to
1171
1172 unsigned GetSize(unsigned index) const {
1173 ASSERT(index < 2);
1174 return 8 * size[index];
1175 }
1176
1177 PAddr GetPhysicalAddress(unsigned index) const {
1178 ASSERT(index < 2);
1179 return (PAddr)(8 * addr[index]);
1180 }
1181 } command_buffer;
1182
1183 INSERT_PADDING_WORDS(4);
1184
1185 /// Number of input attributes to the vertex shader minus 1
1186 BitField<0, 4, u32> max_input_attrib_index;
1187
1188 INSERT_PADDING_WORDS(2);
1189
1190 enum class GPUMode : u32 {
1191 Drawing = 0,
1192 Configuring = 1,
1193 };
1194
1195 GPUMode gpu_mode;
1196
1197 INSERT_PADDING_WORDS(0x18);
1198
1199 enum class TriangleTopology : u32 {
1200 List = 0,
1201 Strip = 1,
1202 Fan = 2,
1203 Shader = 3, // Programmable setup unit implemented in a geometry shader
1204 };
1205
1206 BitField<8, 2, TriangleTopology> triangle_topology;
1207
1208 u32 restart_primitive;
1209
1210 INSERT_PADDING_WORDS(0x20);
1211
1212 struct ShaderConfig {
1213 BitField<0, 16, u32> bool_uniforms;
1214
1215 union {
1216 BitField<0, 8, u32> x;
1217 BitField<8, 8, u32> y;
1218 BitField<16, 8, u32> z;
1219 BitField<24, 8, u32> w;
1220 } int_uniforms[4];
1221
1222 INSERT_PADDING_WORDS(0x4);
1223
1224 union {
1225 // Number of input attributes to shader unit - 1
1226 BitField<0, 4, u32> max_input_attribute_index;
1227 };
1228
1229 // Offset to shader program entry point (in words)
1230 BitField<0, 16, u32> main_offset;
1231
1232 /// Maps input attributes to registers. 4-bits per attribute, specifying a register index
1233 u32 input_attribute_to_register_map_low;
1234 u32 input_attribute_to_register_map_high;
1235
1236 unsigned int GetRegisterForAttribute(unsigned int attribute_index) const {
1237 u64 map = ((u64)input_attribute_to_register_map_high << 32) |
1238 (u64)input_attribute_to_register_map_low;
1239 return (map >> (attribute_index * 4)) & 0b1111;
1240 }
1241
1242 BitField<0, 16, u32> output_mask;
1243
1244 // 0x28E, CODETRANSFER_END
1245 INSERT_PADDING_WORDS(0x2);
1246
1247 struct {
1248 enum Format : u32 {
1249 FLOAT24 = 0,
1250 FLOAT32 = 1,
1251 };
1252
1253 bool IsFloat32() const {
1254 return format == FLOAT32;
1255 }
1256
1257 union {
1258 // Index of the next uniform to write to
1259 // TODO: ctrulib uses 8 bits for this, however that seems to yield lots of invalid
1260 // indices
1261 // TODO: Maybe the uppermost index is for the geometry shader? Investigate!
1262 BitField<0, 7, u32> index;
1263
1264 BitField<31, 1, Format> format;
1265 };
1266
1267 // Writing to these registers sets the current uniform.
1268 u32 set_value[8];
1269
1270 } uniform_setup;
1271
1272 INSERT_PADDING_WORDS(0x2);
1273
1274 struct {
1275 // Offset of the next instruction to write code to.
1276 // Incremented with each instruction write.
1277 u32 offset;
1278
1279 // Writing to these registers sets the "current" word in the shader program.
1280 u32 set_word[8];
1281 } program;
1282
1283 INSERT_PADDING_WORDS(0x1);
1284
1285 // This register group is used to load an internal table of swizzling patterns,
1286 // which are indexed by each shader instruction to specify vector component swizzling.
1287 struct {
1288 // Offset of the next swizzle pattern to write code to.
1289 // Incremented with each instruction write.
1290 u32 offset;
1291
1292 // Writing to these registers sets the current swizzle pattern in the table.
1293 u32 set_word[8];
1294 } swizzle_patterns;
1295
1296 INSERT_PADDING_WORDS(0x2);
1297 };
1298
1299 ShaderConfig gs;
1300 ShaderConfig vs;
1301
1302 INSERT_PADDING_WORDS(0x20);
1303
1304 // Map register indices to names readable by humans
1305 // Used for debugging purposes, so performance is not an issue here
1306 static std::string GetCommandName(int index);
1307
1308 static constexpr size_t NumIds() {
1309 return sizeof(Regs) / sizeof(u32);
1310 }
1311
1312 const u32& operator[](int index) const {
1313 const u32* content = reinterpret_cast<const u32*>(this);
1314 return content[index];
1315 }
1316
1317 u32& operator[](int index) {
1318 u32* content = reinterpret_cast<u32*>(this);
1319 return content[index];
1320 }
1321
1322private:
1323 /*
1324 * Most physical addresses which Pica registers refer to are 8-byte aligned.
1325 * This function should be used to get the address from a raw register value.
1326 */
1327 static inline u32 DecodeAddressRegister(u32 register_value) {
1328 return register_value * 8;
1329 }
1330};
1331
1332// TODO: MSVC does not support using offsetof() on non-static data members even though this
1333// is technically allowed since C++11. This macro should be enabled once MSVC adds
1334// support for that.
1335#ifndef _MSC_VER
1336#define ASSERT_REG_POSITION(field_name, position) \
1337 static_assert(offsetof(Regs, field_name) == position * 4, \
1338 "Field " #field_name " has invalid position")
1339
1340ASSERT_REG_POSITION(trigger_irq, 0x10);
1341ASSERT_REG_POSITION(cull_mode, 0x40);
1342ASSERT_REG_POSITION(viewport_size_x, 0x41);
1343ASSERT_REG_POSITION(viewport_size_y, 0x43);
1344ASSERT_REG_POSITION(viewport_depth_range, 0x4d);
1345ASSERT_REG_POSITION(viewport_depth_near_plane, 0x4e);
1346ASSERT_REG_POSITION(vs_output_attributes[0], 0x50);
1347ASSERT_REG_POSITION(vs_output_attributes[1], 0x51);
1348ASSERT_REG_POSITION(scissor_test, 0x65);
1349ASSERT_REG_POSITION(viewport_corner, 0x68);
1350ASSERT_REG_POSITION(depthmap_enable, 0x6D);
1351ASSERT_REG_POSITION(texture0_enable, 0x80);
1352ASSERT_REG_POSITION(texture0, 0x81);
1353ASSERT_REG_POSITION(texture0_format, 0x8e);
1354ASSERT_REG_POSITION(fragment_lighting_enable, 0x8f);
1355ASSERT_REG_POSITION(texture1, 0x91);
1356ASSERT_REG_POSITION(texture1_format, 0x96);
1357ASSERT_REG_POSITION(texture2, 0x99);
1358ASSERT_REG_POSITION(texture2_format, 0x9e);
1359ASSERT_REG_POSITION(tev_stage0, 0xc0);
1360ASSERT_REG_POSITION(tev_stage1, 0xc8);
1361ASSERT_REG_POSITION(tev_stage2, 0xd0);
1362ASSERT_REG_POSITION(tev_stage3, 0xd8);
1363ASSERT_REG_POSITION(tev_combiner_buffer_input, 0xe0);
1364ASSERT_REG_POSITION(fog_mode, 0xe0);
1365ASSERT_REG_POSITION(fog_color, 0xe1);
1366ASSERT_REG_POSITION(fog_lut_offset, 0xe6);
1367ASSERT_REG_POSITION(fog_lut_data, 0xe8);
1368ASSERT_REG_POSITION(tev_stage4, 0xf0);
1369ASSERT_REG_POSITION(tev_stage5, 0xf8);
1370ASSERT_REG_POSITION(tev_combiner_buffer_color, 0xfd);
1371ASSERT_REG_POSITION(output_merger, 0x100);
1372ASSERT_REG_POSITION(framebuffer, 0x110);
1373ASSERT_REG_POSITION(lighting, 0x140);
1374ASSERT_REG_POSITION(vertex_attributes, 0x200);
1375ASSERT_REG_POSITION(index_array, 0x227);
1376ASSERT_REG_POSITION(num_vertices, 0x228);
1377ASSERT_REG_POSITION(vertex_offset, 0x22a);
1378ASSERT_REG_POSITION(trigger_draw, 0x22e);
1379ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f);
1380ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232);
1381ASSERT_REG_POSITION(command_buffer, 0x238);
1382ASSERT_REG_POSITION(gpu_mode, 0x245);
1383ASSERT_REG_POSITION(triangle_topology, 0x25e);
1384ASSERT_REG_POSITION(restart_primitive, 0x25f);
1385ASSERT_REG_POSITION(gs, 0x280);
1386ASSERT_REG_POSITION(vs, 0x2b0);
1387
1388#undef ASSERT_REG_POSITION
1389#endif // !defined(_MSC_VER)
1390
1391static_assert(sizeof(Regs::ShaderConfig) == 0x30 * sizeof(u32),
1392 "ShaderConfig structure has incorrect size");
1393
1394// The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value
1395// anyway.
1396static_assert(sizeof(Regs) <= 0x300 * sizeof(u32),
1397 "Register set structure larger than it should be");
1398static_assert(sizeof(Regs) >= 0x300 * sizeof(u32),
1399 "Register set structure smaller than it should be");
1400
1401/// Initialize Pica state 10/// Initialize Pica state
1402void Init(); 11void Init();
1403 12
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index 785d05650..af7536d11 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -7,8 +7,8 @@
7#include <array> 7#include <array>
8#include "common/bit_field.h" 8#include "common/bit_field.h"
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/pica.h"
11#include "video_core/primitive_assembly.h" 10#include "video_core/primitive_assembly.h"
11#include "video_core/regs.h"
12#include "video_core/shader/shader.h" 12#include "video_core/shader/shader.h"
13 13
14namespace Pica { 14namespace Pica {
diff --git a/src/video_core/primitive_assembly.cpp b/src/video_core/primitive_assembly.cpp
index e71ff5719..acd2ac5e2 100644
--- a/src/video_core/primitive_assembly.cpp
+++ b/src/video_core/primitive_assembly.cpp
@@ -3,14 +3,14 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "video_core/pica.h"
7#include "video_core/primitive_assembly.h" 6#include "video_core/primitive_assembly.h"
7#include "video_core/regs_pipeline.h"
8#include "video_core/shader/shader.h" 8#include "video_core/shader/shader.h"
9 9
10namespace Pica { 10namespace Pica {
11 11
12template <typename VertexType> 12template <typename VertexType>
13PrimitiveAssembler<VertexType>::PrimitiveAssembler(Regs::TriangleTopology topology) 13PrimitiveAssembler<VertexType>::PrimitiveAssembler(PipelineRegs::TriangleTopology topology)
14 : topology(topology), buffer_index(0) {} 14 : topology(topology), buffer_index(0) {}
15 15
16template <typename VertexType> 16template <typename VertexType>
@@ -18,8 +18,8 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx,
18 TriangleHandler triangle_handler) { 18 TriangleHandler triangle_handler) {
19 switch (topology) { 19 switch (topology) {
20 // TODO: Figure out what's different with TriangleTopology::Shader. 20 // TODO: Figure out what's different with TriangleTopology::Shader.
21 case Regs::TriangleTopology::List: 21 case PipelineRegs::TriangleTopology::List:
22 case Regs::TriangleTopology::Shader: 22 case PipelineRegs::TriangleTopology::Shader:
23 if (buffer_index < 2) { 23 if (buffer_index < 2) {
24 buffer[buffer_index++] = vtx; 24 buffer[buffer_index++] = vtx;
25 } else { 25 } else {
@@ -29,8 +29,8 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx,
29 } 29 }
30 break; 30 break;
31 31
32 case Regs::TriangleTopology::Strip: 32 case PipelineRegs::TriangleTopology::Strip:
33 case Regs::TriangleTopology::Fan: 33 case PipelineRegs::TriangleTopology::Fan:
34 if (strip_ready) 34 if (strip_ready)
35 triangle_handler(buffer[0], buffer[1], vtx); 35 triangle_handler(buffer[0], buffer[1], vtx);
36 36
@@ -38,9 +38,9 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx,
38 38
39 strip_ready |= (buffer_index == 1); 39 strip_ready |= (buffer_index == 1);
40 40
41 if (topology == Regs::TriangleTopology::Strip) 41 if (topology == PipelineRegs::TriangleTopology::Strip)
42 buffer_index = !buffer_index; 42 buffer_index = !buffer_index;
43 else if (topology == Regs::TriangleTopology::Fan) 43 else if (topology == PipelineRegs::TriangleTopology::Fan)
44 buffer_index = 1; 44 buffer_index = 1;
45 break; 45 break;
46 46
@@ -57,7 +57,7 @@ void PrimitiveAssembler<VertexType>::Reset() {
57} 57}
58 58
59template <typename VertexType> 59template <typename VertexType>
60void PrimitiveAssembler<VertexType>::Reconfigure(Regs::TriangleTopology topology) { 60void PrimitiveAssembler<VertexType>::Reconfigure(PipelineRegs::TriangleTopology topology) {
61 Reset(); 61 Reset();
62 this->topology = topology; 62 this->topology = topology;
63} 63}
diff --git a/src/video_core/primitive_assembly.h b/src/video_core/primitive_assembly.h
index 24da47382..e8eccdf27 100644
--- a/src/video_core/primitive_assembly.h
+++ b/src/video_core/primitive_assembly.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <functional> 7#include <functional>
8#include "video_core/pica.h" 8#include "video_core/regs_pipeline.h"
9 9
10namespace Pica { 10namespace Pica {
11 11
@@ -18,7 +18,8 @@ struct PrimitiveAssembler {
18 using TriangleHandler = 18 using TriangleHandler =
19 std::function<void(const VertexType& v0, const VertexType& v1, const VertexType& v2)>; 19 std::function<void(const VertexType& v0, const VertexType& v1, const VertexType& v2)>;
20 20
21 PrimitiveAssembler(Regs::TriangleTopology topology = Regs::TriangleTopology::List); 21 PrimitiveAssembler(
22 PipelineRegs::TriangleTopology topology = PipelineRegs::TriangleTopology::List);
22 23
23 /* 24 /*
24 * Queues a vertex, builds primitives from the vertex queue according to the given 25 * Queues a vertex, builds primitives from the vertex queue according to the given
@@ -36,10 +37,10 @@ struct PrimitiveAssembler {
36 /** 37 /**
37 * Reconfigures the PrimitiveAssembler to use a different triangle topology. 38 * Reconfigures the PrimitiveAssembler to use a different triangle topology.
38 */ 39 */
39 void Reconfigure(Regs::TriangleTopology topology); 40 void Reconfigure(PipelineRegs::TriangleTopology topology);
40 41
41private: 42private:
42 Regs::TriangleTopology topology; 43 PipelineRegs::TriangleTopology topology;
43 44
44 int buffer_index; 45 int buffer_index;
45 VertexType buffer[2]; 46 VertexType buffer[2];
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 287d732b5..ca09c9d0e 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -16,10 +16,10 @@
16#include "core/hw/gpu.h" 16#include "core/hw/gpu.h"
17#include "core/memory.h" 17#include "core/memory.h"
18#include "video_core/debug_utils/debug_utils.h" 18#include "video_core/debug_utils/debug_utils.h"
19#include "video_core/pica.h"
20#include "video_core/pica_state.h" 19#include "video_core/pica_state.h"
21#include "video_core/pica_types.h" 20#include "video_core/pica_types.h"
22#include "video_core/rasterizer.h" 21#include "video_core/rasterizer.h"
22#include "video_core/regs.h"
23#include "video_core/shader/shader.h" 23#include "video_core/shader/shader.h"
24#include "video_core/texture/texture_decode.h" 24#include "video_core/texture/texture_decode.h"
25#include "video_core/utils.h" 25#include "video_core/utils.h"
@@ -29,7 +29,7 @@ namespace Pica {
29namespace Rasterizer { 29namespace Rasterizer {
30 30
31static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { 31static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
32 const auto& framebuffer = g_state.regs.framebuffer; 32 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
33 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress(); 33 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
34 34
35 // Similarly to textures, the render framebuffer is laid out from bottom to top, too. 35 // Similarly to textures, the render framebuffer is laid out from bottom to top, too.
@@ -44,23 +44,23 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
44 u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset; 44 u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset;
45 45
46 switch (framebuffer.color_format) { 46 switch (framebuffer.color_format) {
47 case Regs::ColorFormat::RGBA8: 47 case FramebufferRegs::ColorFormat::RGBA8:
48 Color::EncodeRGBA8(color, dst_pixel); 48 Color::EncodeRGBA8(color, dst_pixel);
49 break; 49 break;
50 50
51 case Regs::ColorFormat::RGB8: 51 case FramebufferRegs::ColorFormat::RGB8:
52 Color::EncodeRGB8(color, dst_pixel); 52 Color::EncodeRGB8(color, dst_pixel);
53 break; 53 break;
54 54
55 case Regs::ColorFormat::RGB5A1: 55 case FramebufferRegs::ColorFormat::RGB5A1:
56 Color::EncodeRGB5A1(color, dst_pixel); 56 Color::EncodeRGB5A1(color, dst_pixel);
57 break; 57 break;
58 58
59 case Regs::ColorFormat::RGB565: 59 case FramebufferRegs::ColorFormat::RGB565:
60 Color::EncodeRGB565(color, dst_pixel); 60 Color::EncodeRGB565(color, dst_pixel);
61 break; 61 break;
62 62
63 case Regs::ColorFormat::RGBA4: 63 case FramebufferRegs::ColorFormat::RGBA4:
64 Color::EncodeRGBA4(color, dst_pixel); 64 Color::EncodeRGBA4(color, dst_pixel);
65 break; 65 break;
66 66
@@ -72,7 +72,7 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
72} 72}
73 73
74static const Math::Vec4<u8> GetPixel(int x, int y) { 74static const Math::Vec4<u8> GetPixel(int x, int y) {
75 const auto& framebuffer = g_state.regs.framebuffer; 75 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
76 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress(); 76 const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
77 77
78 y = framebuffer.height - y; 78 y = framebuffer.height - y;
@@ -85,19 +85,19 @@ static const Math::Vec4<u8> GetPixel(int x, int y) {
85 u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset; 85 u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset;
86 86
87 switch (framebuffer.color_format) { 87 switch (framebuffer.color_format) {
88 case Regs::ColorFormat::RGBA8: 88 case FramebufferRegs::ColorFormat::RGBA8:
89 return Color::DecodeRGBA8(src_pixel); 89 return Color::DecodeRGBA8(src_pixel);
90 90
91 case Regs::ColorFormat::RGB8: 91 case FramebufferRegs::ColorFormat::RGB8:
92 return Color::DecodeRGB8(src_pixel); 92 return Color::DecodeRGB8(src_pixel);
93 93
94 case Regs::ColorFormat::RGB5A1: 94 case FramebufferRegs::ColorFormat::RGB5A1:
95 return Color::DecodeRGB5A1(src_pixel); 95 return Color::DecodeRGB5A1(src_pixel);
96 96
97 case Regs::ColorFormat::RGB565: 97 case FramebufferRegs::ColorFormat::RGB565:
98 return Color::DecodeRGB565(src_pixel); 98 return Color::DecodeRGB565(src_pixel);
99 99
100 case Regs::ColorFormat::RGBA4: 100 case FramebufferRegs::ColorFormat::RGBA4:
101 return Color::DecodeRGBA4(src_pixel); 101 return Color::DecodeRGBA4(src_pixel);
102 102
103 default: 103 default:
@@ -110,25 +110,25 @@ static const Math::Vec4<u8> GetPixel(int x, int y) {
110} 110}
111 111
112static u32 GetDepth(int x, int y) { 112static u32 GetDepth(int x, int y) {
113 const auto& framebuffer = g_state.regs.framebuffer; 113 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
114 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); 114 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
115 u8* depth_buffer = Memory::GetPhysicalPointer(addr); 115 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
116 116
117 y = framebuffer.height - y; 117 y = framebuffer.height - y;
118 118
119 const u32 coarse_y = y & ~7; 119 const u32 coarse_y = y & ~7;
120 u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format); 120 u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
121 u32 stride = framebuffer.width * bytes_per_pixel; 121 u32 stride = framebuffer.width * bytes_per_pixel;
122 122
123 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; 123 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
124 u8* src_pixel = depth_buffer + src_offset; 124 u8* src_pixel = depth_buffer + src_offset;
125 125
126 switch (framebuffer.depth_format) { 126 switch (framebuffer.depth_format) {
127 case Regs::DepthFormat::D16: 127 case FramebufferRegs::DepthFormat::D16:
128 return Color::DecodeD16(src_pixel); 128 return Color::DecodeD16(src_pixel);
129 case Regs::DepthFormat::D24: 129 case FramebufferRegs::DepthFormat::D24:
130 return Color::DecodeD24(src_pixel); 130 return Color::DecodeD24(src_pixel);
131 case Regs::DepthFormat::D24S8: 131 case FramebufferRegs::DepthFormat::D24S8:
132 return Color::DecodeD24S8(src_pixel).x; 132 return Color::DecodeD24S8(src_pixel).x;
133 default: 133 default:
134 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); 134 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
@@ -138,21 +138,21 @@ static u32 GetDepth(int x, int y) {
138} 138}
139 139
140static u8 GetStencil(int x, int y) { 140static u8 GetStencil(int x, int y) {
141 const auto& framebuffer = g_state.regs.framebuffer; 141 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
142 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); 142 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
143 u8* depth_buffer = Memory::GetPhysicalPointer(addr); 143 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
144 144
145 y = framebuffer.height - y; 145 y = framebuffer.height - y;
146 146
147 const u32 coarse_y = y & ~7; 147 const u32 coarse_y = y & ~7;
148 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format); 148 u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
149 u32 stride = framebuffer.width * bytes_per_pixel; 149 u32 stride = framebuffer.width * bytes_per_pixel;
150 150
151 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; 151 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
152 u8* src_pixel = depth_buffer + src_offset; 152 u8* src_pixel = depth_buffer + src_offset;
153 153
154 switch (framebuffer.depth_format) { 154 switch (framebuffer.depth_format) {
155 case Regs::DepthFormat::D24S8: 155 case FramebufferRegs::DepthFormat::D24S8:
156 return Color::DecodeD24S8(src_pixel).y; 156 return Color::DecodeD24S8(src_pixel).y;
157 157
158 default: 158 default:
@@ -165,29 +165,29 @@ static u8 GetStencil(int x, int y) {
165} 165}
166 166
167static void SetDepth(int x, int y, u32 value) { 167static void SetDepth(int x, int y, u32 value) {
168 const auto& framebuffer = g_state.regs.framebuffer; 168 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
169 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); 169 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
170 u8* depth_buffer = Memory::GetPhysicalPointer(addr); 170 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
171 171
172 y = framebuffer.height - y; 172 y = framebuffer.height - y;
173 173
174 const u32 coarse_y = y & ~7; 174 const u32 coarse_y = y & ~7;
175 u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format); 175 u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
176 u32 stride = framebuffer.width * bytes_per_pixel; 176 u32 stride = framebuffer.width * bytes_per_pixel;
177 177
178 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; 178 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
179 u8* dst_pixel = depth_buffer + dst_offset; 179 u8* dst_pixel = depth_buffer + dst_offset;
180 180
181 switch (framebuffer.depth_format) { 181 switch (framebuffer.depth_format) {
182 case Regs::DepthFormat::D16: 182 case FramebufferRegs::DepthFormat::D16:
183 Color::EncodeD16(value, dst_pixel); 183 Color::EncodeD16(value, dst_pixel);
184 break; 184 break;
185 185
186 case Regs::DepthFormat::D24: 186 case FramebufferRegs::DepthFormat::D24:
187 Color::EncodeD24(value, dst_pixel); 187 Color::EncodeD24(value, dst_pixel);
188 break; 188 break;
189 189
190 case Regs::DepthFormat::D24S8: 190 case FramebufferRegs::DepthFormat::D24S8:
191 Color::EncodeD24X8(value, dst_pixel); 191 Color::EncodeD24X8(value, dst_pixel);
192 break; 192 break;
193 193
@@ -199,26 +199,26 @@ static void SetDepth(int x, int y, u32 value) {
199} 199}
200 200
201static void SetStencil(int x, int y, u8 value) { 201static void SetStencil(int x, int y, u8 value) {
202 const auto& framebuffer = g_state.regs.framebuffer; 202 const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
203 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); 203 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
204 u8* depth_buffer = Memory::GetPhysicalPointer(addr); 204 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
205 205
206 y = framebuffer.height - y; 206 y = framebuffer.height - y;
207 207
208 const u32 coarse_y = y & ~7; 208 const u32 coarse_y = y & ~7;
209 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format); 209 u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
210 u32 stride = framebuffer.width * bytes_per_pixel; 210 u32 stride = framebuffer.width * bytes_per_pixel;
211 211
212 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; 212 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
213 u8* dst_pixel = depth_buffer + dst_offset; 213 u8* dst_pixel = depth_buffer + dst_offset;
214 214
215 switch (framebuffer.depth_format) { 215 switch (framebuffer.depth_format) {
216 case Pica::Regs::DepthFormat::D16: 216 case Pica::FramebufferRegs::DepthFormat::D16:
217 case Pica::Regs::DepthFormat::D24: 217 case Pica::FramebufferRegs::DepthFormat::D24:
218 // Nothing to do 218 // Nothing to do
219 break; 219 break;
220 220
221 case Pica::Regs::DepthFormat::D24S8: 221 case Pica::FramebufferRegs::DepthFormat::D24S8:
222 Color::EncodeX24S8(value, dst_pixel); 222 Color::EncodeX24S8(value, dst_pixel);
223 break; 223 break;
224 224
@@ -229,32 +229,32 @@ static void SetStencil(int x, int y, u8 value) {
229 } 229 }
230} 230}
231 231
232static u8 PerformStencilAction(Regs::StencilAction action, u8 old_stencil, u8 ref) { 232static u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref) {
233 switch (action) { 233 switch (action) {
234 case Regs::StencilAction::Keep: 234 case FramebufferRegs::StencilAction::Keep:
235 return old_stencil; 235 return old_stencil;
236 236
237 case Regs::StencilAction::Zero: 237 case FramebufferRegs::StencilAction::Zero:
238 return 0; 238 return 0;
239 239
240 case Regs::StencilAction::Replace: 240 case FramebufferRegs::StencilAction::Replace:
241 return ref; 241 return ref;
242 242
243 case Regs::StencilAction::Increment: 243 case FramebufferRegs::StencilAction::Increment:
244 // Saturated increment 244 // Saturated increment
245 return std::min<u8>(old_stencil, 254) + 1; 245 return std::min<u8>(old_stencil, 254) + 1;
246 246
247 case Regs::StencilAction::Decrement: 247 case FramebufferRegs::StencilAction::Decrement:
248 // Saturated decrement 248 // Saturated decrement
249 return std::max<u8>(old_stencil, 1) - 1; 249 return std::max<u8>(old_stencil, 1) - 1;
250 250
251 case Regs::StencilAction::Invert: 251 case FramebufferRegs::StencilAction::Invert:
252 return ~old_stencil; 252 return ~old_stencil;
253 253
254 case Regs::StencilAction::IncrementWrap: 254 case FramebufferRegs::StencilAction::IncrementWrap:
255 return old_stencil + 1; 255 return old_stencil + 1;
256 256
257 case Regs::StencilAction::DecrementWrap: 257 case FramebufferRegs::StencilAction::DecrementWrap:
258 return old_stencil - 1; 258 return old_stencil - 1;
259 259
260 default: 260 default:
@@ -327,14 +327,14 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
327 ScreenToRasterizerCoordinates(v1.screenpos), 327 ScreenToRasterizerCoordinates(v1.screenpos),
328 ScreenToRasterizerCoordinates(v2.screenpos)}; 328 ScreenToRasterizerCoordinates(v2.screenpos)};
329 329
330 if (regs.cull_mode == Regs::CullMode::KeepAll) { 330 if (regs.rasterizer.cull_mode == RasterizerRegs::CullMode::KeepAll) {
331 // Make sure we always end up with a triangle wound counter-clockwise 331 // Make sure we always end up with a triangle wound counter-clockwise
332 if (!reversed && SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) { 332 if (!reversed && SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) {
333 ProcessTriangleInternal(v0, v2, v1, true); 333 ProcessTriangleInternal(v0, v2, v1, true);
334 return; 334 return;
335 } 335 }
336 } else { 336 } else {
337 if (!reversed && regs.cull_mode == Regs::CullMode::KeepClockWise) { 337 if (!reversed && regs.rasterizer.cull_mode == RasterizerRegs::CullMode::KeepClockWise) {
338 // Reverse vertex order and use the CCW code path. 338 // Reverse vertex order and use the CCW code path.
339 ProcessTriangleInternal(v0, v2, v1, true); 339 ProcessTriangleInternal(v0, v2, v1, true);
340 return; 340 return;
@@ -351,13 +351,13 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
351 u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y}); 351 u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y});
352 352
353 // Convert the scissor box coordinates to 12.4 fixed point 353 // Convert the scissor box coordinates to 12.4 fixed point
354 u16 scissor_x1 = (u16)(regs.scissor_test.x1 << 4); 354 u16 scissor_x1 = (u16)(regs.rasterizer.scissor_test.x1 << 4);
355 u16 scissor_y1 = (u16)(regs.scissor_test.y1 << 4); 355 u16 scissor_y1 = (u16)(regs.rasterizer.scissor_test.y1 << 4);
356 // x2,y2 have +1 added to cover the entire sub-pixel area 356 // x2,y2 have +1 added to cover the entire sub-pixel area
357 u16 scissor_x2 = (u16)((regs.scissor_test.x2 + 1) << 4); 357 u16 scissor_x2 = (u16)((regs.rasterizer.scissor_test.x2 + 1) << 4);
358 u16 scissor_y2 = (u16)((regs.scissor_test.y2 + 1) << 4); 358 u16 scissor_y2 = (u16)((regs.rasterizer.scissor_test.y2 + 1) << 4);
359 359
360 if (regs.scissor_test.mode == Regs::ScissorMode::Include) { 360 if (regs.rasterizer.scissor_test.mode == RasterizerRegs::ScissorMode::Include) {
361 // Calculate the new bounds 361 // Calculate the new bounds
362 min_x = std::max(min_x, scissor_x1); 362 min_x = std::max(min_x, scissor_x1);
363 min_y = std::max(min_y, scissor_y1); 363 min_y = std::max(min_y, scissor_y1);
@@ -397,12 +397,13 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
397 397
398 auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w); 398 auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w);
399 399
400 auto textures = regs.GetTextures(); 400 auto textures = regs.texturing.GetTextures();
401 auto tev_stages = regs.GetTevStages(); 401 auto tev_stages = regs.texturing.GetTevStages();
402 402
403 bool stencil_action_enable = g_state.regs.output_merger.stencil_test.enable && 403 bool stencil_action_enable =
404 g_state.regs.framebuffer.depth_format == Regs::DepthFormat::D24S8; 404 g_state.regs.framebuffer.output_merger.stencil_test.enable &&
405 const auto stencil_test = g_state.regs.output_merger.stencil_test; 405 g_state.regs.framebuffer.framebuffer.depth_format == FramebufferRegs::DepthFormat::D24S8;
406 const auto stencil_test = g_state.regs.framebuffer.output_merger.stencil_test;
406 407
407 // Enter rasterization loop, starting at the center of the topleft bounding box corner. 408 // Enter rasterization loop, starting at the center of the topleft bounding box corner.
408 // TODO: Not sure if looping through x first might be faster 409 // TODO: Not sure if looping through x first might be faster
@@ -411,7 +412,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
411 412
412 // Do not process the pixel if it's inside the scissor box and the scissor mode is set 413 // Do not process the pixel if it's inside the scissor box and the scissor mode is set
413 // to Exclude 414 // to Exclude
414 if (regs.scissor_test.mode == Regs::ScissorMode::Exclude) { 415 if (regs.rasterizer.scissor_test.mode == RasterizerRegs::ScissorMode::Exclude) {
415 if (x >= scissor_x1 && x < scissor_x2 && y >= scissor_y1 && y < scissor_y2) 416 if (x >= scissor_x1 && x < scissor_x2 && y >= scissor_y1 && y < scissor_y2)
416 continue; 417 continue;
417 } 418 }
@@ -441,12 +442,14 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
441 442
442 // Not fully accurate. About 3 bits in precision are missing. 443 // Not fully accurate. About 3 bits in precision are missing.
443 // Z-Buffer (z / w * scale + offset) 444 // Z-Buffer (z / w * scale + offset)
444 float depth_scale = float24::FromRaw(regs.viewport_depth_range).ToFloat32(); 445 float depth_scale = float24::FromRaw(regs.rasterizer.viewport_depth_range).ToFloat32();
445 float depth_offset = float24::FromRaw(regs.viewport_depth_near_plane).ToFloat32(); 446 float depth_offset =
447 float24::FromRaw(regs.rasterizer.viewport_depth_near_plane).ToFloat32();
446 float depth = interpolated_z_over_w * depth_scale + depth_offset; 448 float depth = interpolated_z_over_w * depth_scale + depth_offset;
447 449
448 // Potentially switch to W-Buffer 450 // Potentially switch to W-Buffer
449 if (regs.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) { 451 if (regs.rasterizer.depthmap_enable ==
452 Pica::RasterizerRegs::DepthBuffering::WBuffering) {
450 // W-Buffer (z * scale + w * offset = (z / w * scale + offset) * w) 453 // W-Buffer (z * scale + w * offset = (z / w * scale + offset) * w)
451 depth *= interpolated_w_inverse.ToFloat32() * wsum; 454 depth *= interpolated_w_inverse.ToFloat32() * wsum;
452 } 455 }
@@ -513,9 +516,9 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
513 // TODO: Refactor so cubemaps and shadowmaps can be handled 516 // TODO: Refactor so cubemaps and shadowmaps can be handled
514 if (i == 0) { 517 if (i == 0) {
515 switch (texture.config.type) { 518 switch (texture.config.type) {
516 case Regs::TextureConfig::Texture2D: 519 case TexturingRegs::TextureConfig::Texture2D:
517 break; 520 break;
518 case Regs::TextureConfig::Projection2D: { 521 case TexturingRegs::TextureConfig::Projection2D: {
519 auto tc0_w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w); 522 auto tc0_w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w);
520 u /= tc0_w; 523 u /= tc0_w;
521 v /= tc0_w; 524 v /= tc0_w;
@@ -534,21 +537,21 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
534 int t = (int)(v * float24::FromFloat32(static_cast<float>(texture.config.height))) 537 int t = (int)(v * float24::FromFloat32(static_cast<float>(texture.config.height)))
535 .ToFloat32(); 538 .ToFloat32();
536 539
537 static auto GetWrappedTexCoord = [](Regs::TextureConfig::WrapMode mode, int val, 540 static auto GetWrappedTexCoord = [](TexturingRegs::TextureConfig::WrapMode mode,
538 unsigned size) { 541 int val, unsigned size) {
539 switch (mode) { 542 switch (mode) {
540 case Regs::TextureConfig::ClampToEdge: 543 case TexturingRegs::TextureConfig::ClampToEdge:
541 val = std::max(val, 0); 544 val = std::max(val, 0);
542 val = std::min(val, (int)size - 1); 545 val = std::min(val, (int)size - 1);
543 return val; 546 return val;
544 547
545 case Regs::TextureConfig::ClampToBorder: 548 case TexturingRegs::TextureConfig::ClampToBorder:
546 return val; 549 return val;
547 550
548 case Regs::TextureConfig::Repeat: 551 case TexturingRegs::TextureConfig::Repeat:
549 return (int)((unsigned)val % size); 552 return (int)((unsigned)val % size);
550 553
551 case Regs::TextureConfig::MirroredRepeat: { 554 case TexturingRegs::TextureConfig::MirroredRepeat: {
552 unsigned int coord = ((unsigned)val % (2 * size)); 555 unsigned int coord = ((unsigned)val % (2 * size));
553 if (coord >= size) 556 if (coord >= size)
554 coord = 2 * size - 1 - coord; 557 coord = 2 * size - 1 - coord;
@@ -562,9 +565,9 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
562 } 565 }
563 }; 566 };
564 567
565 if ((texture.config.wrap_s == Regs::TextureConfig::ClampToBorder && 568 if ((texture.config.wrap_s == TexturingRegs::TextureConfig::ClampToBorder &&
566 (s < 0 || static_cast<u32>(s) >= texture.config.width)) || 569 (s < 0 || static_cast<u32>(s) >= texture.config.width)) ||
567 (texture.config.wrap_t == Regs::TextureConfig::ClampToBorder && 570 (texture.config.wrap_t == TexturingRegs::TextureConfig::ClampToBorder &&
568 (t < 0 || static_cast<u32>(t) >= texture.config.height))) { 571 (t < 0 || static_cast<u32>(t) >= texture.config.height))) {
569 auto border_color = texture.config.border_color; 572 auto border_color = texture.config.border_color;
570 texture_color[i] = {border_color.r, border_color.g, border_color.b, 573 texture_color[i] = {border_color.r, border_color.g, border_color.b,
@@ -600,17 +603,19 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
600 Math::Vec4<u8> combiner_output; 603 Math::Vec4<u8> combiner_output;
601 Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0}; 604 Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0};
602 Math::Vec4<u8> next_combiner_buffer = { 605 Math::Vec4<u8> next_combiner_buffer = {
603 regs.tev_combiner_buffer_color.r, regs.tev_combiner_buffer_color.g, 606 regs.texturing.tev_combiner_buffer_color.r,
604 regs.tev_combiner_buffer_color.b, regs.tev_combiner_buffer_color.a, 607 regs.texturing.tev_combiner_buffer_color.g,
608 regs.texturing.tev_combiner_buffer_color.b,
609 regs.texturing.tev_combiner_buffer_color.a,
605 }; 610 };
606 611
607 for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); 612 for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size();
608 ++tev_stage_index) { 613 ++tev_stage_index) {
609 const auto& tev_stage = tev_stages[tev_stage_index]; 614 const auto& tev_stage = tev_stages[tev_stage_index];
610 using Source = Regs::TevStageConfig::Source; 615 using Source = TexturingRegs::TevStageConfig::Source;
611 using ColorModifier = Regs::TevStageConfig::ColorModifier; 616 using ColorModifier = TexturingRegs::TevStageConfig::ColorModifier;
612 using AlphaModifier = Regs::TevStageConfig::AlphaModifier; 617 using AlphaModifier = TexturingRegs::TevStageConfig::AlphaModifier;
613 using Operation = Regs::TevStageConfig::Operation; 618 using Operation = TexturingRegs::TevStageConfig::Operation;
614 619
615 auto GetSource = [&](Source source) -> Math::Vec4<u8> { 620 auto GetSource = [&](Source source) -> Math::Vec4<u8> {
616 switch (source) { 621 switch (source) {
@@ -862,54 +867,54 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
862 867
863 combiner_buffer = next_combiner_buffer; 868 combiner_buffer = next_combiner_buffer;
864 869
865 if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor( 870 if (regs.texturing.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(
866 tev_stage_index)) { 871 tev_stage_index)) {
867 next_combiner_buffer.r() = combiner_output.r(); 872 next_combiner_buffer.r() = combiner_output.r();
868 next_combiner_buffer.g() = combiner_output.g(); 873 next_combiner_buffer.g() = combiner_output.g();
869 next_combiner_buffer.b() = combiner_output.b(); 874 next_combiner_buffer.b() = combiner_output.b();
870 } 875 }
871 876
872 if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha( 877 if (regs.texturing.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(
873 tev_stage_index)) { 878 tev_stage_index)) {
874 next_combiner_buffer.a() = combiner_output.a(); 879 next_combiner_buffer.a() = combiner_output.a();
875 } 880 }
876 } 881 }
877 882
878 const auto& output_merger = regs.output_merger; 883 const auto& output_merger = regs.framebuffer.output_merger;
879 // TODO: Does alpha testing happen before or after stencil? 884 // TODO: Does alpha testing happen before or after stencil?
880 if (output_merger.alpha_test.enable) { 885 if (output_merger.alpha_test.enable) {
881 bool pass = false; 886 bool pass = false;
882 887
883 switch (output_merger.alpha_test.func) { 888 switch (output_merger.alpha_test.func) {
884 case Regs::CompareFunc::Never: 889 case FramebufferRegs::CompareFunc::Never:
885 pass = false; 890 pass = false;
886 break; 891 break;
887 892
888 case Regs::CompareFunc::Always: 893 case FramebufferRegs::CompareFunc::Always:
889 pass = true; 894 pass = true;
890 break; 895 break;
891 896
892 case Regs::CompareFunc::Equal: 897 case FramebufferRegs::CompareFunc::Equal:
893 pass = combiner_output.a() == output_merger.alpha_test.ref; 898 pass = combiner_output.a() == output_merger.alpha_test.ref;
894 break; 899 break;
895 900
896 case Regs::CompareFunc::NotEqual: 901 case FramebufferRegs::CompareFunc::NotEqual:
897 pass = combiner_output.a() != output_merger.alpha_test.ref; 902 pass = combiner_output.a() != output_merger.alpha_test.ref;
898 break; 903 break;
899 904
900 case Regs::CompareFunc::LessThan: 905 case FramebufferRegs::CompareFunc::LessThan:
901 pass = combiner_output.a() < output_merger.alpha_test.ref; 906 pass = combiner_output.a() < output_merger.alpha_test.ref;
902 break; 907 break;
903 908
904 case Regs::CompareFunc::LessThanOrEqual: 909 case FramebufferRegs::CompareFunc::LessThanOrEqual:
905 pass = combiner_output.a() <= output_merger.alpha_test.ref; 910 pass = combiner_output.a() <= output_merger.alpha_test.ref;
906 break; 911 break;
907 912
908 case Regs::CompareFunc::GreaterThan: 913 case FramebufferRegs::CompareFunc::GreaterThan:
909 pass = combiner_output.a() > output_merger.alpha_test.ref; 914 pass = combiner_output.a() > output_merger.alpha_test.ref;
910 break; 915 break;
911 916
912 case Regs::CompareFunc::GreaterThanOrEqual: 917 case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
913 pass = combiner_output.a() >= output_merger.alpha_test.ref; 918 pass = combiner_output.a() >= output_merger.alpha_test.ref;
914 break; 919 break;
915 } 920 }
@@ -922,16 +927,16 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
922 // Not fully accurate. We'd have to know what data type is used to 927 // Not fully accurate. We'd have to know what data type is used to
923 // store the depth etc. Using float for now until we know more 928 // store the depth etc. Using float for now until we know more
924 // about Pica datatypes 929 // about Pica datatypes
925 if (regs.fog_mode == Regs::FogMode::Fog) { 930 if (regs.texturing.fog_mode == TexturingRegs::FogMode::Fog) {
926 const Math::Vec3<u8> fog_color = { 931 const Math::Vec3<u8> fog_color = {
927 static_cast<u8>(regs.fog_color.r.Value()), 932 static_cast<u8>(regs.texturing.fog_color.r.Value()),
928 static_cast<u8>(regs.fog_color.g.Value()), 933 static_cast<u8>(regs.texturing.fog_color.g.Value()),
929 static_cast<u8>(regs.fog_color.b.Value()), 934 static_cast<u8>(regs.texturing.fog_color.b.Value()),
930 }; 935 };
931 936
932 // Get index into fog LUT 937 // Get index into fog LUT
933 float fog_index; 938 float fog_index;
934 if (g_state.regs.fog_flip) { 939 if (g_state.regs.texturing.fog_flip) {
935 fog_index = (1.0f - depth) * 128.0f; 940 fog_index = (1.0f - depth) * 128.0f;
936 } else { 941 } else {
937 fog_index = depth * 128.0f; 942 fog_index = depth * 128.0f;
@@ -955,10 +960,10 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
955 u8 old_stencil = 0; 960 u8 old_stencil = 0;
956 961
957 auto UpdateStencil = [stencil_test, x, y, 962 auto UpdateStencil = [stencil_test, x, y,
958 &old_stencil](Pica::Regs::StencilAction action) { 963 &old_stencil](Pica::FramebufferRegs::StencilAction action) {
959 u8 new_stencil = 964 u8 new_stencil =
960 PerformStencilAction(action, old_stencil, stencil_test.reference_value); 965 PerformStencilAction(action, old_stencil, stencil_test.reference_value);
961 if (g_state.regs.framebuffer.allow_depth_stencil_write != 0) 966 if (g_state.regs.framebuffer.framebuffer.allow_depth_stencil_write != 0)
962 SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) | 967 SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) |
963 (old_stencil & ~stencil_test.write_mask)); 968 (old_stencil & ~stencil_test.write_mask));
964 }; 969 };
@@ -970,35 +975,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
970 975
971 bool pass = false; 976 bool pass = false;
972 switch (stencil_test.func) { 977 switch (stencil_test.func) {
973 case Regs::CompareFunc::Never: 978 case FramebufferRegs::CompareFunc::Never:
974 pass = false; 979 pass = false;
975 break; 980 break;
976 981
977 case Regs::CompareFunc::Always: 982 case FramebufferRegs::CompareFunc::Always:
978 pass = true; 983 pass = true;
979 break; 984 break;
980 985
981 case Regs::CompareFunc::Equal: 986 case FramebufferRegs::CompareFunc::Equal:
982 pass = (ref == dest); 987 pass = (ref == dest);
983 break; 988 break;
984 989
985 case Regs::CompareFunc::NotEqual: 990 case FramebufferRegs::CompareFunc::NotEqual:
986 pass = (ref != dest); 991 pass = (ref != dest);
987 break; 992 break;
988 993
989 case Regs::CompareFunc::LessThan: 994 case FramebufferRegs::CompareFunc::LessThan:
990 pass = (ref < dest); 995 pass = (ref < dest);
991 break; 996 break;
992 997
993 case Regs::CompareFunc::LessThanOrEqual: 998 case FramebufferRegs::CompareFunc::LessThanOrEqual:
994 pass = (ref <= dest); 999 pass = (ref <= dest);
995 break; 1000 break;
996 1001
997 case Regs::CompareFunc::GreaterThan: 1002 case FramebufferRegs::CompareFunc::GreaterThan:
998 pass = (ref > dest); 1003 pass = (ref > dest);
999 break; 1004 break;
1000 1005
1001 case Regs::CompareFunc::GreaterThanOrEqual: 1006 case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
1002 pass = (ref >= dest); 1007 pass = (ref >= dest);
1003 break; 1008 break;
1004 } 1009 }
@@ -1010,7 +1015,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1010 } 1015 }
1011 1016
1012 // Convert float to integer 1017 // Convert float to integer
1013 unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format); 1018 unsigned num_bits =
1019 FramebufferRegs::DepthBitsPerPixel(regs.framebuffer.framebuffer.depth_format);
1014 u32 z = (u32)(depth * ((1 << num_bits) - 1)); 1020 u32 z = (u32)(depth * ((1 << num_bits) - 1));
1015 1021
1016 if (output_merger.depth_test_enable) { 1022 if (output_merger.depth_test_enable) {
@@ -1019,35 +1025,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1019 bool pass = false; 1025 bool pass = false;
1020 1026
1021 switch (output_merger.depth_test_func) { 1027 switch (output_merger.depth_test_func) {
1022 case Regs::CompareFunc::Never: 1028 case FramebufferRegs::CompareFunc::Never:
1023 pass = false; 1029 pass = false;
1024 break; 1030 break;
1025 1031
1026 case Regs::CompareFunc::Always: 1032 case FramebufferRegs::CompareFunc::Always:
1027 pass = true; 1033 pass = true;
1028 break; 1034 break;
1029 1035
1030 case Regs::CompareFunc::Equal: 1036 case FramebufferRegs::CompareFunc::Equal:
1031 pass = z == ref_z; 1037 pass = z == ref_z;
1032 break; 1038 break;
1033 1039
1034 case Regs::CompareFunc::NotEqual: 1040 case FramebufferRegs::CompareFunc::NotEqual:
1035 pass = z != ref_z; 1041 pass = z != ref_z;
1036 break; 1042 break;
1037 1043
1038 case Regs::CompareFunc::LessThan: 1044 case FramebufferRegs::CompareFunc::LessThan:
1039 pass = z < ref_z; 1045 pass = z < ref_z;
1040 break; 1046 break;
1041 1047
1042 case Regs::CompareFunc::LessThanOrEqual: 1048 case FramebufferRegs::CompareFunc::LessThanOrEqual:
1043 pass = z <= ref_z; 1049 pass = z <= ref_z;
1044 break; 1050 break;
1045 1051
1046 case Regs::CompareFunc::GreaterThan: 1052 case FramebufferRegs::CompareFunc::GreaterThan:
1047 pass = z > ref_z; 1053 pass = z > ref_z;
1048 break; 1054 break;
1049 1055
1050 case Regs::CompareFunc::GreaterThanOrEqual: 1056 case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
1051 pass = z >= ref_z; 1057 pass = z >= ref_z;
1052 break; 1058 break;
1053 } 1059 }
@@ -1059,8 +1065,11 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1059 } 1065 }
1060 } 1066 }
1061 1067
1062 if (regs.framebuffer.allow_depth_stencil_write != 0 && output_merger.depth_write_enable) 1068 if (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 &&
1069 output_merger.depth_write_enable) {
1070
1063 SetDepth(x >> 4, y >> 4, z); 1071 SetDepth(x >> 4, y >> 4, z);
1072 }
1064 1073
1065 // The stencil depth_pass action is executed even if depth testing is disabled 1074 // The stencil depth_pass action is executed even if depth testing is disabled
1066 if (stencil_action_enable) 1075 if (stencil_action_enable)
@@ -1072,7 +1081,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1072 if (output_merger.alphablend_enable) { 1081 if (output_merger.alphablend_enable) {
1073 auto params = output_merger.alpha_blending; 1082 auto params = output_merger.alpha_blending;
1074 1083
1075 auto LookupFactor = [&](unsigned channel, Regs::BlendFactor factor) -> u8 { 1084 auto LookupFactor = [&](unsigned channel,
1085 FramebufferRegs::BlendFactor factor) -> u8 {
1076 DEBUG_ASSERT(channel < 4); 1086 DEBUG_ASSERT(channel < 4);
1077 1087
1078 const Math::Vec4<u8> blend_const = { 1088 const Math::Vec4<u8> blend_const = {
@@ -1083,49 +1093,49 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1083 }; 1093 };
1084 1094
1085 switch (factor) { 1095 switch (factor) {
1086 case Regs::BlendFactor::Zero: 1096 case FramebufferRegs::BlendFactor::Zero:
1087 return 0; 1097 return 0;
1088 1098
1089 case Regs::BlendFactor::One: 1099 case FramebufferRegs::BlendFactor::One:
1090 return 255; 1100 return 255;
1091 1101
1092 case Regs::BlendFactor::SourceColor: 1102 case FramebufferRegs::BlendFactor::SourceColor:
1093 return combiner_output[channel]; 1103 return combiner_output[channel];
1094 1104
1095 case Regs::BlendFactor::OneMinusSourceColor: 1105 case FramebufferRegs::BlendFactor::OneMinusSourceColor:
1096 return 255 - combiner_output[channel]; 1106 return 255 - combiner_output[channel];
1097 1107
1098 case Regs::BlendFactor::DestColor: 1108 case FramebufferRegs::BlendFactor::DestColor:
1099 return dest[channel]; 1109 return dest[channel];
1100 1110
1101 case Regs::BlendFactor::OneMinusDestColor: 1111 case FramebufferRegs::BlendFactor::OneMinusDestColor:
1102 return 255 - dest[channel]; 1112 return 255 - dest[channel];
1103 1113
1104 case Regs::BlendFactor::SourceAlpha: 1114 case FramebufferRegs::BlendFactor::SourceAlpha:
1105 return combiner_output.a(); 1115 return combiner_output.a();
1106 1116
1107 case Regs::BlendFactor::OneMinusSourceAlpha: 1117 case FramebufferRegs::BlendFactor::OneMinusSourceAlpha:
1108 return 255 - combiner_output.a(); 1118 return 255 - combiner_output.a();
1109 1119
1110 case Regs::BlendFactor::DestAlpha: 1120 case FramebufferRegs::BlendFactor::DestAlpha:
1111 return dest.a(); 1121 return dest.a();
1112 1122
1113 case Regs::BlendFactor::OneMinusDestAlpha: 1123 case FramebufferRegs::BlendFactor::OneMinusDestAlpha:
1114 return 255 - dest.a(); 1124 return 255 - dest.a();
1115 1125
1116 case Regs::BlendFactor::ConstantColor: 1126 case FramebufferRegs::BlendFactor::ConstantColor:
1117 return blend_const[channel]; 1127 return blend_const[channel];
1118 1128
1119 case Regs::BlendFactor::OneMinusConstantColor: 1129 case FramebufferRegs::BlendFactor::OneMinusConstantColor:
1120 return 255 - blend_const[channel]; 1130 return 255 - blend_const[channel];
1121 1131
1122 case Regs::BlendFactor::ConstantAlpha: 1132 case FramebufferRegs::BlendFactor::ConstantAlpha:
1123 return blend_const.a(); 1133 return blend_const.a();
1124 1134
1125 case Regs::BlendFactor::OneMinusConstantAlpha: 1135 case FramebufferRegs::BlendFactor::OneMinusConstantAlpha:
1126 return 255 - blend_const.a(); 1136 return 255 - blend_const.a();
1127 1137
1128 case Regs::BlendFactor::SourceAlphaSaturate: 1138 case FramebufferRegs::BlendFactor::SourceAlphaSaturate:
1129 // Returns 1.0 for the alpha channel 1139 // Returns 1.0 for the alpha channel
1130 if (channel == 3) 1140 if (channel == 3)
1131 return 255; 1141 return 255;
@@ -1143,36 +1153,37 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1143 static auto EvaluateBlendEquation = []( 1153 static auto EvaluateBlendEquation = [](
1144 const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor, 1154 const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
1145 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor, 1155 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
1146 Regs::BlendEquation equation) { 1156 FramebufferRegs::BlendEquation equation) {
1157
1147 Math::Vec4<int> result; 1158 Math::Vec4<int> result;
1148 1159
1149 auto src_result = (src * srcfactor).Cast<int>(); 1160 auto src_result = (src * srcfactor).Cast<int>();
1150 auto dst_result = (dest * destfactor).Cast<int>(); 1161 auto dst_result = (dest * destfactor).Cast<int>();
1151 1162
1152 switch (equation) { 1163 switch (equation) {
1153 case Regs::BlendEquation::Add: 1164 case FramebufferRegs::BlendEquation::Add:
1154 result = (src_result + dst_result) / 255; 1165 result = (src_result + dst_result) / 255;
1155 break; 1166 break;
1156 1167
1157 case Regs::BlendEquation::Subtract: 1168 case FramebufferRegs::BlendEquation::Subtract:
1158 result = (src_result - dst_result) / 255; 1169 result = (src_result - dst_result) / 255;
1159 break; 1170 break;
1160 1171
1161 case Regs::BlendEquation::ReverseSubtract: 1172 case FramebufferRegs::BlendEquation::ReverseSubtract:
1162 result = (dst_result - src_result) / 255; 1173 result = (dst_result - src_result) / 255;
1163 break; 1174 break;
1164 1175
1165 // TODO: How do these two actually work? 1176 // TODO: How do these two actually work?
1166 // OpenGL doesn't include the blend factors in the min/max computations, 1177 // OpenGL doesn't include the blend factors in the min/max computations,
1167 // but is this what the 3DS actually does? 1178 // but is this what the 3DS actually does?
1168 case Regs::BlendEquation::Min: 1179 case FramebufferRegs::BlendEquation::Min:
1169 result.r() = std::min(src.r(), dest.r()); 1180 result.r() = std::min(src.r(), dest.r());
1170 result.g() = std::min(src.g(), dest.g()); 1181 result.g() = std::min(src.g(), dest.g());
1171 result.b() = std::min(src.b(), dest.b()); 1182 result.b() = std::min(src.b(), dest.b());
1172 result.a() = std::min(src.a(), dest.a()); 1183 result.a() = std::min(src.a(), dest.a());
1173 break; 1184 break;
1174 1185
1175 case Regs::BlendEquation::Max: 1186 case FramebufferRegs::BlendEquation::Max:
1176 result.r() = std::max(src.r(), dest.r()); 1187 result.r() = std::max(src.r(), dest.r());
1177 result.g() = std::max(src.g(), dest.g()); 1188 result.g() = std::max(src.g(), dest.g());
1178 result.b() = std::max(src.b(), dest.b()); 1189 result.b() = std::max(src.b(), dest.b());
@@ -1205,54 +1216,54 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1205 dstfactor, params.blend_equation_a) 1216 dstfactor, params.blend_equation_a)
1206 .a(); 1217 .a();
1207 } else { 1218 } else {
1208 static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 { 1219 static auto LogicOp = [](u8 src, u8 dest, FramebufferRegs::LogicOp op) -> u8 {
1209 switch (op) { 1220 switch (op) {
1210 case Regs::LogicOp::Clear: 1221 case FramebufferRegs::LogicOp::Clear:
1211 return 0; 1222 return 0;
1212 1223
1213 case Regs::LogicOp::And: 1224 case FramebufferRegs::LogicOp::And:
1214 return src & dest; 1225 return src & dest;
1215 1226
1216 case Regs::LogicOp::AndReverse: 1227 case FramebufferRegs::LogicOp::AndReverse:
1217 return src & ~dest; 1228 return src & ~dest;
1218 1229
1219 case Regs::LogicOp::Copy: 1230 case FramebufferRegs::LogicOp::Copy:
1220 return src; 1231 return src;
1221 1232
1222 case Regs::LogicOp::Set: 1233 case FramebufferRegs::LogicOp::Set:
1223 return 255; 1234 return 255;
1224 1235
1225 case Regs::LogicOp::CopyInverted: 1236 case FramebufferRegs::LogicOp::CopyInverted:
1226 return ~src; 1237 return ~src;
1227 1238
1228 case Regs::LogicOp::NoOp: 1239 case FramebufferRegs::LogicOp::NoOp:
1229 return dest; 1240 return dest;
1230 1241
1231 case Regs::LogicOp::Invert: 1242 case FramebufferRegs::LogicOp::Invert:
1232 return ~dest; 1243 return ~dest;
1233 1244
1234 case Regs::LogicOp::Nand: 1245 case FramebufferRegs::LogicOp::Nand:
1235 return ~(src & dest); 1246 return ~(src & dest);
1236 1247
1237 case Regs::LogicOp::Or: 1248 case FramebufferRegs::LogicOp::Or:
1238 return src | dest; 1249 return src | dest;
1239 1250
1240 case Regs::LogicOp::Nor: 1251 case FramebufferRegs::LogicOp::Nor:
1241 return ~(src | dest); 1252 return ~(src | dest);
1242 1253
1243 case Regs::LogicOp::Xor: 1254 case FramebufferRegs::LogicOp::Xor:
1244 return src ^ dest; 1255 return src ^ dest;
1245 1256
1246 case Regs::LogicOp::Equiv: 1257 case FramebufferRegs::LogicOp::Equiv:
1247 return ~(src ^ dest); 1258 return ~(src ^ dest);
1248 1259
1249 case Regs::LogicOp::AndInverted: 1260 case FramebufferRegs::LogicOp::AndInverted:
1250 return ~src & dest; 1261 return ~src & dest;
1251 1262
1252 case Regs::LogicOp::OrReverse: 1263 case FramebufferRegs::LogicOp::OrReverse:
1253 return src | ~dest; 1264 return src | ~dest;
1254 1265
1255 case Regs::LogicOp::OrInverted: 1266 case FramebufferRegs::LogicOp::OrInverted:
1256 return ~src | dest; 1267 return ~src | dest;
1257 } 1268 }
1258 }; 1269 };
@@ -1271,7 +1282,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
1271 output_merger.alpha_enable ? blend_output.a() : dest.a(), 1282 output_merger.alpha_enable ? blend_output.a() : dest.a(),
1272 }; 1283 };
1273 1284
1274 if (regs.framebuffer.allow_color_write != 0) 1285 if (regs.framebuffer.framebuffer.allow_color_write != 0)
1275 DrawPixel(x >> 4, y >> 4, result); 1286 DrawPixel(x >> 4, y >> 4, result);
1276 } 1287 }
1277 } 1288 }
diff --git a/src/video_core/regs.cpp b/src/video_core/regs.cpp
new file mode 100644
index 000000000..f47e9e763
--- /dev/null
+++ b/src/video_core/regs.cpp
@@ -0,0 +1,493 @@
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 <iterator>
6#include <unordered_map>
7#include <utility>
8
9#include "common/common_types.h"
10#include "video_core/regs.h"
11
12namespace Pica {
13
14static const std::pair<u16, const char*> register_names[] = {
15 {0x010, "GPUREG_FINALIZE"},
16
17 {0x040, "GPUREG_FACECULLING_CONFIG"},
18 {0x041, "GPUREG_VIEWPORT_WIDTH"},
19 {0x042, "GPUREG_VIEWPORT_INVW"},
20 {0x043, "GPUREG_VIEWPORT_HEIGHT"},
21 {0x044, "GPUREG_VIEWPORT_INVH"},
22
23 {0x047, "GPUREG_FRAGOP_CLIP"},
24 {0x048, "GPUREG_FRAGOP_CLIP_DATA0"},
25 {0x049, "GPUREG_FRAGOP_CLIP_DATA1"},
26 {0x04A, "GPUREG_FRAGOP_CLIP_DATA2"},
27 {0x04B, "GPUREG_FRAGOP_CLIP_DATA3"},
28
29 {0x04D, "GPUREG_DEPTHMAP_SCALE"},
30 {0x04E, "GPUREG_DEPTHMAP_OFFSET"},
31 {0x04F, "GPUREG_SH_OUTMAP_TOTAL"},
32 {0x050, "GPUREG_SH_OUTMAP_O0"},
33 {0x051, "GPUREG_SH_OUTMAP_O1"},
34 {0x052, "GPUREG_SH_OUTMAP_O2"},
35 {0x053, "GPUREG_SH_OUTMAP_O3"},
36 {0x054, "GPUREG_SH_OUTMAP_O4"},
37 {0x055, "GPUREG_SH_OUTMAP_O5"},
38 {0x056, "GPUREG_SH_OUTMAP_O6"},
39
40 {0x061, "GPUREG_EARLYDEPTH_FUNC"},
41 {0x062, "GPUREG_EARLYDEPTH_TEST1"},
42 {0x063, "GPUREG_EARLYDEPTH_CLEAR"},
43 {0x064, "GPUREG_SH_OUTATTR_MODE"},
44 {0x065, "GPUREG_SCISSORTEST_MODE"},
45 {0x066, "GPUREG_SCISSORTEST_POS"},
46 {0x067, "GPUREG_SCISSORTEST_DIM"},
47 {0x068, "GPUREG_VIEWPORT_XY"},
48
49 {0x06A, "GPUREG_EARLYDEPTH_DATA"},
50
51 {0x06D, "GPUREG_DEPTHMAP_ENABLE"},
52 {0x06E, "GPUREG_RENDERBUF_DIM"},
53 {0x06F, "GPUREG_SH_OUTATTR_CLOCK"},
54
55 {0x080, "GPUREG_TEXUNIT_CONFIG"},
56 {0x081, "GPUREG_TEXUNIT0_BORDER_COLOR"},
57 {0x082, "GPUREG_TEXUNIT0_DIM"},
58 {0x083, "GPUREG_TEXUNIT0_PARAM"},
59 {0x084, "GPUREG_TEXUNIT0_LOD"},
60 {0x085, "GPUREG_TEXUNIT0_ADDR1"},
61 {0x086, "GPUREG_TEXUNIT0_ADDR2"},
62 {0x087, "GPUREG_TEXUNIT0_ADDR3"},
63 {0x088, "GPUREG_TEXUNIT0_ADDR4"},
64 {0x089, "GPUREG_TEXUNIT0_ADDR5"},
65 {0x08A, "GPUREG_TEXUNIT0_ADDR6"},
66 {0x08B, "GPUREG_TEXUNIT0_SHADOW"},
67
68 {0x08E, "GPUREG_TEXUNIT0_TYPE"},
69 {0x08F, "GPUREG_LIGHTING_ENABLE0"},
70
71 {0x091, "GPUREG_TEXUNIT1_BORDER_COLOR"},
72 {0x092, "GPUREG_TEXUNIT1_DIM"},
73 {0x093, "GPUREG_TEXUNIT1_PARAM"},
74 {0x094, "GPUREG_TEXUNIT1_LOD"},
75 {0x095, "GPUREG_TEXUNIT1_ADDR"},
76 {0x096, "GPUREG_TEXUNIT1_TYPE"},
77
78 {0x099, "GPUREG_TEXUNIT2_BORDER_COLOR"},
79 {0x09A, "GPUREG_TEXUNIT2_DIM"},
80 {0x09B, "GPUREG_TEXUNIT2_PARAM"},
81 {0x09C, "GPUREG_TEXUNIT2_LOD"},
82 {0x09D, "GPUREG_TEXUNIT2_ADDR"},
83 {0x09E, "GPUREG_TEXUNIT2_TYPE"},
84
85 {0x0A8, "GPUREG_TEXUNIT3_PROCTEX0"},
86 {0x0A9, "GPUREG_TEXUNIT3_PROCTEX1"},
87 {0x0AA, "GPUREG_TEXUNIT3_PROCTEX2"},
88 {0x0AB, "GPUREG_TEXUNIT3_PROCTEX3"},
89 {0x0AC, "GPUREG_TEXUNIT3_PROCTEX4"},
90 {0x0AD, "GPUREG_TEXUNIT3_PROCTEX5"},
91
92 {0x0AF, "GPUREG_PROCTEX_LUT"},
93 {0x0B0, "GPUREG_PROCTEX_LUT_DATA0"},
94 {0x0B1, "GPUREG_PROCTEX_LUT_DATA1"},
95 {0x0B2, "GPUREG_PROCTEX_LUT_DATA2"},
96 {0x0B3, "GPUREG_PROCTEX_LUT_DATA3"},
97 {0x0B4, "GPUREG_PROCTEX_LUT_DATA4"},
98 {0x0B5, "GPUREG_PROCTEX_LUT_DATA5"},
99 {0x0B6, "GPUREG_PROCTEX_LUT_DATA6"},
100 {0x0B7, "GPUREG_PROCTEX_LUT_DATA7"},
101
102 {0x0C0, "GPUREG_TEXENV0_SOURCE"},
103 {0x0C1, "GPUREG_TEXENV0_OPERAND"},
104 {0x0C2, "GPUREG_TEXENV0_COMBINER"},
105 {0x0C3, "GPUREG_TEXENV0_COLOR"},
106 {0x0C4, "GPUREG_TEXENV0_SCALE"},
107
108 {0x0C8, "GPUREG_TEXENV1_SOURCE"},
109 {0x0C9, "GPUREG_TEXENV1_OPERAND"},
110 {0x0CA, "GPUREG_TEXENV1_COMBINER"},
111 {0x0CB, "GPUREG_TEXENV1_COLOR"},
112 {0x0CC, "GPUREG_TEXENV1_SCALE"},
113
114 {0x0D0, "GPUREG_TEXENV2_SOURCE"},
115 {0x0D1, "GPUREG_TEXENV2_OPERAND"},
116 {0x0D2, "GPUREG_TEXENV2_COMBINER"},
117 {0x0D3, "GPUREG_TEXENV2_COLOR"},
118 {0x0D4, "GPUREG_TEXENV2_SCALE"},
119
120 {0x0D8, "GPUREG_TEXENV3_SOURCE"},
121 {0x0D9, "GPUREG_TEXENV3_OPERAND"},
122 {0x0DA, "GPUREG_TEXENV3_COMBINER"},
123 {0x0DB, "GPUREG_TEXENV3_COLOR"},
124 {0x0DC, "GPUREG_TEXENV3_SCALE"},
125
126 {0x0E0, "GPUREG_TEXENV_UPDATE_BUFFER"},
127 {0x0E1, "GPUREG_FOG_COLOR"},
128
129 {0x0E4, "GPUREG_GAS_ATTENUATION"},
130 {0x0E5, "GPUREG_GAS_ACCMAX"},
131 {0x0E6, "GPUREG_FOG_LUT_INDEX"},
132
133 {0x0E8, "GPUREG_FOG_LUT_DATA0"},
134 {0x0E9, "GPUREG_FOG_LUT_DATA1"},
135 {0x0EA, "GPUREG_FOG_LUT_DATA2"},
136 {0x0EB, "GPUREG_FOG_LUT_DATA3"},
137 {0x0EC, "GPUREG_FOG_LUT_DATA4"},
138 {0x0ED, "GPUREG_FOG_LUT_DATA5"},
139 {0x0EE, "GPUREG_FOG_LUT_DATA6"},
140 {0x0EF, "GPUREG_FOG_LUT_DATA7"},
141 {0x0F0, "GPUREG_TEXENV4_SOURCE"},
142 {0x0F1, "GPUREG_TEXENV4_OPERAND"},
143 {0x0F2, "GPUREG_TEXENV4_COMBINER"},
144 {0x0F3, "GPUREG_TEXENV4_COLOR"},
145 {0x0F4, "GPUREG_TEXENV4_SCALE"},
146
147 {0x0F8, "GPUREG_TEXENV5_SOURCE"},
148 {0x0F9, "GPUREG_TEXENV5_OPERAND"},
149 {0x0FA, "GPUREG_TEXENV5_COMBINER"},
150 {0x0FB, "GPUREG_TEXENV5_COLOR"},
151 {0x0FC, "GPUREG_TEXENV5_SCALE"},
152 {0x0FD, "GPUREG_TEXENV_BUFFER_COLOR"},
153
154 {0x100, "GPUREG_COLOR_OPERATION"},
155 {0x101, "GPUREG_BLEND_FUNC"},
156 {0x102, "GPUREG_LOGIC_OP"},
157 {0x103, "GPUREG_BLEND_COLOR"},
158 {0x104, "GPUREG_FRAGOP_ALPHA_TEST"},
159 {0x105, "GPUREG_STENCIL_TEST"},
160 {0x106, "GPUREG_STENCIL_OP"},
161 {0x107, "GPUREG_DEPTH_COLOR_MASK"},
162
163 {0x110, "GPUREG_FRAMEBUFFER_INVALIDATE"},
164 {0x111, "GPUREG_FRAMEBUFFER_FLUSH"},
165 {0x112, "GPUREG_COLORBUFFER_READ"},
166 {0x113, "GPUREG_COLORBUFFER_WRITE"},
167 {0x114, "GPUREG_DEPTHBUFFER_READ"},
168 {0x115, "GPUREG_DEPTHBUFFER_WRITE"},
169 {0x116, "GPUREG_DEPTHBUFFER_FORMAT"},
170 {0x117, "GPUREG_COLORBUFFER_FORMAT"},
171 {0x118, "GPUREG_EARLYDEPTH_TEST2"},
172
173 {0x11B, "GPUREG_FRAMEBUFFER_BLOCK32"},
174 {0x11C, "GPUREG_DEPTHBUFFER_LOC"},
175 {0x11D, "GPUREG_COLORBUFFER_LOC"},
176 {0x11E, "GPUREG_FRAMEBUFFER_DIM"},
177
178 {0x120, "GPUREG_GAS_LIGHT_XY"},
179 {0x121, "GPUREG_GAS_LIGHT_Z"},
180 {0x122, "GPUREG_GAS_LIGHT_Z_COLOR"},
181 {0x123, "GPUREG_GAS_LUT_INDEX"},
182 {0x124, "GPUREG_GAS_LUT_DATA"},
183
184 {0x126, "GPUREG_GAS_DELTAZ_DEPTH"},
185
186 {0x130, "GPUREG_FRAGOP_SHADOW"},
187
188 {0x140, "GPUREG_LIGHT0_SPECULAR0"},
189 {0x141, "GPUREG_LIGHT0_SPECULAR1"},
190 {0x142, "GPUREG_LIGHT0_DIFFUSE"},
191 {0x143, "GPUREG_LIGHT0_AMBIENT"},
192 {0x144, "GPUREG_LIGHT0_XY"},
193 {0x145, "GPUREG_LIGHT0_Z"},
194 {0x146, "GPUREG_LIGHT0_SPOTDIR_XY"},
195 {0x147, "GPUREG_LIGHT0_SPOTDIR_Z"},
196
197 {0x149, "GPUREG_LIGHT0_CONFIG"},
198 {0x14A, "GPUREG_LIGHT0_ATTENUATION_BIAS"},
199 {0x14B, "GPUREG_LIGHT0_ATTENUATION_SCALE"},
200
201 {0x150, "GPUREG_LIGHT1_SPECULAR0"},
202 {0x151, "GPUREG_LIGHT1_SPECULAR1"},
203 {0x152, "GPUREG_LIGHT1_DIFFUSE"},
204 {0x153, "GPUREG_LIGHT1_AMBIENT"},
205 {0x154, "GPUREG_LIGHT1_XY"},
206 {0x155, "GPUREG_LIGHT1_Z"},
207 {0x156, "GPUREG_LIGHT1_SPOTDIR_XY"},
208 {0x157, "GPUREG_LIGHT1_SPOTDIR_Z"},
209
210 {0x159, "GPUREG_LIGHT1_CONFIG"},
211 {0x15A, "GPUREG_LIGHT1_ATTENUATION_BIAS"},
212 {0x15B, "GPUREG_LIGHT1_ATTENUATION_SCALE"},
213
214 {0x160, "GPUREG_LIGHT2_SPECULAR0"},
215 {0x161, "GPUREG_LIGHT2_SPECULAR1"},
216 {0x162, "GPUREG_LIGHT2_DIFFUSE"},
217 {0x163, "GPUREG_LIGHT2_AMBIENT"},
218 {0x164, "GPUREG_LIGHT2_XY"},
219 {0x165, "GPUREG_LIGHT2_Z"},
220 {0x166, "GPUREG_LIGHT2_SPOTDIR_XY"},
221 {0x167, "GPUREG_LIGHT2_SPOTDIR_Z"},
222
223 {0x169, "GPUREG_LIGHT2_CONFIG"},
224 {0x16A, "GPUREG_LIGHT2_ATTENUATION_BIAS"},
225 {0x16B, "GPUREG_LIGHT2_ATTENUATION_SCALE"},
226
227 {0x170, "GPUREG_LIGHT3_SPECULAR0"},
228 {0x171, "GPUREG_LIGHT3_SPECULAR1"},
229 {0x172, "GPUREG_LIGHT3_DIFFUSE"},
230 {0x173, "GPUREG_LIGHT3_AMBIENT"},
231 {0x174, "GPUREG_LIGHT3_XY"},
232 {0x175, "GPUREG_LIGHT3_Z"},
233 {0x176, "GPUREG_LIGHT3_SPOTDIR_XY"},
234 {0x177, "GPUREG_LIGHT3_SPOTDIR_Z"},
235
236 {0x179, "GPUREG_LIGHT3_CONFIG"},
237 {0x17A, "GPUREG_LIGHT3_ATTENUATION_BIAS"},
238 {0x17B, "GPUREG_LIGHT3_ATTENUATION_SCALE"},
239
240 {0x180, "GPUREG_LIGHT4_SPECULAR0"},
241 {0x181, "GPUREG_LIGHT4_SPECULAR1"},
242 {0x182, "GPUREG_LIGHT4_DIFFUSE"},
243 {0x183, "GPUREG_LIGHT4_AMBIENT"},
244 {0x184, "GPUREG_LIGHT4_XY"},
245 {0x185, "GPUREG_LIGHT4_Z"},
246 {0x186, "GPUREG_LIGHT4_SPOTDIR_XY"},
247 {0x187, "GPUREG_LIGHT4_SPOTDIR_Z"},
248
249 {0x189, "GPUREG_LIGHT4_CONFIG"},
250 {0x18A, "GPUREG_LIGHT4_ATTENUATION_BIAS"},
251 {0x18B, "GPUREG_LIGHT4_ATTENUATION_SCALE"},
252
253 {0x190, "GPUREG_LIGHT5_SPECULAR0"},
254 {0x191, "GPUREG_LIGHT5_SPECULAR1"},
255 {0x192, "GPUREG_LIGHT5_DIFFUSE"},
256 {0x193, "GPUREG_LIGHT5_AMBIENT"},
257 {0x194, "GPUREG_LIGHT5_XY"},
258 {0x195, "GPUREG_LIGHT5_Z"},
259 {0x196, "GPUREG_LIGHT5_SPOTDIR_XY"},
260 {0x197, "GPUREG_LIGHT5_SPOTDIR_Z"},
261
262 {0x199, "GPUREG_LIGHT5_CONFIG"},
263 {0x19A, "GPUREG_LIGHT5_ATTENUATION_BIAS"},
264 {0x19B, "GPUREG_LIGHT5_ATTENUATION_SCALE"},
265
266 {0x1A0, "GPUREG_LIGHT6_SPECULAR0"},
267 {0x1A1, "GPUREG_LIGHT6_SPECULAR1"},
268 {0x1A2, "GPUREG_LIGHT6_DIFFUSE"},
269 {0x1A3, "GPUREG_LIGHT6_AMBIENT"},
270 {0x1A4, "GPUREG_LIGHT6_XY"},
271 {0x1A5, "GPUREG_LIGHT6_Z"},
272 {0x1A6, "GPUREG_LIGHT6_SPOTDIR_XY"},
273 {0x1A7, "GPUREG_LIGHT6_SPOTDIR_Z"},
274
275 {0x1A9, "GPUREG_LIGHT6_CONFIG"},
276 {0x1AA, "GPUREG_LIGHT6_ATTENUATION_BIAS"},
277 {0x1AB, "GPUREG_LIGHT6_ATTENUATION_SCALE"},
278
279 {0x1B0, "GPUREG_LIGHT7_SPECULAR0"},
280 {0x1B1, "GPUREG_LIGHT7_SPECULAR1"},
281 {0x1B2, "GPUREG_LIGHT7_DIFFUSE"},
282 {0x1B3, "GPUREG_LIGHT7_AMBIENT"},
283 {0x1B4, "GPUREG_LIGHT7_XY"},
284 {0x1B5, "GPUREG_LIGHT7_Z"},
285 {0x1B6, "GPUREG_LIGHT7_SPOTDIR_XY"},
286 {0x1B7, "GPUREG_LIGHT7_SPOTDIR_Z"},
287
288 {0x1B9, "GPUREG_LIGHT7_CONFIG"},
289 {0x1BA, "GPUREG_LIGHT7_ATTENUATION_BIAS"},
290 {0x1BB, "GPUREG_LIGHT7_ATTENUATION_SCALE"},
291
292 {0x1C0, "GPUREG_LIGHTING_AMBIENT"},
293
294 {0x1C2, "GPUREG_LIGHTING_NUM_LIGHTS"},
295 {0x1C3, "GPUREG_LIGHTING_CONFIG0"},
296 {0x1C4, "GPUREG_LIGHTING_CONFIG1"},
297 {0x1C5, "GPUREG_LIGHTING_LUT_INDEX"},
298 {0x1C6, "GPUREG_LIGHTING_ENABLE1"},
299
300 {0x1C8, "GPUREG_LIGHTING_LUT_DATA0"},
301 {0x1C9, "GPUREG_LIGHTING_LUT_DATA1"},
302 {0x1CA, "GPUREG_LIGHTING_LUT_DATA2"},
303 {0x1CB, "GPUREG_LIGHTING_LUT_DATA3"},
304 {0x1CC, "GPUREG_LIGHTING_LUT_DATA4"},
305 {0x1CD, "GPUREG_LIGHTING_LUT_DATA5"},
306 {0x1CE, "GPUREG_LIGHTING_LUT_DATA6"},
307 {0x1CF, "GPUREG_LIGHTING_LUT_DATA7"},
308 {0x1D0, "GPUREG_LIGHTING_LUTINPUT_ABS"},
309 {0x1D1, "GPUREG_LIGHTING_LUTINPUT_SELECT"},
310 {0x1D2, "GPUREG_LIGHTING_LUTINPUT_SCALE"},
311
312 {0x1D9, "GPUREG_LIGHTING_LIGHT_PERMUTATION"},
313
314 {0x200, "GPUREG_ATTRIBBUFFERS_LOC"},
315 {0x201, "GPUREG_ATTRIBBUFFERS_FORMAT_LOW"},
316 {0x202, "GPUREG_ATTRIBBUFFERS_FORMAT_HIGH"},
317 {0x203, "GPUREG_ATTRIBBUFFER0_OFFSET"},
318 {0x204, "GPUREG_ATTRIBBUFFER0_CONFIG1"},
319 {0x205, "GPUREG_ATTRIBBUFFER0_CONFIG2"},
320 {0x206, "GPUREG_ATTRIBBUFFER1_OFFSET"},
321 {0x207, "GPUREG_ATTRIBBUFFER1_CONFIG1"},
322 {0x208, "GPUREG_ATTRIBBUFFER1_CONFIG2"},
323 {0x209, "GPUREG_ATTRIBBUFFER2_OFFSET"},
324 {0x20A, "GPUREG_ATTRIBBUFFER2_CONFIG1"},
325 {0x20B, "GPUREG_ATTRIBBUFFER2_CONFIG2"},
326 {0x20C, "GPUREG_ATTRIBBUFFER3_OFFSET"},
327 {0x20D, "GPUREG_ATTRIBBUFFER3_CONFIG1"},
328 {0x20E, "GPUREG_ATTRIBBUFFER3_CONFIG2"},
329 {0x20F, "GPUREG_ATTRIBBUFFER4_OFFSET"},
330 {0x210, "GPUREG_ATTRIBBUFFER4_CONFIG1"},
331 {0x211, "GPUREG_ATTRIBBUFFER4_CONFIG2"},
332 {0x212, "GPUREG_ATTRIBBUFFER5_OFFSET"},
333 {0x213, "GPUREG_ATTRIBBUFFER5_CONFIG1"},
334 {0x214, "GPUREG_ATTRIBBUFFER5_CONFIG2"},
335 {0x215, "GPUREG_ATTRIBBUFFER6_OFFSET"},
336 {0x216, "GPUREG_ATTRIBBUFFER6_CONFIG1"},
337 {0x217, "GPUREG_ATTRIBBUFFER6_CONFIG2"},
338 {0x218, "GPUREG_ATTRIBBUFFER7_OFFSET"},
339 {0x219, "GPUREG_ATTRIBBUFFER7_CONFIG1"},
340 {0x21A, "GPUREG_ATTRIBBUFFER7_CONFIG2"},
341 {0x21B, "GPUREG_ATTRIBBUFFER8_OFFSET"},
342 {0x21C, "GPUREG_ATTRIBBUFFER8_CONFIG1"},
343 {0x21D, "GPUREG_ATTRIBBUFFER8_CONFIG2"},
344 {0x21E, "GPUREG_ATTRIBBUFFER9_OFFSET"},
345 {0x21F, "GPUREG_ATTRIBBUFFER9_CONFIG1"},
346 {0x220, "GPUREG_ATTRIBBUFFER9_CONFIG2"},
347 {0x221, "GPUREG_ATTRIBBUFFER10_OFFSET"},
348 {0x222, "GPUREG_ATTRIBBUFFER10_CONFIG1"},
349 {0x223, "GPUREG_ATTRIBBUFFER10_CONFIG2"},
350 {0x224, "GPUREG_ATTRIBBUFFER11_OFFSET"},
351 {0x225, "GPUREG_ATTRIBBUFFER11_CONFIG1"},
352 {0x226, "GPUREG_ATTRIBBUFFER11_CONFIG2"},
353 {0x227, "GPUREG_INDEXBUFFER_CONFIG"},
354 {0x228, "GPUREG_NUMVERTICES"},
355 {0x229, "GPUREG_GEOSTAGE_CONFIG"},
356 {0x22A, "GPUREG_VERTEX_OFFSET"},
357
358 {0x22D, "GPUREG_POST_VERTEX_CACHE_NUM"},
359 {0x22E, "GPUREG_DRAWARRAYS"},
360 {0x22F, "GPUREG_DRAWELEMENTS"},
361
362 {0x231, "GPUREG_VTX_FUNC"},
363 {0x232, "GPUREG_FIXEDATTRIB_INDEX"},
364 {0x233, "GPUREG_FIXEDATTRIB_DATA0"},
365 {0x234, "GPUREG_FIXEDATTRIB_DATA1"},
366 {0x235, "GPUREG_FIXEDATTRIB_DATA2"},
367
368 {0x238, "GPUREG_CMDBUF_SIZE0"},
369 {0x239, "GPUREG_CMDBUF_SIZE1"},
370 {0x23A, "GPUREG_CMDBUF_ADDR0"},
371 {0x23B, "GPUREG_CMDBUF_ADDR1"},
372 {0x23C, "GPUREG_CMDBUF_JUMP0"},
373 {0x23D, "GPUREG_CMDBUF_JUMP1"},
374
375 {0x242, "GPUREG_VSH_NUM_ATTR"},
376
377 {0x244, "GPUREG_VSH_COM_MODE"},
378 {0x245, "GPUREG_START_DRAW_FUNC0"},
379
380 {0x24A, "GPUREG_VSH_OUTMAP_TOTAL1"},
381
382 {0x251, "GPUREG_VSH_OUTMAP_TOTAL2"},
383 {0x252, "GPUREG_GSH_MISC0"},
384 {0x253, "GPUREG_GEOSTAGE_CONFIG2"},
385 {0x254, "GPUREG_GSH_MISC1"},
386
387 {0x25E, "GPUREG_PRIMITIVE_CONFIG"},
388 {0x25F, "GPUREG_RESTART_PRIMITIVE"},
389
390 {0x280, "GPUREG_GSH_BOOLUNIFORM"},
391 {0x281, "GPUREG_GSH_INTUNIFORM_I0"},
392 {0x282, "GPUREG_GSH_INTUNIFORM_I1"},
393 {0x283, "GPUREG_GSH_INTUNIFORM_I2"},
394 {0x284, "GPUREG_GSH_INTUNIFORM_I3"},
395
396 {0x289, "GPUREG_GSH_INPUTBUFFER_CONFIG"},
397 {0x28A, "GPUREG_GSH_ENTRYPOINT"},
398 {0x28B, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_LOW"},
399 {0x28C, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_HIGH"},
400 {0x28D, "GPUREG_GSH_OUTMAP_MASK"},
401
402 {0x28F, "GPUREG_GSH_CODETRANSFER_END"},
403 {0x290, "GPUREG_GSH_FLOATUNIFORM_INDEX"},
404 {0x291, "GPUREG_GSH_FLOATUNIFORM_DATA0"},
405 {0x292, "GPUREG_GSH_FLOATUNIFORM_DATA1"},
406 {0x293, "GPUREG_GSH_FLOATUNIFORM_DATA2"},
407 {0x294, "GPUREG_GSH_FLOATUNIFORM_DATA3"},
408 {0x295, "GPUREG_GSH_FLOATUNIFORM_DATA4"},
409 {0x296, "GPUREG_GSH_FLOATUNIFORM_DATA5"},
410 {0x297, "GPUREG_GSH_FLOATUNIFORM_DATA6"},
411 {0x298, "GPUREG_GSH_FLOATUNIFORM_DATA7"},
412
413 {0x29B, "GPUREG_GSH_CODETRANSFER_INDEX"},
414 {0x29C, "GPUREG_GSH_CODETRANSFER_DATA0"},
415 {0x29D, "GPUREG_GSH_CODETRANSFER_DATA1"},
416 {0x29E, "GPUREG_GSH_CODETRANSFER_DATA2"},
417 {0x29F, "GPUREG_GSH_CODETRANSFER_DATA3"},
418 {0x2A0, "GPUREG_GSH_CODETRANSFER_DATA4"},
419 {0x2A1, "GPUREG_GSH_CODETRANSFER_DATA5"},
420 {0x2A2, "GPUREG_GSH_CODETRANSFER_DATA6"},
421 {0x2A3, "GPUREG_GSH_CODETRANSFER_DATA7"},
422
423 {0x2A5, "GPUREG_GSH_OPDESCS_INDEX"},
424 {0x2A6, "GPUREG_GSH_OPDESCS_DATA0"},
425 {0x2A7, "GPUREG_GSH_OPDESCS_DATA1"},
426 {0x2A8, "GPUREG_GSH_OPDESCS_DATA2"},
427 {0x2A9, "GPUREG_GSH_OPDESCS_DATA3"},
428 {0x2AA, "GPUREG_GSH_OPDESCS_DATA4"},
429 {0x2AB, "GPUREG_GSH_OPDESCS_DATA5"},
430 {0x2AC, "GPUREG_GSH_OPDESCS_DATA6"},
431 {0x2AD, "GPUREG_GSH_OPDESCS_DATA7"},
432
433 {0x2B0, "GPUREG_VSH_BOOLUNIFORM"},
434 {0x2B1, "GPUREG_VSH_INTUNIFORM_I0"},
435 {0x2B2, "GPUREG_VSH_INTUNIFORM_I1"},
436 {0x2B3, "GPUREG_VSH_INTUNIFORM_I2"},
437 {0x2B4, "GPUREG_VSH_INTUNIFORM_I3"},
438
439 {0x2B9, "GPUREG_VSH_INPUTBUFFER_CONFIG"},
440 {0x2BA, "GPUREG_VSH_ENTRYPOINT"},
441 {0x2BB, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW"},
442 {0x2BC, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_HIGH"},
443 {0x2BD, "GPUREG_VSH_OUTMAP_MASK"},
444
445 {0x2BF, "GPUREG_VSH_CODETRANSFER_END"},
446 {0x2C0, "GPUREG_VSH_FLOATUNIFORM_INDEX"},
447 {0x2C1, "GPUREG_VSH_FLOATUNIFORM_DATA0"},
448 {0x2C2, "GPUREG_VSH_FLOATUNIFORM_DATA1"},
449 {0x2C3, "GPUREG_VSH_FLOATUNIFORM_DATA2"},
450 {0x2C4, "GPUREG_VSH_FLOATUNIFORM_DATA3"},
451 {0x2C5, "GPUREG_VSH_FLOATUNIFORM_DATA4"},
452 {0x2C6, "GPUREG_VSH_FLOATUNIFORM_DATA5"},
453 {0x2C7, "GPUREG_VSH_FLOATUNIFORM_DATA6"},
454 {0x2C8, "GPUREG_VSH_FLOATUNIFORM_DATA7"},
455
456 {0x2CB, "GPUREG_VSH_CODETRANSFER_INDEX"},
457 {0x2CC, "GPUREG_VSH_CODETRANSFER_DATA0"},
458 {0x2CD, "GPUREG_VSH_CODETRANSFER_DATA1"},
459 {0x2CE, "GPUREG_VSH_CODETRANSFER_DATA2"},
460 {0x2CF, "GPUREG_VSH_CODETRANSFER_DATA3"},
461 {0x2D0, "GPUREG_VSH_CODETRANSFER_DATA4"},
462 {0x2D1, "GPUREG_VSH_CODETRANSFER_DATA5"},
463 {0x2D2, "GPUREG_VSH_CODETRANSFER_DATA6"},
464 {0x2D3, "GPUREG_VSH_CODETRANSFER_DATA7"},
465
466 {0x2D5, "GPUREG_VSH_OPDESCS_INDEX"},
467 {0x2D6, "GPUREG_VSH_OPDESCS_DATA0"},
468 {0x2D7, "GPUREG_VSH_OPDESCS_DATA1"},
469 {0x2D8, "GPUREG_VSH_OPDESCS_DATA2"},
470 {0x2D9, "GPUREG_VSH_OPDESCS_DATA3"},
471 {0x2DA, "GPUREG_VSH_OPDESCS_DATA4"},
472 {0x2DB, "GPUREG_VSH_OPDESCS_DATA5"},
473 {0x2DC, "GPUREG_VSH_OPDESCS_DATA6"},
474 {0x2DD, "GPUREG_VSH_OPDESCS_DATA7"},
475};
476
477std::string Regs::GetCommandName(int index) {
478 static std::unordered_map<u32, const char*> map;
479
480 if (map.empty()) {
481 map.insert(std::begin(register_names), std::end(register_names));
482 }
483
484 // Return empty string if no match is found
485 auto it = map.find(index);
486 if (it != map.end()) {
487 return it->second;
488 } else {
489 return std::string();
490 }
491}
492
493} // namespace Pica
diff --git a/src/video_core/regs.h b/src/video_core/regs.h
new file mode 100644
index 000000000..f25edde27
--- /dev/null
+++ b/src/video_core/regs.h
@@ -0,0 +1,164 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <cstddef>
9#include <string>
10#ifndef _MSC_VER
11#include <type_traits> // for std::enable_if
12#endif
13
14#include "common/common_funcs.h"
15#include "common/common_types.h"
16#include "video_core/regs_framebuffer.h"
17#include "video_core/regs_lighting.h"
18#include "video_core/regs_pipeline.h"
19#include "video_core/regs_rasterizer.h"
20#include "video_core/regs_shader.h"
21#include "video_core/regs_texturing.h"
22
23namespace Pica {
24
25// Returns index corresponding to the Regs member labeled by field_name
26// TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions
27// when used with array elements (e.g. PICA_REG_INDEX(vs_uniform_setup.set_value[1])).
28// For details cf.
29// https://connect.microsoft.com/VisualStudio/feedback/details/209229/offsetof-does-not-produce-a-constant-expression-for-array-members
30// Hopefully, this will be fixed sometime in the future.
31// For lack of better alternatives, we currently hardcode the offsets when constant
32// expressions are needed via PICA_REG_INDEX_WORKAROUND (on sane compilers, static_asserts
33// will then make sure the offsets indeed match the automatically calculated ones).
34#define PICA_REG_INDEX(field_name) (offsetof(Pica::Regs, field_name) / sizeof(u32))
35#if defined(_MSC_VER)
36#define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) (backup_workaround_index)
37#else
38// NOTE: Yeah, hacking in a static_assert here just to workaround the lacking MSVC compiler
39// really is this annoying. This macro just forwards its first argument to PICA_REG_INDEX
40// and then performs a (no-op) cast to size_t iff the second argument matches the expected
41// field offset. Otherwise, the compiler will fail to compile this code.
42#define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) \
43 ((typename std::enable_if<backup_workaround_index == PICA_REG_INDEX(field_name), \
44 size_t>::type)PICA_REG_INDEX(field_name))
45#endif // _MSC_VER
46
47struct Regs {
48 INSERT_PADDING_WORDS(0x10);
49 u32 trigger_irq;
50 INSERT_PADDING_WORDS(0x2f);
51 RasterizerRegs rasterizer;
52 TexturingRegs texturing;
53 FramebufferRegs framebuffer;
54 LightingRegs lighting;
55 PipelineRegs pipeline;
56 ShaderRegs gs;
57 ShaderRegs vs;
58 INSERT_PADDING_WORDS(0x20);
59
60 // Map register indices to names readable by humans
61 // Used for debugging purposes, so performance is not an issue here
62 static std::string GetCommandName(int index);
63
64 static constexpr size_t NumIds() {
65 return sizeof(Regs) / sizeof(u32);
66 }
67
68 const u32& operator[](int index) const {
69 const u32* content = reinterpret_cast<const u32*>(this);
70 return content[index];
71 }
72
73 u32& operator[](int index) {
74 u32* content = reinterpret_cast<u32*>(this);
75 return content[index];
76 }
77
78private:
79 /*
80 * Most physical addresses which Pica registers refer to are 8-byte aligned.
81 * This function should be used to get the address from a raw register value.
82 */
83 static inline u32 DecodeAddressRegister(u32 register_value) {
84 return register_value * 8;
85 }
86};
87
88// TODO: MSVC does not support using offsetof() on non-static data members even though this
89// is technically allowed since C++11. This macro should be enabled once MSVC adds
90// support for that.
91#ifndef _MSC_VER
92#define ASSERT_REG_POSITION(field_name, position) \
93 static_assert(offsetof(Regs, field_name) == position * 4, \
94 "Field " #field_name " has invalid position")
95
96ASSERT_REG_POSITION(trigger_irq, 0x10);
97
98ASSERT_REG_POSITION(rasterizer, 0x40);
99ASSERT_REG_POSITION(rasterizer.cull_mode, 0x40);
100ASSERT_REG_POSITION(rasterizer.viewport_size_x, 0x41);
101ASSERT_REG_POSITION(rasterizer.viewport_size_y, 0x43);
102ASSERT_REG_POSITION(rasterizer.viewport_depth_range, 0x4d);
103ASSERT_REG_POSITION(rasterizer.viewport_depth_near_plane, 0x4e);
104ASSERT_REG_POSITION(rasterizer.vs_output_attributes[0], 0x50);
105ASSERT_REG_POSITION(rasterizer.vs_output_attributes[1], 0x51);
106ASSERT_REG_POSITION(rasterizer.scissor_test, 0x65);
107ASSERT_REG_POSITION(rasterizer.viewport_corner, 0x68);
108ASSERT_REG_POSITION(rasterizer.depthmap_enable, 0x6D);
109
110ASSERT_REG_POSITION(texturing, 0x80);
111ASSERT_REG_POSITION(texturing.texture0_enable, 0x80);
112ASSERT_REG_POSITION(texturing.texture0, 0x81);
113ASSERT_REG_POSITION(texturing.texture0_format, 0x8e);
114ASSERT_REG_POSITION(texturing.fragment_lighting_enable, 0x8f);
115ASSERT_REG_POSITION(texturing.texture1, 0x91);
116ASSERT_REG_POSITION(texturing.texture1_format, 0x96);
117ASSERT_REG_POSITION(texturing.texture2, 0x99);
118ASSERT_REG_POSITION(texturing.texture2_format, 0x9e);
119ASSERT_REG_POSITION(texturing.tev_stage0, 0xc0);
120ASSERT_REG_POSITION(texturing.tev_stage1, 0xc8);
121ASSERT_REG_POSITION(texturing.tev_stage2, 0xd0);
122ASSERT_REG_POSITION(texturing.tev_stage3, 0xd8);
123ASSERT_REG_POSITION(texturing.tev_combiner_buffer_input, 0xe0);
124ASSERT_REG_POSITION(texturing.fog_mode, 0xe0);
125ASSERT_REG_POSITION(texturing.fog_color, 0xe1);
126ASSERT_REG_POSITION(texturing.fog_lut_offset, 0xe6);
127ASSERT_REG_POSITION(texturing.fog_lut_data, 0xe8);
128ASSERT_REG_POSITION(texturing.tev_stage4, 0xf0);
129ASSERT_REG_POSITION(texturing.tev_stage5, 0xf8);
130ASSERT_REG_POSITION(texturing.tev_combiner_buffer_color, 0xfd);
131
132ASSERT_REG_POSITION(framebuffer, 0x100);
133ASSERT_REG_POSITION(framebuffer.output_merger, 0x100);
134ASSERT_REG_POSITION(framebuffer.framebuffer, 0x110);
135
136ASSERT_REG_POSITION(lighting, 0x140);
137
138ASSERT_REG_POSITION(pipeline, 0x200);
139ASSERT_REG_POSITION(pipeline.vertex_attributes, 0x200);
140ASSERT_REG_POSITION(pipeline.index_array, 0x227);
141ASSERT_REG_POSITION(pipeline.num_vertices, 0x228);
142ASSERT_REG_POSITION(pipeline.vertex_offset, 0x22a);
143ASSERT_REG_POSITION(pipeline.trigger_draw, 0x22e);
144ASSERT_REG_POSITION(pipeline.trigger_draw_indexed, 0x22f);
145ASSERT_REG_POSITION(pipeline.vs_default_attributes_setup, 0x232);
146ASSERT_REG_POSITION(pipeline.command_buffer, 0x238);
147ASSERT_REG_POSITION(pipeline.gpu_mode, 0x245);
148ASSERT_REG_POSITION(pipeline.triangle_topology, 0x25e);
149ASSERT_REG_POSITION(pipeline.restart_primitive, 0x25f);
150
151ASSERT_REG_POSITION(gs, 0x280);
152ASSERT_REG_POSITION(vs, 0x2b0);
153
154#undef ASSERT_REG_POSITION
155#endif // !defined(_MSC_VER)
156
157// The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value
158// anyway.
159static_assert(sizeof(Regs) <= 0x300 * sizeof(u32),
160 "Register set structure larger than it should be");
161static_assert(sizeof(Regs) >= 0x300 * sizeof(u32),
162 "Register set structure smaller than it should be");
163
164} // namespace Pica
diff --git a/src/video_core/regs_framebuffer.h b/src/video_core/regs_framebuffer.h
new file mode 100644
index 000000000..366782080
--- /dev/null
+++ b/src/video_core/regs_framebuffer.h
@@ -0,0 +1,284 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8
9#include "common/assert.h"
10#include "common/bit_field.h"
11#include "common/common_funcs.h"
12#include "common/common_types.h"
13#include "common/logging/log.h"
14
15namespace Pica {
16
17struct FramebufferRegs {
18 enum class LogicOp : u32 {
19 Clear = 0,
20 And = 1,
21 AndReverse = 2,
22 Copy = 3,
23 Set = 4,
24 CopyInverted = 5,
25 NoOp = 6,
26 Invert = 7,
27 Nand = 8,
28 Or = 9,
29 Nor = 10,
30 Xor = 11,
31 Equiv = 12,
32 AndInverted = 13,
33 OrReverse = 14,
34 OrInverted = 15,
35 };
36
37 enum class BlendEquation : u32 {
38 Add = 0,
39 Subtract = 1,
40 ReverseSubtract = 2,
41 Min = 3,
42 Max = 4,
43 };
44
45 enum class BlendFactor : u32 {
46 Zero = 0,
47 One = 1,
48 SourceColor = 2,
49 OneMinusSourceColor = 3,
50 DestColor = 4,
51 OneMinusDestColor = 5,
52 SourceAlpha = 6,
53 OneMinusSourceAlpha = 7,
54 DestAlpha = 8,
55 OneMinusDestAlpha = 9,
56 ConstantColor = 10,
57 OneMinusConstantColor = 11,
58 ConstantAlpha = 12,
59 OneMinusConstantAlpha = 13,
60 SourceAlphaSaturate = 14,
61 };
62
63 enum class CompareFunc : u32 {
64 Never = 0,
65 Always = 1,
66 Equal = 2,
67 NotEqual = 3,
68 LessThan = 4,
69 LessThanOrEqual = 5,
70 GreaterThan = 6,
71 GreaterThanOrEqual = 7,
72 };
73
74 enum class StencilAction : u32 {
75 Keep = 0,
76 Zero = 1,
77 Replace = 2,
78 Increment = 3,
79 Decrement = 4,
80 Invert = 5,
81 IncrementWrap = 6,
82 DecrementWrap = 7,
83 };
84
85 struct {
86 union {
87 // If false, logic blending is used
88 BitField<8, 1, u32> alphablend_enable;
89 };
90
91 union {
92 BitField<0, 8, BlendEquation> blend_equation_rgb;
93 BitField<8, 8, BlendEquation> blend_equation_a;
94
95 BitField<16, 4, BlendFactor> factor_source_rgb;
96 BitField<20, 4, BlendFactor> factor_dest_rgb;
97
98 BitField<24, 4, BlendFactor> factor_source_a;
99 BitField<28, 4, BlendFactor> factor_dest_a;
100 } alpha_blending;
101
102 union {
103 BitField<0, 4, LogicOp> logic_op;
104 };
105
106 union {
107 u32 raw;
108 BitField<0, 8, u32> r;
109 BitField<8, 8, u32> g;
110 BitField<16, 8, u32> b;
111 BitField<24, 8, u32> a;
112 } blend_const;
113
114 union {
115 BitField<0, 1, u32> enable;
116 BitField<4, 3, CompareFunc> func;
117 BitField<8, 8, u32> ref;
118 } alpha_test;
119
120 struct {
121 union {
122 // Raw value of this register
123 u32 raw_func;
124
125 // If true, enable stencil testing
126 BitField<0, 1, u32> enable;
127
128 // Comparison operation for stencil testing
129 BitField<4, 3, CompareFunc> func;
130
131 // Mask used to control writing to the stencil buffer
132 BitField<8, 8, u32> write_mask;
133
134 // Value to compare against for stencil testing
135 BitField<16, 8, u32> reference_value;
136
137 // Mask to apply on stencil test inputs
138 BitField<24, 8, u32> input_mask;
139 };
140
141 union {
142 // Raw value of this register
143 u32 raw_op;
144
145 // Action to perform when the stencil test fails
146 BitField<0, 3, StencilAction> action_stencil_fail;
147
148 // Action to perform when stencil testing passed but depth testing fails
149 BitField<4, 3, StencilAction> action_depth_fail;
150
151 // Action to perform when both stencil and depth testing pass
152 BitField<8, 3, StencilAction> action_depth_pass;
153 };
154 } stencil_test;
155
156 union {
157 BitField<0, 1, u32> depth_test_enable;
158 BitField<4, 3, CompareFunc> depth_test_func;
159 BitField<8, 1, u32> red_enable;
160 BitField<9, 1, u32> green_enable;
161 BitField<10, 1, u32> blue_enable;
162 BitField<11, 1, u32> alpha_enable;
163 BitField<12, 1, u32> depth_write_enable;
164 };
165
166 INSERT_PADDING_WORDS(0x8);
167 } output_merger;
168
169 // Components are laid out in reverse byte order, most significant bits first.
170 enum class ColorFormat : u32 {
171 RGBA8 = 0,
172 RGB8 = 1,
173 RGB5A1 = 2,
174 RGB565 = 3,
175 RGBA4 = 4,
176 };
177
178 enum class DepthFormat : u32 {
179 D16 = 0,
180 D24 = 2,
181 D24S8 = 3,
182 };
183
184 // Returns the number of bytes in the specified color format
185 static unsigned BytesPerColorPixel(ColorFormat format) {
186 switch (format) {
187 case ColorFormat::RGBA8:
188 return 4;
189 case ColorFormat::RGB8:
190 return 3;
191 case ColorFormat::RGB5A1:
192 case ColorFormat::RGB565:
193 case ColorFormat::RGBA4:
194 return 2;
195 default:
196 LOG_CRITICAL(HW_GPU, "Unknown color format %u", format);
197 UNIMPLEMENTED();
198 }
199 }
200
201 struct FramebufferConfig {
202 INSERT_PADDING_WORDS(0x3);
203
204 union {
205 BitField<0, 4, u32> allow_color_write; // 0 = disable, else enable
206 };
207
208 INSERT_PADDING_WORDS(0x1);
209
210 union {
211 BitField<0, 2, u32> allow_depth_stencil_write; // 0 = disable, else enable
212 };
213
214 DepthFormat depth_format; // TODO: Should be a BitField!
215 BitField<16, 3, ColorFormat> color_format;
216
217 INSERT_PADDING_WORDS(0x4);
218
219 u32 depth_buffer_address;
220 u32 color_buffer_address;
221
222 union {
223 // Apparently, the framebuffer width is stored as expected,
224 // while the height is stored as the actual height minus one.
225 // Hence, don't access these fields directly but use the accessors
226 // GetWidth() and GetHeight() instead.
227 BitField<0, 11, u32> width;
228 BitField<12, 10, u32> height;
229 };
230
231 INSERT_PADDING_WORDS(0x1);
232
233 inline PAddr GetColorBufferPhysicalAddress() const {
234 return color_buffer_address * 8;
235 }
236 inline PAddr GetDepthBufferPhysicalAddress() const {
237 return depth_buffer_address * 8;
238 }
239
240 inline u32 GetWidth() const {
241 return width;
242 }
243
244 inline u32 GetHeight() const {
245 return height + 1;
246 }
247 } framebuffer;
248
249 // Returns the number of bytes in the specified depth format
250 static u32 BytesPerDepthPixel(DepthFormat format) {
251 switch (format) {
252 case DepthFormat::D16:
253 return 2;
254 case DepthFormat::D24:
255 return 3;
256 case DepthFormat::D24S8:
257 return 4;
258 default:
259 LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
260 UNIMPLEMENTED();
261 }
262 }
263
264 // Returns the number of bits per depth component of the specified depth format
265 static u32 DepthBitsPerPixel(DepthFormat format) {
266 switch (format) {
267 case DepthFormat::D16:
268 return 16;
269 case DepthFormat::D24:
270 case DepthFormat::D24S8:
271 return 24;
272 default:
273 LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
274 UNIMPLEMENTED();
275 }
276 }
277
278 INSERT_PADDING_WORDS(0x20);
279};
280
281static_assert(sizeof(FramebufferRegs) == 0x40 * sizeof(u32),
282 "FramebufferRegs struct has incorrect size");
283
284} // namespace Pica
diff --git a/src/video_core/regs_lighting.h b/src/video_core/regs_lighting.h
new file mode 100644
index 000000000..548a6c4d5
--- /dev/null
+++ b/src/video_core/regs_lighting.h
@@ -0,0 +1,294 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8
9#include "common/assert.h"
10#include "common/bit_field.h"
11#include "common/common_funcs.h"
12#include "common/common_types.h"
13#include "common/vector_math.h"
14
15namespace Pica {
16
17struct LightingRegs {
18 enum class LightingSampler {
19 Distribution0 = 0,
20 Distribution1 = 1,
21 Fresnel = 3,
22 ReflectBlue = 4,
23 ReflectGreen = 5,
24 ReflectRed = 6,
25 SpotlightAttenuation = 8,
26 DistanceAttenuation = 16,
27 };
28
29 /**
30 * Pica fragment lighting supports using different LUTs for each lighting component: Reflectance
31 * R, G, and B channels, distribution function for specular components 0 and 1, fresnel factor,
32 * and spotlight attenuation. Furthermore, which LUTs are used for each channel (or whether a
33 * channel is enabled at all) is specified by various pre-defined lighting configurations. With
34 * configurations that require more LUTs, more cycles are required on HW to perform lighting
35 * computations.
36 */
37 enum class LightingConfig {
38 Config0 = 0, ///< Reflect Red, Distribution 0, Spotlight
39 Config1 = 1, ///< Reflect Red, Fresnel, Spotlight
40 Config2 = 2, ///< Reflect Red, Distribution 0/1
41 Config3 = 3, ///< Distribution 0/1, Fresnel
42 Config4 = 4, ///< Reflect Red/Green/Blue, Distribution 0/1, Spotlight
43 Config5 = 5, ///< Reflect Red/Green/Blue, Distribution 0, Fresnel, Spotlight
44 Config6 = 6, ///< Reflect Red, Distribution 0/1, Fresnel, Spotlight
45
46 Config7 = 8, ///< Reflect Red/Green/Blue, Distribution 0/1, Fresnel, Spotlight
47 ///< NOTE: '8' is intentional, '7' does not appear to be a valid configuration
48 };
49
50 /// Selects which lighting components are affected by fresnel
51 enum class LightingFresnelSelector {
52 None = 0, ///< Fresnel is disabled
53 PrimaryAlpha = 1, ///< Primary (diffuse) lighting alpha is affected by fresnel
54 SecondaryAlpha = 2, ///< Secondary (specular) lighting alpha is affected by fresnel
55 Both =
56 PrimaryAlpha |
57 SecondaryAlpha, ///< Both primary and secondary lighting alphas are affected by fresnel
58 };
59
60 /// Factor used to scale the output of a lighting LUT
61 enum class LightingScale {
62 Scale1 = 0, ///< Scale is 1x
63 Scale2 = 1, ///< Scale is 2x
64 Scale4 = 2, ///< Scale is 4x
65 Scale8 = 3, ///< Scale is 8x
66
67 Scale1_4 = 6, ///< Scale is 0.25x
68 Scale1_2 = 7, ///< Scale is 0.5x
69 };
70
71 enum class LightingLutInput {
72 NH = 0, // Cosine of the angle between the normal and half-angle vectors
73 VH = 1, // Cosine of the angle between the view and half-angle vectors
74 NV = 2, // Cosine of the angle between the normal and the view vector
75 LN = 3, // Cosine of the angle between the light and the normal vectors
76 };
77
78 enum class LightingBumpMode : u32 {
79 None = 0,
80 NormalMap = 1,
81 TangentMap = 2,
82 };
83
84 union LightColor {
85 BitField<0, 10, u32> b;
86 BitField<10, 10, u32> g;
87 BitField<20, 10, u32> r;
88
89 Math::Vec3f ToVec3f() const {
90 // These fields are 10 bits wide, however 255 corresponds to 1.0f for each color
91 // component
92 return Math::MakeVec((f32)r / 255.f, (f32)g / 255.f, (f32)b / 255.f);
93 }
94 };
95
96 /// Returns true if the specified lighting sampler is supported by the current Pica lighting
97 /// configuration
98 static bool IsLightingSamplerSupported(LightingConfig config, LightingSampler sampler) {
99 switch (sampler) {
100 case LightingSampler::Distribution0:
101 return (config != LightingConfig::Config1);
102
103 case LightingSampler::Distribution1:
104 return (config != LightingConfig::Config0) && (config != LightingConfig::Config1) &&
105 (config != LightingConfig::Config5);
106
107 case LightingSampler::Fresnel:
108 return (config != LightingConfig::Config0) && (config != LightingConfig::Config2) &&
109 (config != LightingConfig::Config4);
110
111 case LightingSampler::ReflectRed:
112 return (config != LightingConfig::Config3);
113
114 case LightingSampler::ReflectGreen:
115 case LightingSampler::ReflectBlue:
116 return (config == LightingConfig::Config4) || (config == LightingConfig::Config5) ||
117 (config == LightingConfig::Config7);
118 default:
119 UNREACHABLE_MSG("Regs::IsLightingSamplerSupported: Reached "
120 "unreachable section, sampler should be one "
121 "of Distribution0, Distribution1, Fresnel, "
122 "ReflectRed, ReflectGreen or ReflectBlue, instead "
123 "got %i",
124 static_cast<int>(config));
125 }
126 }
127
128 struct LightSrc {
129 LightColor specular_0; // material.specular_0 * light.specular_0
130 LightColor specular_1; // material.specular_1 * light.specular_1
131 LightColor diffuse; // material.diffuse * light.diffuse
132 LightColor ambient; // material.ambient * light.ambient
133
134 // Encoded as 16-bit floating point
135 union {
136 BitField<0, 16, u32> x;
137 BitField<16, 16, u32> y;
138 };
139 union {
140 BitField<0, 16, u32> z;
141 };
142
143 INSERT_PADDING_WORDS(0x3);
144
145 union {
146 BitField<0, 1, u32> directional;
147 BitField<1, 1, u32> two_sided_diffuse; // When disabled, clamp dot-product to 0
148 } config;
149
150 BitField<0, 20, u32> dist_atten_bias;
151 BitField<0, 20, u32> dist_atten_scale;
152
153 INSERT_PADDING_WORDS(0x4);
154 };
155 static_assert(sizeof(LightSrc) == 0x10 * sizeof(u32), "LightSrc structure must be 0x10 words");
156
157 LightSrc light[8];
158 LightColor global_ambient; // Emission + (material.ambient * lighting.ambient)
159 INSERT_PADDING_WORDS(0x1);
160 BitField<0, 3, u32> max_light_index; // Number of enabled lights - 1
161
162 union {
163 BitField<2, 2, LightingFresnelSelector> fresnel_selector;
164 BitField<4, 4, LightingConfig> config;
165 BitField<22, 2, u32> bump_selector; // 0: Texture 0, 1: Texture 1, 2: Texture 2
166 BitField<27, 1, u32> clamp_highlights;
167 BitField<28, 2, LightingBumpMode> bump_mode;
168 BitField<30, 1, u32> disable_bump_renorm;
169 } config0;
170
171 union {
172 BitField<16, 1, u32> disable_lut_d0;
173 BitField<17, 1, u32> disable_lut_d1;
174 BitField<19, 1, u32> disable_lut_fr;
175 BitField<20, 1, u32> disable_lut_rr;
176 BitField<21, 1, u32> disable_lut_rg;
177 BitField<22, 1, u32> disable_lut_rb;
178
179 // Each bit specifies whether distance attenuation should be applied for the corresponding
180 // light.
181 BitField<24, 1, u32> disable_dist_atten_light_0;
182 BitField<25, 1, u32> disable_dist_atten_light_1;
183 BitField<26, 1, u32> disable_dist_atten_light_2;
184 BitField<27, 1, u32> disable_dist_atten_light_3;
185 BitField<28, 1, u32> disable_dist_atten_light_4;
186 BitField<29, 1, u32> disable_dist_atten_light_5;
187 BitField<30, 1, u32> disable_dist_atten_light_6;
188 BitField<31, 1, u32> disable_dist_atten_light_7;
189 } config1;
190
191 bool IsDistAttenDisabled(unsigned index) const {
192 const unsigned disable[] = {
193 config1.disable_dist_atten_light_0, config1.disable_dist_atten_light_1,
194 config1.disable_dist_atten_light_2, config1.disable_dist_atten_light_3,
195 config1.disable_dist_atten_light_4, config1.disable_dist_atten_light_5,
196 config1.disable_dist_atten_light_6, config1.disable_dist_atten_light_7};
197 return disable[index] != 0;
198 }
199
200 union {
201 BitField<0, 8, u32> index; ///< Index at which to set data in the LUT
202 BitField<8, 5, u32> type; ///< Type of LUT for which to set data
203 } lut_config;
204
205 BitField<0, 1, u32> disable;
206 INSERT_PADDING_WORDS(0x1);
207
208 // When data is written to any of these registers, it gets written to the lookup table of the
209 // selected type at the selected index, specified above in the `lut_config` register. With each
210 // write, `lut_config.index` is incremented. It does not matter which of these registers is
211 // written to, the behavior will be the same.
212 u32 lut_data[8];
213
214 // These are used to specify if absolute (abs) value should be used for each LUT index. When
215 // abs mode is disabled, LUT indexes are in the range of (-1.0, 1.0). Otherwise, they are in
216 // the range of (0.0, 1.0).
217 union {
218 BitField<1, 1, u32> disable_d0;
219 BitField<5, 1, u32> disable_d1;
220 BitField<9, 1, u32> disable_sp;
221 BitField<13, 1, u32> disable_fr;
222 BitField<17, 1, u32> disable_rb;
223 BitField<21, 1, u32> disable_rg;
224 BitField<25, 1, u32> disable_rr;
225 } abs_lut_input;
226
227 union {
228 BitField<0, 3, LightingLutInput> d0;
229 BitField<4, 3, LightingLutInput> d1;
230 BitField<8, 3, LightingLutInput> sp;
231 BitField<12, 3, LightingLutInput> fr;
232 BitField<16, 3, LightingLutInput> rb;
233 BitField<20, 3, LightingLutInput> rg;
234 BitField<24, 3, LightingLutInput> rr;
235 } lut_input;
236
237 union {
238 BitField<0, 3, LightingScale> d0;
239 BitField<4, 3, LightingScale> d1;
240 BitField<8, 3, LightingScale> sp;
241 BitField<12, 3, LightingScale> fr;
242 BitField<16, 3, LightingScale> rb;
243 BitField<20, 3, LightingScale> rg;
244 BitField<24, 3, LightingScale> rr;
245
246 static float GetScale(LightingScale scale) {
247 switch (scale) {
248 case LightingScale::Scale1:
249 return 1.0f;
250 case LightingScale::Scale2:
251 return 2.0f;
252 case LightingScale::Scale4:
253 return 4.0f;
254 case LightingScale::Scale8:
255 return 8.0f;
256 case LightingScale::Scale1_4:
257 return 0.25f;
258 case LightingScale::Scale1_2:
259 return 0.5f;
260 }
261 return 0.0f;
262 }
263 } lut_scale;
264
265 INSERT_PADDING_WORDS(0x6);
266
267 union {
268 // There are 8 light enable "slots", corresponding to the total number of lights supported
269 // by Pica. For N enabled lights (specified by register 0x1c2, or 'src_num' above), the
270 // first N slots below will be set to integers within the range of 0-7, corresponding to the
271 // actual light that is enabled for each slot.
272
273 BitField<0, 3, u32> slot_0;
274 BitField<4, 3, u32> slot_1;
275 BitField<8, 3, u32> slot_2;
276 BitField<12, 3, u32> slot_3;
277 BitField<16, 3, u32> slot_4;
278 BitField<20, 3, u32> slot_5;
279 BitField<24, 3, u32> slot_6;
280 BitField<28, 3, u32> slot_7;
281
282 unsigned GetNum(unsigned index) const {
283 const unsigned enable_slots[] = {slot_0, slot_1, slot_2, slot_3,
284 slot_4, slot_5, slot_6, slot_7};
285 return enable_slots[index];
286 }
287 } light_enable;
288
289 INSERT_PADDING_WORDS(0x26);
290};
291
292static_assert(sizeof(LightingRegs) == 0xC0 * sizeof(u32), "LightingRegs struct has incorrect size");
293
294} // namespace Pica
diff --git a/src/video_core/regs_pipeline.h b/src/video_core/regs_pipeline.h
new file mode 100644
index 000000000..5844a66ee
--- /dev/null
+++ b/src/video_core/regs_pipeline.h
@@ -0,0 +1,224 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8
9#include "common/assert.h"
10#include "common/bit_field.h"
11#include "common/common_funcs.h"
12#include "common/common_types.h"
13
14namespace Pica {
15
16struct PipelineRegs {
17 enum class VertexAttributeFormat : u64 {
18 BYTE = 0,
19 UBYTE = 1,
20 SHORT = 2,
21 FLOAT = 3,
22 };
23
24 struct {
25 BitField<0, 29, u32> base_address;
26
27 PAddr GetPhysicalBaseAddress() const {
28 return base_address * 8;
29 }
30
31 // Descriptor for internal vertex attributes
32 union {
33 BitField<0, 2, VertexAttributeFormat> format0; // size of one element
34 BitField<2, 2, u64> size0; // number of elements minus 1
35 BitField<4, 2, VertexAttributeFormat> format1;
36 BitField<6, 2, u64> size1;
37 BitField<8, 2, VertexAttributeFormat> format2;
38 BitField<10, 2, u64> size2;
39 BitField<12, 2, VertexAttributeFormat> format3;
40 BitField<14, 2, u64> size3;
41 BitField<16, 2, VertexAttributeFormat> format4;
42 BitField<18, 2, u64> size4;
43 BitField<20, 2, VertexAttributeFormat> format5;
44 BitField<22, 2, u64> size5;
45 BitField<24, 2, VertexAttributeFormat> format6;
46 BitField<26, 2, u64> size6;
47 BitField<28, 2, VertexAttributeFormat> format7;
48 BitField<30, 2, u64> size7;
49 BitField<32, 2, VertexAttributeFormat> format8;
50 BitField<34, 2, u64> size8;
51 BitField<36, 2, VertexAttributeFormat> format9;
52 BitField<38, 2, u64> size9;
53 BitField<40, 2, VertexAttributeFormat> format10;
54 BitField<42, 2, u64> size10;
55 BitField<44, 2, VertexAttributeFormat> format11;
56 BitField<46, 2, u64> size11;
57
58 BitField<48, 12, u64> attribute_mask;
59
60 // number of total attributes minus 1
61 BitField<60, 4, u64> max_attribute_index;
62 };
63
64 inline VertexAttributeFormat GetFormat(int n) const {
65 VertexAttributeFormat formats[] = {format0, format1, format2, format3,
66 format4, format5, format6, format7,
67 format8, format9, format10, format11};
68 return formats[n];
69 }
70
71 inline int GetNumElements(int n) const {
72 u64 sizes[] = {size0, size1, size2, size3, size4, size5,
73 size6, size7, size8, size9, size10, size11};
74 return (int)sizes[n] + 1;
75 }
76
77 inline int GetElementSizeInBytes(int n) const {
78 return (GetFormat(n) == VertexAttributeFormat::FLOAT)
79 ? 4
80 : (GetFormat(n) == VertexAttributeFormat::SHORT) ? 2 : 1;
81 }
82
83 inline int GetStride(int n) const {
84 return GetNumElements(n) * GetElementSizeInBytes(n);
85 }
86
87 inline bool IsDefaultAttribute(int id) const {
88 return (id >= 12) || (attribute_mask & (1ULL << id)) != 0;
89 }
90
91 inline int GetNumTotalAttributes() const {
92 return (int)max_attribute_index + 1;
93 }
94
95 // Attribute loaders map the source vertex data to input attributes
96 // This e.g. allows to load different attributes from different memory locations
97 struct {
98 // Source attribute data offset from the base address
99 u32 data_offset;
100
101 union {
102 BitField<0, 4, u64> comp0;
103 BitField<4, 4, u64> comp1;
104 BitField<8, 4, u64> comp2;
105 BitField<12, 4, u64> comp3;
106 BitField<16, 4, u64> comp4;
107 BitField<20, 4, u64> comp5;
108 BitField<24, 4, u64> comp6;
109 BitField<28, 4, u64> comp7;
110 BitField<32, 4, u64> comp8;
111 BitField<36, 4, u64> comp9;
112 BitField<40, 4, u64> comp10;
113 BitField<44, 4, u64> comp11;
114
115 // bytes for a single vertex in this loader
116 BitField<48, 8, u64> byte_count;
117
118 BitField<60, 4, u64> component_count;
119 };
120
121 inline int GetComponent(int n) const {
122 u64 components[] = {comp0, comp1, comp2, comp3, comp4, comp5,
123 comp6, comp7, comp8, comp9, comp10, comp11};
124 return (int)components[n];
125 }
126 } attribute_loaders[12];
127 } vertex_attributes;
128
129 struct {
130 enum IndexFormat : u32 {
131 BYTE = 0,
132 SHORT = 1,
133 };
134
135 union {
136 BitField<0, 31, u32> offset; // relative to base attribute address
137 BitField<31, 1, IndexFormat> format;
138 };
139 } index_array;
140
141 // Number of vertices to render
142 u32 num_vertices;
143
144 INSERT_PADDING_WORDS(0x1);
145
146 // The index of the first vertex to render
147 u32 vertex_offset;
148
149 INSERT_PADDING_WORDS(0x3);
150
151 // These two trigger rendering of triangles
152 u32 trigger_draw;
153 u32 trigger_draw_indexed;
154
155 INSERT_PADDING_WORDS(0x2);
156
157 // These registers are used to setup the default "fall-back" vertex shader attributes
158 struct {
159 // Index of the current default attribute
160 u32 index;
161
162 // Writing to these registers sets the "current" default attribute.
163 u32 set_value[3];
164 } vs_default_attributes_setup;
165
166 INSERT_PADDING_WORDS(0x2);
167
168 struct {
169 // There are two channels that can be used to configure the next command buffer, which can
170 // be then executed by writing to the "trigger" registers. There are two reasons why a game
171 // might use this feature:
172 // 1) With this, an arbitrary number of additional command buffers may be executed in
173 // sequence without requiring any intervention of the CPU after the initial one is
174 // kicked off.
175 // 2) Games can configure these registers to provide a command list subroutine mechanism.
176
177 BitField<0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer
178 BitField<0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer
179 u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to
180
181 unsigned GetSize(unsigned index) const {
182 ASSERT(index < 2);
183 return 8 * size[index];
184 }
185
186 PAddr GetPhysicalAddress(unsigned index) const {
187 ASSERT(index < 2);
188 return (PAddr)(8 * addr[index]);
189 }
190 } command_buffer;
191
192 INSERT_PADDING_WORDS(4);
193
194 /// Number of input attributes to the vertex shader minus 1
195 BitField<0, 4, u32> max_input_attrib_index;
196
197 INSERT_PADDING_WORDS(2);
198
199 enum class GPUMode : u32 {
200 Drawing = 0,
201 Configuring = 1,
202 };
203
204 GPUMode gpu_mode;
205
206 INSERT_PADDING_WORDS(0x18);
207
208 enum class TriangleTopology : u32 {
209 List = 0,
210 Strip = 1,
211 Fan = 2,
212 Shader = 3, // Programmable setup unit implemented in a geometry shader
213 };
214
215 BitField<8, 2, TriangleTopology> triangle_topology;
216
217 u32 restart_primitive;
218
219 INSERT_PADDING_WORDS(0x20);
220};
221
222static_assert(sizeof(PipelineRegs) == 0x80 * sizeof(u32), "PipelineRegs struct has incorrect size");
223
224} // namespace Pica
diff --git a/src/video_core/regs_rasterizer.h b/src/video_core/regs_rasterizer.h
new file mode 100644
index 000000000..a471a3b38
--- /dev/null
+++ b/src/video_core/regs_rasterizer.h
@@ -0,0 +1,129 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8
9#include "common/bit_field.h"
10#include "common/common_funcs.h"
11#include "common/common_types.h"
12
13namespace Pica {
14
15struct RasterizerRegs {
16 enum class CullMode : u32 {
17 // Select which polygons are considered to be "frontfacing".
18 KeepAll = 0,
19 KeepClockWise = 1,
20 KeepCounterClockWise = 2,
21 // TODO: What does the third value imply?
22 };
23
24 union {
25 BitField<0, 2, CullMode> cull_mode;
26 };
27
28 BitField<0, 24, u32> viewport_size_x;
29
30 INSERT_PADDING_WORDS(0x1);
31
32 BitField<0, 24, u32> viewport_size_y;
33
34 INSERT_PADDING_WORDS(0x9);
35
36 BitField<0, 24, u32> viewport_depth_range; // float24
37 BitField<0, 24, u32> viewport_depth_near_plane; // float24
38
39 BitField<0, 3, u32> vs_output_total;
40
41 union VSOutputAttributes {
42 // Maps components of output vertex attributes to semantics
43 enum Semantic : u32 {
44 POSITION_X = 0,
45 POSITION_Y = 1,
46 POSITION_Z = 2,
47 POSITION_W = 3,
48
49 QUATERNION_X = 4,
50 QUATERNION_Y = 5,
51 QUATERNION_Z = 6,
52 QUATERNION_W = 7,
53
54 COLOR_R = 8,
55 COLOR_G = 9,
56 COLOR_B = 10,
57 COLOR_A = 11,
58
59 TEXCOORD0_U = 12,
60 TEXCOORD0_V = 13,
61 TEXCOORD1_U = 14,
62 TEXCOORD1_V = 15,
63
64 TEXCOORD0_W = 16,
65
66 VIEW_X = 18,
67 VIEW_Y = 19,
68 VIEW_Z = 20,
69
70 TEXCOORD2_U = 22,
71 TEXCOORD2_V = 23,
72
73 INVALID = 31,
74 };
75
76 BitField<0, 5, Semantic> map_x;
77 BitField<8, 5, Semantic> map_y;
78 BitField<16, 5, Semantic> map_z;
79 BitField<24, 5, Semantic> map_w;
80 } vs_output_attributes[7];
81
82 INSERT_PADDING_WORDS(0xe);
83
84 enum class ScissorMode : u32 {
85 Disabled = 0,
86 Exclude = 1, // Exclude pixels inside the scissor box
87
88 Include = 3 // Exclude pixels outside the scissor box
89 };
90
91 struct {
92 BitField<0, 2, ScissorMode> mode;
93
94 union {
95 BitField<0, 16, u32> x1;
96 BitField<16, 16, u32> y1;
97 };
98
99 union {
100 BitField<0, 16, u32> x2;
101 BitField<16, 16, u32> y2;
102 };
103 } scissor_test;
104
105 union {
106 BitField<0, 10, s32> x;
107 BitField<16, 10, s32> y;
108 } viewport_corner;
109
110 INSERT_PADDING_WORDS(0x1);
111
112 // TODO: early depth
113 INSERT_PADDING_WORDS(0x1);
114
115 INSERT_PADDING_WORDS(0x2);
116
117 enum DepthBuffering : u32 {
118 WBuffering = 0,
119 ZBuffering = 1,
120 };
121 BitField<0, 1, DepthBuffering> depthmap_enable;
122
123 INSERT_PADDING_WORDS(0x12);
124};
125
126static_assert(sizeof(RasterizerRegs) == 0x40 * sizeof(u32),
127 "RasterizerRegs struct has incorrect size");
128
129} // namespace Pica
diff --git a/src/video_core/regs_shader.h b/src/video_core/regs_shader.h
new file mode 100644
index 000000000..ddb1ee451
--- /dev/null
+++ b/src/video_core/regs_shader.h
@@ -0,0 +1,104 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8
9#include "common/bit_field.h"
10#include "common/common_funcs.h"
11#include "common/common_types.h"
12
13namespace Pica {
14
15struct ShaderRegs {
16 BitField<0, 16, u32> bool_uniforms;
17
18 union {
19 BitField<0, 8, u32> x;
20 BitField<8, 8, u32> y;
21 BitField<16, 8, u32> z;
22 BitField<24, 8, u32> w;
23 } int_uniforms[4];
24
25 INSERT_PADDING_WORDS(0x4);
26
27 union {
28 // Number of input attributes to shader unit - 1
29 BitField<0, 4, u32> max_input_attribute_index;
30 };
31
32 // Offset to shader program entry point (in words)
33 BitField<0, 16, u32> main_offset;
34
35 /// Maps input attributes to registers. 4-bits per attribute, specifying a register index
36 u32 input_attribute_to_register_map_low;
37 u32 input_attribute_to_register_map_high;
38
39 unsigned int GetRegisterForAttribute(unsigned int attribute_index) const {
40 u64 map = ((u64)input_attribute_to_register_map_high << 32) |
41 (u64)input_attribute_to_register_map_low;
42 return (map >> (attribute_index * 4)) & 0b1111;
43 }
44
45 BitField<0, 16, u32> output_mask;
46
47 // 0x28E, CODETRANSFER_END
48 INSERT_PADDING_WORDS(0x2);
49
50 struct {
51 enum Format : u32 {
52 FLOAT24 = 0,
53 FLOAT32 = 1,
54 };
55
56 bool IsFloat32() const {
57 return format == FLOAT32;
58 }
59
60 union {
61 // Index of the next uniform to write to
62 // TODO: ctrulib uses 8 bits for this, however that seems to yield lots of invalid
63 // indices
64 // TODO: Maybe the uppermost index is for the geometry shader? Investigate!
65 BitField<0, 7, u32> index;
66
67 BitField<31, 1, Format> format;
68 };
69
70 // Writing to these registers sets the current uniform.
71 u32 set_value[8];
72
73 } uniform_setup;
74
75 INSERT_PADDING_WORDS(0x2);
76
77 struct {
78 // Offset of the next instruction to write code to.
79 // Incremented with each instruction write.
80 u32 offset;
81
82 // Writing to these registers sets the "current" word in the shader program.
83 u32 set_word[8];
84 } program;
85
86 INSERT_PADDING_WORDS(0x1);
87
88 // This register group is used to load an internal table of swizzling patterns,
89 // which are indexed by each shader instruction to specify vector component swizzling.
90 struct {
91 // Offset of the next swizzle pattern to write code to.
92 // Incremented with each instruction write.
93 u32 offset;
94
95 // Writing to these registers sets the current swizzle pattern in the table.
96 u32 set_word[8];
97 } swizzle_patterns;
98
99 INSERT_PADDING_WORDS(0x2);
100};
101
102static_assert(sizeof(ShaderRegs) == 0x30 * sizeof(u32), "ShaderRegs struct has incorrect size");
103
104} // namespace Pica
diff --git a/src/video_core/regs_texturing.h b/src/video_core/regs_texturing.h
new file mode 100644
index 000000000..be8bc6826
--- /dev/null
+++ b/src/video_core/regs_texturing.h
@@ -0,0 +1,328 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8
9#include "common/assert.h"
10#include "common/bit_field.h"
11#include "common/common_funcs.h"
12#include "common/common_types.h"
13
14namespace Pica {
15
16struct TexturingRegs {
17 struct TextureConfig {
18 enum TextureType : u32 {
19 Texture2D = 0,
20 TextureCube = 1,
21 Shadow2D = 2,
22 Projection2D = 3,
23 ShadowCube = 4,
24 Disabled = 5,
25 };
26
27 enum WrapMode : u32 {
28 ClampToEdge = 0,
29 ClampToBorder = 1,
30 Repeat = 2,
31 MirroredRepeat = 3,
32 };
33
34 enum TextureFilter : u32 {
35 Nearest = 0,
36 Linear = 1,
37 };
38
39 union {
40 u32 raw;
41 BitField<0, 8, u32> r;
42 BitField<8, 8, u32> g;
43 BitField<16, 8, u32> b;
44 BitField<24, 8, u32> a;
45 } border_color;
46
47 union {
48 BitField<0, 16, u32> height;
49 BitField<16, 16, u32> width;
50 };
51
52 union {
53 BitField<1, 1, TextureFilter> mag_filter;
54 BitField<2, 1, TextureFilter> min_filter;
55 BitField<8, 2, WrapMode> wrap_t;
56 BitField<12, 2, WrapMode> wrap_s;
57 BitField<28, 2, TextureType>
58 type; ///< @note Only valid for texture 0 according to 3DBrew.
59 };
60
61 INSERT_PADDING_WORDS(0x1);
62
63 u32 address;
64
65 PAddr GetPhysicalAddress() const {
66 return address * 8;
67 }
68
69 // texture1 and texture2 store the texture format directly after the address
70 // whereas texture0 inserts some additional flags inbetween.
71 // Hence, we store the format separately so that all other parameters can be described
72 // in a single structure.
73 };
74
75 enum class TextureFormat : u32 {
76 RGBA8 = 0,
77 RGB8 = 1,
78 RGB5A1 = 2,
79 RGB565 = 3,
80 RGBA4 = 4,
81 IA8 = 5,
82 RG8 = 6, ///< @note Also called HILO8 in 3DBrew.
83 I8 = 7,
84 A8 = 8,
85 IA4 = 9,
86 I4 = 10,
87 A4 = 11,
88 ETC1 = 12, // compressed
89 ETC1A4 = 13, // compressed
90 };
91
92 static unsigned NibblesPerPixel(TextureFormat format) {
93 switch (format) {
94 case TextureFormat::RGBA8:
95 return 8;
96
97 case TextureFormat::RGB8:
98 return 6;
99
100 case TextureFormat::RGB5A1:
101 case TextureFormat::RGB565:
102 case TextureFormat::RGBA4:
103 case TextureFormat::IA8:
104 case TextureFormat::RG8:
105 return 4;
106
107 case TextureFormat::I4:
108 case TextureFormat::A4:
109 return 1;
110
111 case TextureFormat::I8:
112 case TextureFormat::A8:
113 case TextureFormat::IA4:
114
115 default: // placeholder for yet unknown formats
116 UNIMPLEMENTED();
117 return 0;
118 }
119 }
120
121 union {
122 BitField<0, 1, u32> texture0_enable;
123 BitField<1, 1, u32> texture1_enable;
124 BitField<2, 1, u32> texture2_enable;
125 };
126 TextureConfig texture0;
127 INSERT_PADDING_WORDS(0x8);
128 BitField<0, 4, TextureFormat> texture0_format;
129 BitField<0, 1, u32> fragment_lighting_enable;
130 INSERT_PADDING_WORDS(0x1);
131 TextureConfig texture1;
132 BitField<0, 4, TextureFormat> texture1_format;
133 INSERT_PADDING_WORDS(0x2);
134 TextureConfig texture2;
135 BitField<0, 4, TextureFormat> texture2_format;
136 INSERT_PADDING_WORDS(0x21);
137
138 struct FullTextureConfig {
139 const bool enabled;
140 const TextureConfig config;
141 const TextureFormat format;
142 };
143 const std::array<FullTextureConfig, 3> GetTextures() const {
144 return {{
145 {texture0_enable.ToBool(), texture0, texture0_format},
146 {texture1_enable.ToBool(), texture1, texture1_format},
147 {texture2_enable.ToBool(), texture2, texture2_format},
148 }};
149 }
150
151 // 0xc0-0xff: Texture Combiner (akin to glTexEnv)
152 struct TevStageConfig {
153 enum class Source : u32 {
154 PrimaryColor = 0x0,
155 PrimaryFragmentColor = 0x1,
156 SecondaryFragmentColor = 0x2,
157
158 Texture0 = 0x3,
159 Texture1 = 0x4,
160 Texture2 = 0x5,
161 Texture3 = 0x6,
162
163 PreviousBuffer = 0xd,
164 Constant = 0xe,
165 Previous = 0xf,
166 };
167
168 enum class ColorModifier : u32 {
169 SourceColor = 0x0,
170 OneMinusSourceColor = 0x1,
171 SourceAlpha = 0x2,
172 OneMinusSourceAlpha = 0x3,
173 SourceRed = 0x4,
174 OneMinusSourceRed = 0x5,
175
176 SourceGreen = 0x8,
177 OneMinusSourceGreen = 0x9,
178
179 SourceBlue = 0xc,
180 OneMinusSourceBlue = 0xd,
181 };
182
183 enum class AlphaModifier : u32 {
184 SourceAlpha = 0x0,
185 OneMinusSourceAlpha = 0x1,
186 SourceRed = 0x2,
187 OneMinusSourceRed = 0x3,
188 SourceGreen = 0x4,
189 OneMinusSourceGreen = 0x5,
190 SourceBlue = 0x6,
191 OneMinusSourceBlue = 0x7,
192 };
193
194 enum class Operation : u32 {
195 Replace = 0,
196 Modulate = 1,
197 Add = 2,
198 AddSigned = 3,
199 Lerp = 4,
200 Subtract = 5,
201 Dot3_RGB = 6,
202
203 MultiplyThenAdd = 8,
204 AddThenMultiply = 9,
205 };
206
207 union {
208 u32 sources_raw;
209 BitField<0, 4, Source> color_source1;
210 BitField<4, 4, Source> color_source2;
211 BitField<8, 4, Source> color_source3;
212 BitField<16, 4, Source> alpha_source1;
213 BitField<20, 4, Source> alpha_source2;
214 BitField<24, 4, Source> alpha_source3;
215 };
216
217 union {
218 u32 modifiers_raw;
219 BitField<0, 4, ColorModifier> color_modifier1;
220 BitField<4, 4, ColorModifier> color_modifier2;
221 BitField<8, 4, ColorModifier> color_modifier3;
222 BitField<12, 3, AlphaModifier> alpha_modifier1;
223 BitField<16, 3, AlphaModifier> alpha_modifier2;
224 BitField<20, 3, AlphaModifier> alpha_modifier3;
225 };
226
227 union {
228 u32 ops_raw;
229 BitField<0, 4, Operation> color_op;
230 BitField<16, 4, Operation> alpha_op;
231 };
232
233 union {
234 u32 const_color;
235 BitField<0, 8, u32> const_r;
236 BitField<8, 8, u32> const_g;
237 BitField<16, 8, u32> const_b;
238 BitField<24, 8, u32> const_a;
239 };
240
241 union {
242 u32 scales_raw;
243 BitField<0, 2, u32> color_scale;
244 BitField<16, 2, u32> alpha_scale;
245 };
246
247 inline unsigned GetColorMultiplier() const {
248 return (color_scale < 3) ? (1 << color_scale) : 1;
249 }
250
251 inline unsigned GetAlphaMultiplier() const {
252 return (alpha_scale < 3) ? (1 << alpha_scale) : 1;
253 }
254 };
255
256 TevStageConfig tev_stage0;
257 INSERT_PADDING_WORDS(0x3);
258 TevStageConfig tev_stage1;
259 INSERT_PADDING_WORDS(0x3);
260 TevStageConfig tev_stage2;
261 INSERT_PADDING_WORDS(0x3);
262 TevStageConfig tev_stage3;
263 INSERT_PADDING_WORDS(0x3);
264
265 enum class FogMode : u32 {
266 None = 0,
267 Fog = 5,
268 Gas = 7,
269 };
270
271 union {
272 BitField<0, 3, FogMode> fog_mode;
273 BitField<16, 1, u32> fog_flip;
274
275 union {
276 // Tev stages 0-3 write their output to the combiner buffer if the corresponding bit in
277 // these masks are set
278 BitField<8, 4, u32> update_mask_rgb;
279 BitField<12, 4, u32> update_mask_a;
280
281 bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const {
282 return (stage_index < 4) && (update_mask_rgb & (1 << stage_index));
283 }
284
285 bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const {
286 return (stage_index < 4) && (update_mask_a & (1 << stage_index));
287 }
288 } tev_combiner_buffer_input;
289 };
290
291 union {
292 u32 raw;
293 BitField<0, 8, u32> r;
294 BitField<8, 8, u32> g;
295 BitField<16, 8, u32> b;
296 } fog_color;
297
298 INSERT_PADDING_WORDS(0x4);
299
300 BitField<0, 16, u32> fog_lut_offset;
301
302 INSERT_PADDING_WORDS(0x1);
303
304 u32 fog_lut_data[8];
305
306 TevStageConfig tev_stage4;
307 INSERT_PADDING_WORDS(0x3);
308 TevStageConfig tev_stage5;
309
310 union {
311 u32 raw;
312 BitField<0, 8, u32> r;
313 BitField<8, 8, u32> g;
314 BitField<16, 8, u32> b;
315 BitField<24, 8, u32> a;
316 } tev_combiner_buffer_color;
317
318 INSERT_PADDING_WORDS(0x2);
319
320 const std::array<TevStageConfig, 6> GetTevStages() const {
321 return {{tev_stage0, tev_stage1, tev_stage2, tev_stage3, tev_stage4, tev_stage5}};
322 };
323};
324
325static_assert(sizeof(TexturingRegs) == 0x80 * sizeof(u32),
326 "TexturingRegs struct has incorrect size");
327
328} // namespace Pica
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 071e4ace0..75736c99f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -14,8 +14,8 @@
14#include "common/microprofile.h" 14#include "common/microprofile.h"
15#include "common/vector_math.h" 15#include "common/vector_math.h"
16#include "core/hw/gpu.h" 16#include "core/hw/gpu.h"
17#include "video_core/pica.h"
18#include "video_core/pica_state.h" 17#include "video_core/pica_state.h"
18#include "video_core/regs.h"
19#include "video_core/renderer_opengl/gl_rasterizer.h" 19#include "video_core/renderer_opengl/gl_rasterizer.h"
20#include "video_core/renderer_opengl/gl_shader_gen.h" 20#include "video_core/renderer_opengl/gl_shader_gen.h"
21#include "video_core/renderer_opengl/gl_shader_util.h" 21#include "video_core/renderer_opengl/gl_shader_util.h"
@@ -26,13 +26,15 @@ MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192));
26MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255)); 26MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
27MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); 27MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
28 28
29static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) { 29static bool IsPassThroughTevStage(const Pica::TexturingRegs::TevStageConfig& stage) {
30 return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace && 30 using TevStageConfig = Pica::TexturingRegs::TevStageConfig;
31 stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace && 31
32 stage.color_source1 == Pica::Regs::TevStageConfig::Source::Previous && 32 return (stage.color_op == TevStageConfig::Operation::Replace &&
33 stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous && 33 stage.alpha_op == TevStageConfig::Operation::Replace &&
34 stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor && 34 stage.color_source1 == TevStageConfig::Source::Previous &&
35 stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha && 35 stage.alpha_source1 == TevStageConfig::Source::Previous &&
36 stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor &&
37 stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha &&
36 stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1); 38 stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1);
37} 39}
38 40
@@ -181,7 +183,7 @@ void RasterizerOpenGL::DrawTriangles() {
181 CachedSurface* depth_surface; 183 CachedSurface* depth_surface;
182 MathUtil::Rectangle<int> rect; 184 MathUtil::Rectangle<int> rect;
183 std::tie(color_surface, depth_surface, rect) = 185 std::tie(color_surface, depth_surface, rect) =
184 res_cache.GetFramebufferSurfaces(regs.framebuffer); 186 res_cache.GetFramebufferSurfaces(regs.framebuffer.framebuffer);
185 187
186 state.draw.draw_framebuffer = framebuffer.handle; 188 state.draw.draw_framebuffer = framebuffer.handle;
187 state.Apply(); 189 state.Apply();
@@ -190,20 +192,24 @@ void RasterizerOpenGL::DrawTriangles() {
190 color_surface != nullptr ? color_surface->texture.handle : 0, 0); 192 color_surface != nullptr ? color_surface->texture.handle : 0, 0);
191 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 193 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
192 depth_surface != nullptr ? depth_surface->texture.handle : 0, 0); 194 depth_surface != nullptr ? depth_surface->texture.handle : 0, 0);
193 bool has_stencil = regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; 195 bool has_stencil =
196 regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8;
194 glFramebufferTexture2D( 197 glFramebufferTexture2D(
195 GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 198 GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
196 (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0); 199 (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0);
197 200
198 // Sync the viewport 201 // Sync the viewport
199 // These registers hold half-width and half-height, so must be multiplied by 2 202 // These registers hold half-width and half-height, so must be multiplied by 2
200 GLsizei viewport_width = (GLsizei)Pica::float24::FromRaw(regs.viewport_size_x).ToFloat32() * 2; 203 GLsizei viewport_width =
201 GLsizei viewport_height = (GLsizei)Pica::float24::FromRaw(regs.viewport_size_y).ToFloat32() * 2; 204 (GLsizei)Pica::float24::FromRaw(regs.rasterizer.viewport_size_x).ToFloat32() * 2;
205 GLsizei viewport_height =
206 (GLsizei)Pica::float24::FromRaw(regs.rasterizer.viewport_size_y).ToFloat32() * 2;
202 207
203 glViewport((GLint)(rect.left + regs.viewport_corner.x * color_surface->res_scale_width), 208 glViewport(
204 (GLint)(rect.bottom + regs.viewport_corner.y * color_surface->res_scale_height), 209 (GLint)(rect.left + regs.rasterizer.viewport_corner.x * color_surface->res_scale_width),
205 (GLsizei)(viewport_width * color_surface->res_scale_width), 210 (GLint)(rect.bottom + regs.rasterizer.viewport_corner.y * color_surface->res_scale_height),
206 (GLsizei)(viewport_height * color_surface->res_scale_height)); 211 (GLsizei)(viewport_width * color_surface->res_scale_width),
212 (GLsizei)(viewport_height * color_surface->res_scale_height));
207 213
208 if (uniform_block_data.data.framebuffer_scale[0] != color_surface->res_scale_width || 214 if (uniform_block_data.data.framebuffer_scale[0] != color_surface->res_scale_width ||
209 uniform_block_data.data.framebuffer_scale[1] != color_surface->res_scale_height) { 215 uniform_block_data.data.framebuffer_scale[1] != color_surface->res_scale_height) {
@@ -215,16 +221,16 @@ void RasterizerOpenGL::DrawTriangles() {
215 221
216 // Scissor checks are window-, not viewport-relative, which means that if the cached texture 222 // Scissor checks are window-, not viewport-relative, which means that if the cached texture
217 // sub-rect changes, the scissor bounds also need to be updated. 223 // sub-rect changes, the scissor bounds also need to be updated.
218 GLint scissor_x1 = 224 GLint scissor_x1 = static_cast<GLint>(
219 static_cast<GLint>(rect.left + regs.scissor_test.x1 * color_surface->res_scale_width); 225 rect.left + regs.rasterizer.scissor_test.x1 * color_surface->res_scale_width);
220 GLint scissor_y1 = 226 GLint scissor_y1 = static_cast<GLint>(
221 static_cast<GLint>(rect.bottom + regs.scissor_test.y1 * color_surface->res_scale_height); 227 rect.bottom + regs.rasterizer.scissor_test.y1 * color_surface->res_scale_height);
222 // x2, y2 have +1 added to cover the entire pixel area, otherwise you might get cracks when 228 // x2, y2 have +1 added to cover the entire pixel area, otherwise you might get cracks when
223 // scaling or doing multisampling. 229 // scaling or doing multisampling.
224 GLint scissor_x2 = 230 GLint scissor_x2 = static_cast<GLint>(
225 static_cast<GLint>(rect.left + (regs.scissor_test.x2 + 1) * color_surface->res_scale_width); 231 rect.left + (regs.rasterizer.scissor_test.x2 + 1) * color_surface->res_scale_width);
226 GLint scissor_y2 = static_cast<GLint>( 232 GLint scissor_y2 = static_cast<GLint>(
227 rect.bottom + (regs.scissor_test.y2 + 1) * color_surface->res_scale_height); 233 rect.bottom + (regs.rasterizer.scissor_test.y2 + 1) * color_surface->res_scale_height);
228 234
229 if (uniform_block_data.data.scissor_x1 != scissor_x1 || 235 if (uniform_block_data.data.scissor_x1 != scissor_x1 ||
230 uniform_block_data.data.scissor_x2 != scissor_x2 || 236 uniform_block_data.data.scissor_x2 != scissor_x2 ||
@@ -239,7 +245,7 @@ void RasterizerOpenGL::DrawTriangles() {
239 } 245 }
240 246
241 // Sync and bind the texture surfaces 247 // Sync and bind the texture surfaces
242 const auto pica_textures = regs.GetTextures(); 248 const auto pica_textures = regs.texturing.GetTextures();
243 for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) { 249 for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
244 const auto& texture = pica_textures[texture_index]; 250 const auto& texture = pica_textures[texture_index];
245 251
@@ -316,69 +322,69 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
316 322
317 switch (id) { 323 switch (id) {
318 // Culling 324 // Culling
319 case PICA_REG_INDEX(cull_mode): 325 case PICA_REG_INDEX(rasterizer.cull_mode):
320 SyncCullMode(); 326 SyncCullMode();
321 break; 327 break;
322 328
323 // Depth modifiers 329 // Depth modifiers
324 case PICA_REG_INDEX(viewport_depth_range): 330 case PICA_REG_INDEX(rasterizer.viewport_depth_range):
325 SyncDepthScale(); 331 SyncDepthScale();
326 break; 332 break;
327 case PICA_REG_INDEX(viewport_depth_near_plane): 333 case PICA_REG_INDEX(rasterizer.viewport_depth_near_plane):
328 SyncDepthOffset(); 334 SyncDepthOffset();
329 break; 335 break;
330 336
331 // Depth buffering 337 // Depth buffering
332 case PICA_REG_INDEX(depthmap_enable): 338 case PICA_REG_INDEX(rasterizer.depthmap_enable):
333 shader_dirty = true; 339 shader_dirty = true;
334 break; 340 break;
335 341
336 // Blending 342 // Blending
337 case PICA_REG_INDEX(output_merger.alphablend_enable): 343 case PICA_REG_INDEX(framebuffer.output_merger.alphablend_enable):
338 SyncBlendEnabled(); 344 SyncBlendEnabled();
339 break; 345 break;
340 case PICA_REG_INDEX(output_merger.alpha_blending): 346 case PICA_REG_INDEX(framebuffer.output_merger.alpha_blending):
341 SyncBlendFuncs(); 347 SyncBlendFuncs();
342 break; 348 break;
343 case PICA_REG_INDEX(output_merger.blend_const): 349 case PICA_REG_INDEX(framebuffer.output_merger.blend_const):
344 SyncBlendColor(); 350 SyncBlendColor();
345 break; 351 break;
346 352
347 // Fog state 353 // Fog state
348 case PICA_REG_INDEX(fog_color): 354 case PICA_REG_INDEX(texturing.fog_color):
349 SyncFogColor(); 355 SyncFogColor();
350 break; 356 break;
351 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[0], 0xe8): 357 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[0], 0xe8):
352 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[1], 0xe9): 358 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[1], 0xe9):
353 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[2], 0xea): 359 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[2], 0xea):
354 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[3], 0xeb): 360 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[3], 0xeb):
355 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[4], 0xec): 361 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[4], 0xec):
356 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[5], 0xed): 362 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[5], 0xed):
357 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[6], 0xee): 363 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[6], 0xee):
358 case PICA_REG_INDEX_WORKAROUND(fog_lut_data[7], 0xef): 364 case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[7], 0xef):
359 uniform_block_data.fog_lut_dirty = true; 365 uniform_block_data.fog_lut_dirty = true;
360 break; 366 break;
361 367
362 // Alpha test 368 // Alpha test
363 case PICA_REG_INDEX(output_merger.alpha_test): 369 case PICA_REG_INDEX(framebuffer.output_merger.alpha_test):
364 SyncAlphaTest(); 370 SyncAlphaTest();
365 shader_dirty = true; 371 shader_dirty = true;
366 break; 372 break;
367 373
368 // Sync GL stencil test + stencil write mask 374 // Sync GL stencil test + stencil write mask
369 // (Pica stencil test function register also contains a stencil write mask) 375 // (Pica stencil test function register also contains a stencil write mask)
370 case PICA_REG_INDEX(output_merger.stencil_test.raw_func): 376 case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_func):
371 SyncStencilTest(); 377 SyncStencilTest();
372 SyncStencilWriteMask(); 378 SyncStencilWriteMask();
373 break; 379 break;
374 case PICA_REG_INDEX(output_merger.stencil_test.raw_op): 380 case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_op):
375 case PICA_REG_INDEX(framebuffer.depth_format): 381 case PICA_REG_INDEX(framebuffer.framebuffer.depth_format):
376 SyncStencilTest(); 382 SyncStencilTest();
377 break; 383 break;
378 384
379 // Sync GL depth test + depth and color write mask 385 // Sync GL depth test + depth and color write mask
380 // (Pica depth test function register also contains a depth and color write mask) 386 // (Pica depth test function register also contains a depth and color write mask)
381 case PICA_REG_INDEX(output_merger.depth_test_enable): 387 case PICA_REG_INDEX(framebuffer.output_merger.depth_test_enable):
382 SyncDepthTest(); 388 SyncDepthTest();
383 SyncDepthWriteMask(); 389 SyncDepthWriteMask();
384 SyncColorWriteMask(); 390 SyncColorWriteMask();
@@ -386,82 +392,82 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
386 392
387 // Sync GL depth and stencil write mask 393 // Sync GL depth and stencil write mask
388 // (This is a dedicated combined depth / stencil write-enable register) 394 // (This is a dedicated combined depth / stencil write-enable register)
389 case PICA_REG_INDEX(framebuffer.allow_depth_stencil_write): 395 case PICA_REG_INDEX(framebuffer.framebuffer.allow_depth_stencil_write):
390 SyncDepthWriteMask(); 396 SyncDepthWriteMask();
391 SyncStencilWriteMask(); 397 SyncStencilWriteMask();
392 break; 398 break;
393 399
394 // Sync GL color write mask 400 // Sync GL color write mask
395 // (This is a dedicated color write-enable register) 401 // (This is a dedicated color write-enable register)
396 case PICA_REG_INDEX(framebuffer.allow_color_write): 402 case PICA_REG_INDEX(framebuffer.framebuffer.allow_color_write):
397 SyncColorWriteMask(); 403 SyncColorWriteMask();
398 break; 404 break;
399 405
400 // Scissor test 406 // Scissor test
401 case PICA_REG_INDEX(scissor_test.mode): 407 case PICA_REG_INDEX(rasterizer.scissor_test.mode):
402 shader_dirty = true; 408 shader_dirty = true;
403 break; 409 break;
404 410
405 // Logic op 411 // Logic op
406 case PICA_REG_INDEX(output_merger.logic_op): 412 case PICA_REG_INDEX(framebuffer.output_merger.logic_op):
407 SyncLogicOp(); 413 SyncLogicOp();
408 break; 414 break;
409 415
410 // Texture 0 type 416 // Texture 0 type
411 case PICA_REG_INDEX(texture0.type): 417 case PICA_REG_INDEX(texturing.texture0.type):
412 shader_dirty = true; 418 shader_dirty = true;
413 break; 419 break;
414 420
415 // TEV stages 421 // TEV stages
416 // (This also syncs fog_mode and fog_flip which are part of tev_combiner_buffer_input) 422 // (This also syncs fog_mode and fog_flip which are part of tev_combiner_buffer_input)
417 case PICA_REG_INDEX(tev_stage0.color_source1): 423 case PICA_REG_INDEX(texturing.tev_stage0.color_source1):
418 case PICA_REG_INDEX(tev_stage0.color_modifier1): 424 case PICA_REG_INDEX(texturing.tev_stage0.color_modifier1):
419 case PICA_REG_INDEX(tev_stage0.color_op): 425 case PICA_REG_INDEX(texturing.tev_stage0.color_op):
420 case PICA_REG_INDEX(tev_stage0.color_scale): 426 case PICA_REG_INDEX(texturing.tev_stage0.color_scale):
421 case PICA_REG_INDEX(tev_stage1.color_source1): 427 case PICA_REG_INDEX(texturing.tev_stage1.color_source1):
422 case PICA_REG_INDEX(tev_stage1.color_modifier1): 428 case PICA_REG_INDEX(texturing.tev_stage1.color_modifier1):
423 case PICA_REG_INDEX(tev_stage1.color_op): 429 case PICA_REG_INDEX(texturing.tev_stage1.color_op):
424 case PICA_REG_INDEX(tev_stage1.color_scale): 430 case PICA_REG_INDEX(texturing.tev_stage1.color_scale):
425 case PICA_REG_INDEX(tev_stage2.color_source1): 431 case PICA_REG_INDEX(texturing.tev_stage2.color_source1):
426 case PICA_REG_INDEX(tev_stage2.color_modifier1): 432 case PICA_REG_INDEX(texturing.tev_stage2.color_modifier1):
427 case PICA_REG_INDEX(tev_stage2.color_op): 433 case PICA_REG_INDEX(texturing.tev_stage2.color_op):
428 case PICA_REG_INDEX(tev_stage2.color_scale): 434 case PICA_REG_INDEX(texturing.tev_stage2.color_scale):
429 case PICA_REG_INDEX(tev_stage3.color_source1): 435 case PICA_REG_INDEX(texturing.tev_stage3.color_source1):
430 case PICA_REG_INDEX(tev_stage3.color_modifier1): 436 case PICA_REG_INDEX(texturing.tev_stage3.color_modifier1):
431 case PICA_REG_INDEX(tev_stage3.color_op): 437 case PICA_REG_INDEX(texturing.tev_stage3.color_op):
432 case PICA_REG_INDEX(tev_stage3.color_scale): 438 case PICA_REG_INDEX(texturing.tev_stage3.color_scale):
433 case PICA_REG_INDEX(tev_stage4.color_source1): 439 case PICA_REG_INDEX(texturing.tev_stage4.color_source1):
434 case PICA_REG_INDEX(tev_stage4.color_modifier1): 440 case PICA_REG_INDEX(texturing.tev_stage4.color_modifier1):
435 case PICA_REG_INDEX(tev_stage4.color_op): 441 case PICA_REG_INDEX(texturing.tev_stage4.color_op):
436 case PICA_REG_INDEX(tev_stage4.color_scale): 442 case PICA_REG_INDEX(texturing.tev_stage4.color_scale):
437 case PICA_REG_INDEX(tev_stage5.color_source1): 443 case PICA_REG_INDEX(texturing.tev_stage5.color_source1):
438 case PICA_REG_INDEX(tev_stage5.color_modifier1): 444 case PICA_REG_INDEX(texturing.tev_stage5.color_modifier1):
439 case PICA_REG_INDEX(tev_stage5.color_op): 445 case PICA_REG_INDEX(texturing.tev_stage5.color_op):
440 case PICA_REG_INDEX(tev_stage5.color_scale): 446 case PICA_REG_INDEX(texturing.tev_stage5.color_scale):
441 case PICA_REG_INDEX(tev_combiner_buffer_input): 447 case PICA_REG_INDEX(texturing.tev_combiner_buffer_input):
442 shader_dirty = true; 448 shader_dirty = true;
443 break; 449 break;
444 case PICA_REG_INDEX(tev_stage0.const_r): 450 case PICA_REG_INDEX(texturing.tev_stage0.const_r):
445 SyncTevConstColor(0, regs.tev_stage0); 451 SyncTevConstColor(0, regs.texturing.tev_stage0);
446 break; 452 break;
447 case PICA_REG_INDEX(tev_stage1.const_r): 453 case PICA_REG_INDEX(texturing.tev_stage1.const_r):
448 SyncTevConstColor(1, regs.tev_stage1); 454 SyncTevConstColor(1, regs.texturing.tev_stage1);
449 break; 455 break;
450 case PICA_REG_INDEX(tev_stage2.const_r): 456 case PICA_REG_INDEX(texturing.tev_stage2.const_r):
451 SyncTevConstColor(2, regs.tev_stage2); 457 SyncTevConstColor(2, regs.texturing.tev_stage2);
452 break; 458 break;
453 case PICA_REG_INDEX(tev_stage3.const_r): 459 case PICA_REG_INDEX(texturing.tev_stage3.const_r):
454 SyncTevConstColor(3, regs.tev_stage3); 460 SyncTevConstColor(3, regs.texturing.tev_stage3);
455 break; 461 break;
456 case PICA_REG_INDEX(tev_stage4.const_r): 462 case PICA_REG_INDEX(texturing.tev_stage4.const_r):
457 SyncTevConstColor(4, regs.tev_stage4); 463 SyncTevConstColor(4, regs.texturing.tev_stage4);
458 break; 464 break;
459 case PICA_REG_INDEX(tev_stage5.const_r): 465 case PICA_REG_INDEX(texturing.tev_stage5.const_r):
460 SyncTevConstColor(5, regs.tev_stage5); 466 SyncTevConstColor(5, regs.texturing.tev_stage5);
461 break; 467 break;
462 468
463 // TEV combiner buffer color 469 // TEV combiner buffer color
464 case PICA_REG_INDEX(tev_combiner_buffer_color): 470 case PICA_REG_INDEX(texturing.tev_combiner_buffer_color):
465 SyncCombinerColor(); 471 SyncCombinerColor();
466 break; 472 break;
467 473
@@ -976,7 +982,9 @@ void RasterizerOpenGL::SamplerInfo::Create() {
976 // Other attributes have correct defaults 982 // Other attributes have correct defaults
977} 983}
978 984
979void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Pica::Regs::TextureConfig& config) { 985void RasterizerOpenGL::SamplerInfo::SyncWithConfig(
986 const Pica::TexturingRegs::TextureConfig& config) {
987
980 GLuint s = sampler.handle; 988 GLuint s = sampler.handle;
981 989
982 if (mag_filter != config.mag_filter) { 990 if (mag_filter != config.mag_filter) {
@@ -1088,7 +1096,7 @@ void RasterizerOpenGL::SetShader() {
1088 SyncDepthOffset(); 1096 SyncDepthOffset();
1089 SyncAlphaTest(); 1097 SyncAlphaTest();
1090 SyncCombinerColor(); 1098 SyncCombinerColor();
1091 auto& tev_stages = Pica::g_state.regs.GetTevStages(); 1099 auto& tev_stages = Pica::g_state.regs.texturing.GetTevStages();
1092 for (int index = 0; index < tev_stages.size(); ++index) 1100 for (int index = 0; index < tev_stages.size(); ++index)
1093 SyncTevConstColor(index, tev_stages[index]); 1101 SyncTevConstColor(index, tev_stages[index]);
1094 1102
@@ -1110,30 +1118,31 @@ void RasterizerOpenGL::SetShader() {
1110void RasterizerOpenGL::SyncCullMode() { 1118void RasterizerOpenGL::SyncCullMode() {
1111 const auto& regs = Pica::g_state.regs; 1119 const auto& regs = Pica::g_state.regs;
1112 1120
1113 switch (regs.cull_mode) { 1121 switch (regs.rasterizer.cull_mode) {
1114 case Pica::Regs::CullMode::KeepAll: 1122 case Pica::RasterizerRegs::CullMode::KeepAll:
1115 state.cull.enabled = false; 1123 state.cull.enabled = false;
1116 break; 1124 break;
1117 1125
1118 case Pica::Regs::CullMode::KeepClockWise: 1126 case Pica::RasterizerRegs::CullMode::KeepClockWise:
1119 state.cull.enabled = true; 1127 state.cull.enabled = true;
1120 state.cull.front_face = GL_CW; 1128 state.cull.front_face = GL_CW;
1121 break; 1129 break;
1122 1130
1123 case Pica::Regs::CullMode::KeepCounterClockWise: 1131 case Pica::RasterizerRegs::CullMode::KeepCounterClockWise:
1124 state.cull.enabled = true; 1132 state.cull.enabled = true;
1125 state.cull.front_face = GL_CCW; 1133 state.cull.front_face = GL_CCW;
1126 break; 1134 break;
1127 1135
1128 default: 1136 default:
1129 LOG_CRITICAL(Render_OpenGL, "Unknown cull mode %d", regs.cull_mode.Value()); 1137 LOG_CRITICAL(Render_OpenGL, "Unknown cull mode %d", regs.rasterizer.cull_mode.Value());
1130 UNIMPLEMENTED(); 1138 UNIMPLEMENTED();
1131 break; 1139 break;
1132 } 1140 }
1133} 1141}
1134 1142
1135void RasterizerOpenGL::SyncDepthScale() { 1143void RasterizerOpenGL::SyncDepthScale() {
1136 float depth_scale = Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_range).ToFloat32(); 1144 float depth_scale =
1145 Pica::float24::FromRaw(Pica::g_state.regs.rasterizer.viewport_depth_range).ToFloat32();
1137 if (depth_scale != uniform_block_data.data.depth_scale) { 1146 if (depth_scale != uniform_block_data.data.depth_scale) {
1138 uniform_block_data.data.depth_scale = depth_scale; 1147 uniform_block_data.data.depth_scale = depth_scale;
1139 uniform_block_data.dirty = true; 1148 uniform_block_data.dirty = true;
@@ -1142,7 +1151,7 @@ void RasterizerOpenGL::SyncDepthScale() {
1142 1151
1143void RasterizerOpenGL::SyncDepthOffset() { 1152void RasterizerOpenGL::SyncDepthOffset() {
1144 float depth_offset = 1153 float depth_offset =
1145 Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_near_plane).ToFloat32(); 1154 Pica::float24::FromRaw(Pica::g_state.regs.rasterizer.viewport_depth_near_plane).ToFloat32();
1146 if (depth_offset != uniform_block_data.data.depth_offset) { 1155 if (depth_offset != uniform_block_data.data.depth_offset) {
1147 uniform_block_data.data.depth_offset = depth_offset; 1156 uniform_block_data.data.depth_offset = depth_offset;
1148 uniform_block_data.dirty = true; 1157 uniform_block_data.dirty = true;
@@ -1150,25 +1159,28 @@ void RasterizerOpenGL::SyncDepthOffset() {
1150} 1159}
1151 1160
1152void RasterizerOpenGL::SyncBlendEnabled() { 1161void RasterizerOpenGL::SyncBlendEnabled() {
1153 state.blend.enabled = (Pica::g_state.regs.output_merger.alphablend_enable == 1); 1162 state.blend.enabled = (Pica::g_state.regs.framebuffer.output_merger.alphablend_enable == 1);
1154} 1163}
1155 1164
1156void RasterizerOpenGL::SyncBlendFuncs() { 1165void RasterizerOpenGL::SyncBlendFuncs() {
1157 const auto& regs = Pica::g_state.regs; 1166 const auto& regs = Pica::g_state.regs;
1158 state.blend.rgb_equation = 1167 state.blend.rgb_equation =
1159 PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_rgb); 1168 PicaToGL::BlendEquation(regs.framebuffer.output_merger.alpha_blending.blend_equation_rgb);
1160 state.blend.a_equation = 1169 state.blend.a_equation =
1161 PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_a); 1170 PicaToGL::BlendEquation(regs.framebuffer.output_merger.alpha_blending.blend_equation_a);
1162 state.blend.src_rgb_func = 1171 state.blend.src_rgb_func =
1163 PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb); 1172 PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_source_rgb);
1164 state.blend.dst_rgb_func = 1173 state.blend.dst_rgb_func =
1165 PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb); 1174 PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_rgb);
1166 state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a); 1175 state.blend.src_a_func =
1167 state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a); 1176 PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_source_a);
1177 state.blend.dst_a_func =
1178 PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_a);
1168} 1179}
1169 1180
1170void RasterizerOpenGL::SyncBlendColor() { 1181void RasterizerOpenGL::SyncBlendColor() {
1171 auto blend_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.output_merger.blend_const.raw); 1182 auto blend_color =
1183 PicaToGL::ColorRGBA8(Pica::g_state.regs.framebuffer.output_merger.blend_const.raw);
1172 state.blend.color.red = blend_color[0]; 1184 state.blend.color.red = blend_color[0];
1173 state.blend.color.green = blend_color[1]; 1185 state.blend.color.green = blend_color[1];
1174 state.blend.color.blue = blend_color[2]; 1186 state.blend.color.blue = blend_color[2];
@@ -1178,8 +1190,8 @@ void RasterizerOpenGL::SyncBlendColor() {
1178void RasterizerOpenGL::SyncFogColor() { 1190void RasterizerOpenGL::SyncFogColor() {
1179 const auto& regs = Pica::g_state.regs; 1191 const auto& regs = Pica::g_state.regs;
1180 uniform_block_data.data.fog_color = { 1192 uniform_block_data.data.fog_color = {
1181 regs.fog_color.r.Value() / 255.0f, regs.fog_color.g.Value() / 255.0f, 1193 regs.texturing.fog_color.r.Value() / 255.0f, regs.texturing.fog_color.g.Value() / 255.0f,
1182 regs.fog_color.b.Value() / 255.0f, 1194 regs.texturing.fog_color.b.Value() / 255.0f,
1183 }; 1195 };
1184 uniform_block_data.dirty = true; 1196 uniform_block_data.dirty = true;
1185} 1197}
@@ -1200,70 +1212,78 @@ void RasterizerOpenGL::SyncFogLUT() {
1200 1212
1201void RasterizerOpenGL::SyncAlphaTest() { 1213void RasterizerOpenGL::SyncAlphaTest() {
1202 const auto& regs = Pica::g_state.regs; 1214 const auto& regs = Pica::g_state.regs;
1203 if (regs.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) { 1215 if (regs.framebuffer.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) {
1204 uniform_block_data.data.alphatest_ref = regs.output_merger.alpha_test.ref; 1216 uniform_block_data.data.alphatest_ref = regs.framebuffer.output_merger.alpha_test.ref;
1205 uniform_block_data.dirty = true; 1217 uniform_block_data.dirty = true;
1206 } 1218 }
1207} 1219}
1208 1220
1209void RasterizerOpenGL::SyncLogicOp() { 1221void RasterizerOpenGL::SyncLogicOp() {
1210 state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op); 1222 state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.framebuffer.output_merger.logic_op);
1211} 1223}
1212 1224
1213void RasterizerOpenGL::SyncColorWriteMask() { 1225void RasterizerOpenGL::SyncColorWriteMask() {
1214 const auto& regs = Pica::g_state.regs; 1226 const auto& regs = Pica::g_state.regs;
1215 1227
1216 auto IsColorWriteEnabled = [&](u32 value) { 1228 auto IsColorWriteEnabled = [&](u32 value) {
1217 return (regs.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE : GL_FALSE; 1229 return (regs.framebuffer.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE
1230 : GL_FALSE;
1218 }; 1231 };
1219 1232
1220 state.color_mask.red_enabled = IsColorWriteEnabled(regs.output_merger.red_enable); 1233 state.color_mask.red_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.red_enable);
1221 state.color_mask.green_enabled = IsColorWriteEnabled(regs.output_merger.green_enable); 1234 state.color_mask.green_enabled =
1222 state.color_mask.blue_enabled = IsColorWriteEnabled(regs.output_merger.blue_enable); 1235 IsColorWriteEnabled(regs.framebuffer.output_merger.green_enable);
1223 state.color_mask.alpha_enabled = IsColorWriteEnabled(regs.output_merger.alpha_enable); 1236 state.color_mask.blue_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.blue_enable);
1237 state.color_mask.alpha_enabled =
1238 IsColorWriteEnabled(regs.framebuffer.output_merger.alpha_enable);
1224} 1239}
1225 1240
1226void RasterizerOpenGL::SyncStencilWriteMask() { 1241void RasterizerOpenGL::SyncStencilWriteMask() {
1227 const auto& regs = Pica::g_state.regs; 1242 const auto& regs = Pica::g_state.regs;
1228 state.stencil.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0) 1243 state.stencil.write_mask =
1229 ? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask) 1244 (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0)
1230 : 0; 1245 ? static_cast<GLuint>(regs.framebuffer.output_merger.stencil_test.write_mask)
1246 : 0;
1231} 1247}
1232 1248
1233void RasterizerOpenGL::SyncDepthWriteMask() { 1249void RasterizerOpenGL::SyncDepthWriteMask() {
1234 const auto& regs = Pica::g_state.regs; 1250 const auto& regs = Pica::g_state.regs;
1235 state.depth.write_mask = 1251 state.depth.write_mask = (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 &&
1236 (regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable) 1252 regs.framebuffer.output_merger.depth_write_enable)
1237 ? GL_TRUE 1253 ? GL_TRUE
1238 : GL_FALSE; 1254 : GL_FALSE;
1239} 1255}
1240 1256
1241void RasterizerOpenGL::SyncStencilTest() { 1257void RasterizerOpenGL::SyncStencilTest() {
1242 const auto& regs = Pica::g_state.regs; 1258 const auto& regs = Pica::g_state.regs;
1243 state.stencil.test_enabled = regs.output_merger.stencil_test.enable && 1259 state.stencil.test_enabled =
1244 regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; 1260 regs.framebuffer.output_merger.stencil_test.enable &&
1245 state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func); 1261 regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8;
1246 state.stencil.test_ref = regs.output_merger.stencil_test.reference_value; 1262 state.stencil.test_func =
1247 state.stencil.test_mask = regs.output_merger.stencil_test.input_mask; 1263 PicaToGL::CompareFunc(regs.framebuffer.output_merger.stencil_test.func);
1264 state.stencil.test_ref = regs.framebuffer.output_merger.stencil_test.reference_value;
1265 state.stencil.test_mask = regs.framebuffer.output_merger.stencil_test.input_mask;
1248 state.stencil.action_stencil_fail = 1266 state.stencil.action_stencil_fail =
1249 PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail); 1267 PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_stencil_fail);
1250 state.stencil.action_depth_fail = 1268 state.stencil.action_depth_fail =
1251 PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail); 1269 PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_depth_fail);
1252 state.stencil.action_depth_pass = 1270 state.stencil.action_depth_pass =
1253 PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass); 1271 PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_depth_pass);
1254} 1272}
1255 1273
1256void RasterizerOpenGL::SyncDepthTest() { 1274void RasterizerOpenGL::SyncDepthTest() {
1257 const auto& regs = Pica::g_state.regs; 1275 const auto& regs = Pica::g_state.regs;
1258 state.depth.test_enabled = 1276 state.depth.test_enabled = regs.framebuffer.output_merger.depth_test_enable == 1 ||
1259 regs.output_merger.depth_test_enable == 1 || regs.output_merger.depth_write_enable == 1; 1277 regs.framebuffer.output_merger.depth_write_enable == 1;
1260 state.depth.test_func = regs.output_merger.depth_test_enable == 1 1278 state.depth.test_func =
1261 ? PicaToGL::CompareFunc(regs.output_merger.depth_test_func) 1279 regs.framebuffer.output_merger.depth_test_enable == 1
1262 : GL_ALWAYS; 1280 ? PicaToGL::CompareFunc(regs.framebuffer.output_merger.depth_test_func)
1281 : GL_ALWAYS;
1263} 1282}
1264 1283
1265void RasterizerOpenGL::SyncCombinerColor() { 1284void RasterizerOpenGL::SyncCombinerColor() {
1266 auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); 1285 auto combiner_color =
1286 PicaToGL::ColorRGBA8(Pica::g_state.regs.texturing.tev_combiner_buffer_color.raw);
1267 if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) { 1287 if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) {
1268 uniform_block_data.data.tev_combiner_buffer_color = combiner_color; 1288 uniform_block_data.data.tev_combiner_buffer_color = combiner_color;
1269 uniform_block_data.dirty = true; 1289 uniform_block_data.dirty = true;
@@ -1271,7 +1291,7 @@ void RasterizerOpenGL::SyncCombinerColor() {
1271} 1291}
1272 1292
1273void RasterizerOpenGL::SyncTevConstColor(int stage_index, 1293void RasterizerOpenGL::SyncTevConstColor(int stage_index,
1274 const Pica::Regs::TevStageConfig& tev_stage) { 1294 const Pica::TexturingRegs::TevStageConfig& tev_stage) {
1275 auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color); 1295 auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color);
1276 if (const_color != uniform_block_data.data.const_color[stage_index]) { 1296 if (const_color != uniform_block_data.data.const_color[stage_index]) {
1277 uniform_block_data.data.const_color[stage_index] = const_color; 1297 uniform_block_data.data.const_color[stage_index] = const_color;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index a1aa07074..bfee911b6 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -16,10 +16,10 @@
16#include "common/hash.h" 16#include "common/hash.h"
17#include "common/vector_math.h" 17#include "common/vector_math.h"
18#include "core/hw/gpu.h" 18#include "core/hw/gpu.h"
19#include "video_core/pica.h"
20#include "video_core/pica_state.h" 19#include "video_core/pica_state.h"
21#include "video_core/pica_types.h" 20#include "video_core/pica_types.h"
22#include "video_core/rasterizer_interface.h" 21#include "video_core/rasterizer_interface.h"
22#include "video_core/regs.h"
23#include "video_core/renderer_opengl/gl_rasterizer_cache.h" 23#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
24#include "video_core/renderer_opengl/gl_resource_manager.h" 24#include "video_core/renderer_opengl/gl_resource_manager.h"
25#include "video_core/renderer_opengl/gl_state.h" 25#include "video_core/renderer_opengl/gl_state.h"
@@ -52,20 +52,20 @@ union PicaShaderConfig {
52 52
53 const auto& regs = Pica::g_state.regs; 53 const auto& regs = Pica::g_state.regs;
54 54
55 state.scissor_test_mode = regs.scissor_test.mode; 55 state.scissor_test_mode = regs.rasterizer.scissor_test.mode;
56 56
57 state.depthmap_enable = regs.depthmap_enable; 57 state.depthmap_enable = regs.rasterizer.depthmap_enable;
58 58
59 state.alpha_test_func = regs.output_merger.alpha_test.enable 59 state.alpha_test_func = regs.framebuffer.output_merger.alpha_test.enable
60 ? regs.output_merger.alpha_test.func.Value() 60 ? regs.framebuffer.output_merger.alpha_test.func.Value()
61 : Pica::Regs::CompareFunc::Always; 61 : Pica::FramebufferRegs::CompareFunc::Always;
62 62
63 state.texture0_type = regs.texture0.type; 63 state.texture0_type = regs.texturing.texture0.type;
64 64
65 // Copy relevant tev stages fields. 65 // Copy relevant tev stages fields.
66 // We don't sync const_color here because of the high variance, it is a 66 // We don't sync const_color here because of the high variance, it is a
67 // shader uniform instead. 67 // shader uniform instead.
68 const auto& tev_stages = regs.GetTevStages(); 68 const auto& tev_stages = regs.texturing.GetTevStages();
69 DEBUG_ASSERT(state.tev_stages.size() == tev_stages.size()); 69 DEBUG_ASSERT(state.tev_stages.size() == tev_stages.size());
70 for (size_t i = 0; i < tev_stages.size(); i++) { 70 for (size_t i = 0; i < tev_stages.size(); i++) {
71 const auto& tev_stage = tev_stages[i]; 71 const auto& tev_stage = tev_stages[i];
@@ -75,11 +75,12 @@ union PicaShaderConfig {
75 state.tev_stages[i].scales_raw = tev_stage.scales_raw; 75 state.tev_stages[i].scales_raw = tev_stage.scales_raw;
76 } 76 }
77 77
78 state.fog_mode = regs.fog_mode; 78 state.fog_mode = regs.texturing.fog_mode;
79 state.fog_flip = regs.fog_flip != 0; 79 state.fog_flip = regs.texturing.fog_flip != 0;
80 80
81 state.combiner_buffer_input = regs.tev_combiner_buffer_input.update_mask_rgb.Value() | 81 state.combiner_buffer_input =
82 regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; 82 regs.texturing.tev_combiner_buffer_input.update_mask_rgb.Value() |
83 regs.texturing.tev_combiner_buffer_input.update_mask_a.Value() << 4;
83 84
84 // Fragment lighting 85 // Fragment lighting
85 86
@@ -159,8 +160,8 @@ union PicaShaderConfig {
159 u32 modifiers_raw; 160 u32 modifiers_raw;
160 u32 ops_raw; 161 u32 ops_raw;
161 u32 scales_raw; 162 u32 scales_raw;
162 explicit operator Pica::Regs::TevStageConfig() const noexcept { 163 explicit operator Pica::TexturingRegs::TevStageConfig() const noexcept {
163 Pica::Regs::TevStageConfig stage; 164 Pica::TexturingRegs::TevStageConfig stage;
164 stage.sources_raw = sources_raw; 165 stage.sources_raw = sources_raw;
165 stage.modifiers_raw = modifiers_raw; 166 stage.modifiers_raw = modifiers_raw;
166 stage.ops_raw = ops_raw; 167 stage.ops_raw = ops_raw;
@@ -171,14 +172,14 @@ union PicaShaderConfig {
171 }; 172 };
172 173
173 struct State { 174 struct State {
174 Pica::Regs::CompareFunc alpha_test_func; 175 Pica::FramebufferRegs::CompareFunc alpha_test_func;
175 Pica::Regs::ScissorMode scissor_test_mode; 176 Pica::RasterizerRegs::ScissorMode scissor_test_mode;
176 Pica::Regs::TextureConfig::TextureType texture0_type; 177 Pica::TexturingRegs::TextureConfig::TextureType texture0_type;
177 std::array<TevStageConfigRaw, 6> tev_stages; 178 std::array<TevStageConfigRaw, 6> tev_stages;
178 u8 combiner_buffer_input; 179 u8 combiner_buffer_input;
179 180
180 Pica::Regs::DepthBuffering depthmap_enable; 181 Pica::RasterizerRegs::DepthBuffering depthmap_enable;
181 Pica::Regs::FogMode fog_mode; 182 Pica::TexturingRegs::FogMode fog_mode;
182 bool fog_flip; 183 bool fog_flip;
183 184
184 struct { 185 struct {
@@ -191,18 +192,18 @@ union PicaShaderConfig {
191 192
192 bool enable; 193 bool enable;
193 unsigned src_num; 194 unsigned src_num;
194 Pica::Regs::LightingBumpMode bump_mode; 195 Pica::LightingRegs::LightingBumpMode bump_mode;
195 unsigned bump_selector; 196 unsigned bump_selector;
196 bool bump_renorm; 197 bool bump_renorm;
197 bool clamp_highlights; 198 bool clamp_highlights;
198 199
199 Pica::Regs::LightingConfig config; 200 Pica::LightingRegs::LightingConfig config;
200 Pica::Regs::LightingFresnelSelector fresnel_selector; 201 Pica::LightingRegs::LightingFresnelSelector fresnel_selector;
201 202
202 struct { 203 struct {
203 bool enable; 204 bool enable;
204 bool abs_input; 205 bool abs_input;
205 Pica::Regs::LightingLutInput type; 206 Pica::LightingRegs::LightingLutInput type;
206 float scale; 207 float scale;
207 } lut_d0, lut_d1, lut_fr, lut_rr, lut_rg, lut_rb; 208 } lut_d0, lut_d1, lut_fr, lut_rr, lut_rg, lut_rb;
208 } lighting; 209 } lighting;
@@ -251,7 +252,7 @@ public:
251 252
252private: 253private:
253 struct SamplerInfo { 254 struct SamplerInfo {
254 using TextureConfig = Pica::Regs::TextureConfig; 255 using TextureConfig = Pica::TexturingRegs::TextureConfig;
255 256
256 OGLSampler sampler; 257 OGLSampler sampler;
257 258
@@ -398,7 +399,7 @@ private:
398 void SyncCombinerColor(); 399 void SyncCombinerColor();
399 400
400 /// Syncs the TEV constant color to match the PICA register 401 /// Syncs the TEV constant color to match the PICA register
401 void SyncTevConstColor(int tev_index, const Pica::Regs::TevStageConfig& tev_stage); 402 void SyncTevConstColor(int tev_index, const Pica::TexturingRegs::TevStageConfig& tev_stage);
402 403
403 /// Syncs the lighting global ambient color to match the PICA register 404 /// Syncs the lighting global ambient color to match the PICA register
404 void SyncGlobalAmbient(); 405 void SyncGlobalAmbient();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 60380257a..0818a87b3 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -342,7 +342,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
342 Pica::Texture::TextureInfo tex_info; 342 Pica::Texture::TextureInfo tex_info;
343 tex_info.width = params.width; 343 tex_info.width = params.width;
344 tex_info.height = params.height; 344 tex_info.height = params.height;
345 tex_info.format = (Pica::Regs::TextureFormat)params.pixel_format; 345 tex_info.format = (Pica::TexturingRegs::TextureFormat)params.pixel_format;
346 tex_info.SetDefaultStride(); 346 tex_info.SetDefaultStride();
347 tex_info.physical_address = params.addr; 347 tex_info.physical_address = params.addr;
348 348
@@ -510,7 +510,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params
510} 510}
511 511
512CachedSurface* RasterizerCacheOpenGL::GetTextureSurface( 512CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(
513 const Pica::Regs::FullTextureConfig& config) { 513 const Pica::TexturingRegs::FullTextureConfig& config) {
514 514
515 Pica::Texture::TextureInfo info = 515 Pica::Texture::TextureInfo info =
516 Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format); 516 Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format);
@@ -525,7 +525,9 @@ CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(
525} 525}
526 526
527std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> 527std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>>
528RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config) { 528RasterizerCacheOpenGL::GetFramebufferSurfaces(
529 const Pica::FramebufferRegs::FramebufferConfig& config) {
530
529 const auto& regs = Pica::g_state.regs; 531 const auto& regs = Pica::g_state.regs;
530 532
531 // Make sur that framebuffers don't overlap if both color and depth are being used 533 // Make sur that framebuffers don't overlap if both color and depth are being used
@@ -537,11 +539,12 @@ RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfi
537 config.GetColorBufferPhysicalAddress(), 539 config.GetColorBufferPhysicalAddress(),
538 fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())), 540 fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())),
539 config.GetDepthBufferPhysicalAddress(), 541 config.GetDepthBufferPhysicalAddress(),
540 fb_area * Pica::Regs::BytesPerDepthPixel(config.depth_format)); 542 fb_area * Pica::FramebufferRegs::BytesPerDepthPixel(config.depth_format));
541 bool using_color_fb = config.GetColorBufferPhysicalAddress() != 0; 543 bool using_color_fb = config.GetColorBufferPhysicalAddress() != 0;
542 bool using_depth_fb = config.GetDepthBufferPhysicalAddress() != 0 && 544 bool using_depth_fb =
543 (regs.output_merger.depth_test_enable || 545 config.GetDepthBufferPhysicalAddress() != 0 &&
544 regs.output_merger.depth_write_enable || !framebuffers_overlap); 546 (regs.framebuffer.output_merger.depth_test_enable ||
547 regs.framebuffer.output_merger.depth_write_enable || !framebuffers_overlap);
545 548
546 if (framebuffers_overlap && using_color_fb && using_depth_fb) { 549 if (framebuffers_overlap && using_color_fb && using_depth_fb) {
547 LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; " 550 LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; "
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index f57fdb3cc..4072ed49e 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -21,7 +21,7 @@
21#include "common/common_funcs.h" 21#include "common/common_funcs.h"
22#include "common/common_types.h" 22#include "common/common_types.h"
23#include "core/hw/gpu.h" 23#include "core/hw/gpu.h"
24#include "video_core/pica.h" 24#include "video_core/regs.h"
25#include "video_core/renderer_opengl/gl_resource_manager.h" 25#include "video_core/renderer_opengl/gl_resource_manager.h"
26 26
27namespace MathUtil { 27namespace MathUtil {
@@ -96,15 +96,15 @@ struct CachedSurface {
96 return bpp_table[(unsigned int)format]; 96 return bpp_table[(unsigned int)format];
97 } 97 }
98 98
99 static PixelFormat PixelFormatFromTextureFormat(Pica::Regs::TextureFormat format) { 99 static PixelFormat PixelFormatFromTextureFormat(Pica::TexturingRegs::TextureFormat format) {
100 return ((unsigned int)format < 14) ? (PixelFormat)format : PixelFormat::Invalid; 100 return ((unsigned int)format < 14) ? (PixelFormat)format : PixelFormat::Invalid;
101 } 101 }
102 102
103 static PixelFormat PixelFormatFromColorFormat(Pica::Regs::ColorFormat format) { 103 static PixelFormat PixelFormatFromColorFormat(Pica::FramebufferRegs::ColorFormat format) {
104 return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid; 104 return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid;
105 } 105 }
106 106
107 static PixelFormat PixelFormatFromDepthFormat(Pica::Regs::DepthFormat format) { 107 static PixelFormat PixelFormatFromDepthFormat(Pica::FramebufferRegs::DepthFormat format) {
108 return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14) 108 return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14)
109 : PixelFormat::Invalid; 109 : PixelFormat::Invalid;
110 } 110 }
@@ -212,12 +212,12 @@ public:
212 bool load_if_create, MathUtil::Rectangle<int>& out_rect); 212 bool load_if_create, MathUtil::Rectangle<int>& out_rect);
213 213
214 /// Gets a surface based on the texture configuration 214 /// Gets a surface based on the texture configuration
215 CachedSurface* GetTextureSurface(const Pica::Regs::FullTextureConfig& config); 215 CachedSurface* GetTextureSurface(const Pica::TexturingRegs::FullTextureConfig& config);
216 216
217 /// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer 217 /// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer
218 /// configuration 218 /// configuration
219 std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> GetFramebufferSurfaces( 219 std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> GetFramebufferSurfaces(
220 const Pica::Regs::FramebufferConfig& config); 220 const Pica::FramebufferRegs::FramebufferConfig& config);
221 221
222 /// Attempt to get a surface that exactly matches the fill region and format 222 /// Attempt to get a surface that exactly matches the fill region and format
223 CachedSurface* TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config); 223 CachedSurface* TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config);
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 4c4f98ac9..3ea25f302 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -7,13 +7,15 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/bit_field.h" 8#include "common/bit_field.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "video_core/pica.h" 10#include "video_core/regs.h"
11#include "video_core/renderer_opengl/gl_rasterizer.h" 11#include "video_core/renderer_opengl/gl_rasterizer.h"
12#include "video_core/renderer_opengl/gl_shader_gen.h" 12#include "video_core/renderer_opengl/gl_shader_gen.h"
13#include "video_core/renderer_opengl/gl_shader_util.h" 13#include "video_core/renderer_opengl/gl_shader_util.h"
14 14
15using Pica::Regs; 15using Pica::Regs;
16using TevStageConfig = Regs::TevStageConfig; 16using Pica::RasterizerRegs;
17using Pica::LightingRegs;
18using TevStageConfig = Pica::TexturingRegs::TevStageConfig;
17 19
18namespace GLShader { 20namespace GLShader {
19 21
@@ -46,10 +48,10 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config,
46 case Source::Texture0: 48 case Source::Texture0:
47 // Only unit 0 respects the texturing type (according to 3DBrew) 49 // Only unit 0 respects the texturing type (according to 3DBrew)
48 switch (state.texture0_type) { 50 switch (state.texture0_type) {
49 case Pica::Regs::TextureConfig::Texture2D: 51 case Pica::TexturingRegs::TextureConfig::Texture2D:
50 out += "texture(tex[0], texcoord[0])"; 52 out += "texture(tex[0], texcoord[0])";
51 break; 53 break;
52 case Pica::Regs::TextureConfig::Projection2D: 54 case Pica::TexturingRegs::TextureConfig::Projection2D:
53 out += "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))"; 55 out += "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))";
54 break; 56 break;
55 default: 57 default:
@@ -276,8 +278,8 @@ static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation oper
276} 278}
277 279
278/// Writes the if-statement condition used to evaluate alpha testing 280/// Writes the if-statement condition used to evaluate alpha testing
279static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) { 281static void AppendAlphaTestCondition(std::string& out, Pica::FramebufferRegs::CompareFunc func) {
280 using CompareFunc = Regs::CompareFunc; 282 using CompareFunc = Pica::FramebufferRegs::CompareFunc;
281 switch (func) { 283 switch (func) {
282 case CompareFunc::Never: 284 case CompareFunc::Never:
283 out += "true"; 285 out += "true";
@@ -307,7 +309,7 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) {
307/// Writes the code to emulate the specified TEV stage 309/// Writes the code to emulate the specified TEV stage
308static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) { 310static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) {
309 const auto stage = 311 const auto stage =
310 static_cast<const Pica::Regs::TevStageConfig>(config.state.tev_stages[index]); 312 static_cast<const Pica::TexturingRegs::TevStageConfig>(config.state.tev_stages[index]);
311 if (!IsPassThroughTevStage(stage)) { 313 if (!IsPassThroughTevStage(stage)) {
312 std::string index_name = std::to_string(index); 314 std::string index_name = std::to_string(index);
313 315
@@ -364,7 +366,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
364 "vec3 refl_value = vec3(0.0);\n"; 366 "vec3 refl_value = vec3(0.0);\n";
365 367
366 // Compute fragment normals 368 // Compute fragment normals
367 if (lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) { 369 if (lighting.bump_mode == LightingRegs::LightingBumpMode::NormalMap) {
368 // Bump mapping is enabled using a normal map, read perturbation vector from the selected 370 // Bump mapping is enabled using a normal map, read perturbation vector from the selected
369 // texture 371 // texture
370 std::string bump_selector = std::to_string(lighting.bump_selector); 372 std::string bump_selector = std::to_string(lighting.bump_selector);
@@ -378,7 +380,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
378 "(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))"; 380 "(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))";
379 out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n"; 381 out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n";
380 } 382 }
381 } else if (lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) { 383 } else if (lighting.bump_mode == LightingRegs::LightingBumpMode::TangentMap) {
382 // Bump mapping is enabled using a tangent map 384 // Bump mapping is enabled using a tangent map
383 LOG_CRITICAL(HW_GPU, "unimplemented bump mapping mode (tangent mapping)"); 385 LOG_CRITICAL(HW_GPU, "unimplemented bump mapping mode (tangent mapping)");
384 UNIMPLEMENTED(); 386 UNIMPLEMENTED();
@@ -392,23 +394,24 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
392 out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n"; 394 out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n";
393 395
394 // Gets the index into the specified lookup table for specular lighting 396 // Gets the index into the specified lookup table for specular lighting
395 auto GetLutIndex = [&lighting](unsigned light_num, Regs::LightingLutInput input, bool abs) { 397 auto GetLutIndex = [&lighting](unsigned light_num, LightingRegs::LightingLutInput input,
398 bool abs) {
396 const std::string half_angle = "normalize(normalize(view) + light_vector)"; 399 const std::string half_angle = "normalize(normalize(view) + light_vector)";
397 std::string index; 400 std::string index;
398 switch (input) { 401 switch (input) {
399 case Regs::LightingLutInput::NH: 402 case LightingRegs::LightingLutInput::NH:
400 index = "dot(normal, " + half_angle + ")"; 403 index = "dot(normal, " + half_angle + ")";
401 break; 404 break;
402 405
403 case Regs::LightingLutInput::VH: 406 case LightingRegs::LightingLutInput::VH:
404 index = std::string("dot(normalize(view), " + half_angle + ")"); 407 index = std::string("dot(normalize(view), " + half_angle + ")");
405 break; 408 break;
406 409
407 case Regs::LightingLutInput::NV: 410 case LightingRegs::LightingLutInput::NV:
408 index = std::string("dot(normal, normalize(view))"); 411 index = std::string("dot(normal, normalize(view))");
409 break; 412 break;
410 413
411 case Regs::LightingLutInput::LN: 414 case LightingRegs::LightingLutInput::LN:
412 index = std::string("dot(light_vector, normal)"); 415 index = std::string("dot(light_vector, normal)");
413 break; 416 break;
414 417
@@ -432,7 +435,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
432 }; 435 };
433 436
434 // Gets the lighting lookup table value given the specified sampler and index 437 // Gets the lighting lookup table value given the specified sampler and index
435 auto GetLutValue = [](Regs::LightingSampler sampler, std::string lut_index) { 438 auto GetLutValue = [](LightingRegs::LightingSampler sampler, std::string lut_index) {
436 return std::string("texture(lut[" + std::to_string((unsigned)sampler / 4) + "], " + 439 return std::string("texture(lut[" + std::to_string((unsigned)sampler / 4) + "], " +
437 lut_index + ")[" + std::to_string((unsigned)sampler & 3) + "]"); 440 lut_index + ")[" + std::to_string((unsigned)sampler & 3) + "]");
438 }; 441 };
@@ -461,8 +464,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
461 light_src + ".position) + " + light_src + ".dist_atten_bias)"; 464 light_src + ".position) + " + light_src + ".dist_atten_bias)";
462 index = "(OFFSET_256 + SCALE_256 * clamp(" + index + ", 0.0, 1.0))"; 465 index = "(OFFSET_256 + SCALE_256 * clamp(" + index + ", 0.0, 1.0))";
463 const unsigned lut_num = 466 const unsigned lut_num =
464 ((unsigned)Regs::LightingSampler::DistanceAttenuation + light_config.num); 467 ((unsigned)LightingRegs::LightingSampler::DistanceAttenuation + light_config.num);
465 dist_atten = GetLutValue((Regs::LightingSampler)lut_num, index); 468 dist_atten = GetLutValue((LightingRegs::LightingSampler)lut_num, index);
466 } 469 }
467 470
468 // If enabled, clamp specular component if lighting result is negative 471 // If enabled, clamp specular component if lighting result is negative
@@ -472,24 +475,24 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
472 // Specular 0 component 475 // Specular 0 component
473 std::string d0_lut_value = "1.0"; 476 std::string d0_lut_value = "1.0";
474 if (lighting.lut_d0.enable && 477 if (lighting.lut_d0.enable &&
475 Pica::Regs::IsLightingSamplerSupported(lighting.config, 478 LightingRegs::IsLightingSamplerSupported(
476 Pica::Regs::LightingSampler::Distribution0)) { 479 lighting.config, LightingRegs::LightingSampler::Distribution0)) {
477 // Lookup specular "distribution 0" LUT value 480 // Lookup specular "distribution 0" LUT value
478 std::string index = 481 std::string index =
479 GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input); 482 GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input);
480 d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " + 483 d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " +
481 GetLutValue(Regs::LightingSampler::Distribution0, index) + ")"; 484 GetLutValue(LightingRegs::LightingSampler::Distribution0, index) + ")";
482 } 485 }
483 std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)"; 486 std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)";
484 487
485 // If enabled, lookup ReflectRed value, otherwise, 1.0 is used 488 // If enabled, lookup ReflectRed value, otherwise, 1.0 is used
486 if (lighting.lut_rr.enable && 489 if (lighting.lut_rr.enable &&
487 Pica::Regs::IsLightingSamplerSupported(lighting.config, 490 LightingRegs::IsLightingSamplerSupported(lighting.config,
488 Pica::Regs::LightingSampler::ReflectRed)) { 491 LightingRegs::LightingSampler::ReflectRed)) {
489 std::string index = 492 std::string index =
490 GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input); 493 GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input);
491 std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " + 494 std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " +
492 GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")"; 495 GetLutValue(LightingRegs::LightingSampler::ReflectRed, index) + ")";
493 out += "refl_value.r = " + value + ";\n"; 496 out += "refl_value.r = " + value + ";\n";
494 } else { 497 } else {
495 out += "refl_value.r = 1.0;\n"; 498 out += "refl_value.r = 1.0;\n";
@@ -497,12 +500,13 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
497 500
498 // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used 501 // If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used
499 if (lighting.lut_rg.enable && 502 if (lighting.lut_rg.enable &&
500 Pica::Regs::IsLightingSamplerSupported(lighting.config, 503 LightingRegs::IsLightingSamplerSupported(lighting.config,
501 Pica::Regs::LightingSampler::ReflectGreen)) { 504 LightingRegs::LightingSampler::ReflectGreen)) {
502 std::string index = 505 std::string index =
503 GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input); 506 GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input);
504 std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " + 507 std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " +
505 GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")"; 508 GetLutValue(LightingRegs::LightingSampler::ReflectGreen, index) +
509 ")";
506 out += "refl_value.g = " + value + ";\n"; 510 out += "refl_value.g = " + value + ";\n";
507 } else { 511 } else {
508 out += "refl_value.g = refl_value.r;\n"; 512 out += "refl_value.g = refl_value.r;\n";
@@ -510,12 +514,13 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
510 514
511 // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used 515 // If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used
512 if (lighting.lut_rb.enable && 516 if (lighting.lut_rb.enable &&
513 Pica::Regs::IsLightingSamplerSupported(lighting.config, 517 LightingRegs::IsLightingSamplerSupported(lighting.config,
514 Pica::Regs::LightingSampler::ReflectBlue)) { 518 LightingRegs::LightingSampler::ReflectBlue)) {
515 std::string index = 519 std::string index =
516 GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input); 520 GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input);
517 std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " + 521 std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " +
518 GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")"; 522 GetLutValue(LightingRegs::LightingSampler::ReflectBlue, index) +
523 ")";
519 out += "refl_value.b = " + value + ";\n"; 524 out += "refl_value.b = " + value + ";\n";
520 } else { 525 } else {
521 out += "refl_value.b = refl_value.r;\n"; 526 out += "refl_value.b = refl_value.r;\n";
@@ -524,35 +529,39 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
524 // Specular 1 component 529 // Specular 1 component
525 std::string d1_lut_value = "1.0"; 530 std::string d1_lut_value = "1.0";
526 if (lighting.lut_d1.enable && 531 if (lighting.lut_d1.enable &&
527 Pica::Regs::IsLightingSamplerSupported(lighting.config, 532 LightingRegs::IsLightingSamplerSupported(
528 Pica::Regs::LightingSampler::Distribution1)) { 533 lighting.config, LightingRegs::LightingSampler::Distribution1)) {
529 // Lookup specular "distribution 1" LUT value 534 // Lookup specular "distribution 1" LUT value
530 std::string index = 535 std::string index =
531 GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input); 536 GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input);
532 d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " + 537 d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " +
533 GetLutValue(Regs::LightingSampler::Distribution1, index) + ")"; 538 GetLutValue(LightingRegs::LightingSampler::Distribution1, index) + ")";
534 } 539 }
535 std::string specular_1 = 540 std::string specular_1 =
536 "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)"; 541 "(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)";
537 542
538 // Fresnel 543 // Fresnel
539 if (lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported( 544 if (lighting.lut_fr.enable &&
540 lighting.config, Pica::Regs::LightingSampler::Fresnel)) { 545 LightingRegs::IsLightingSamplerSupported(lighting.config,
546 LightingRegs::LightingSampler::Fresnel)) {
541 // Lookup fresnel LUT value 547 // Lookup fresnel LUT value
542 std::string index = 548 std::string index =
543 GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input); 549 GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input);
544 std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " + 550 std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " +
545 GetLutValue(Regs::LightingSampler::Fresnel, index) + ")"; 551 GetLutValue(LightingRegs::LightingSampler::Fresnel, index) + ")";
546 552
547 // Enabled for difffuse lighting alpha component 553 // Enabled for difffuse lighting alpha component
548 if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha || 554 if (lighting.fresnel_selector == LightingRegs::LightingFresnelSelector::PrimaryAlpha ||
549 lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both) 555 lighting.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) {
550 out += "diffuse_sum.a *= " + value + ";\n"; 556 out += "diffuse_sum.a *= " + value + ";\n";
557 }
551 558
552 // Enabled for the specular lighting alpha component 559 // Enabled for the specular lighting alpha component
553 if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::SecondaryAlpha || 560 if (lighting.fresnel_selector ==
554 lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both) 561 LightingRegs::LightingFresnelSelector::SecondaryAlpha ||
562 lighting.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) {
555 out += "specular_sum.a *= " + value + ";\n"; 563 out += "specular_sum.a *= " + value + ";\n";
564 }
556 } 565 }
557 566
558 // Compute primary fragment color (diffuse lighting) function 567 // Compute primary fragment color (diffuse lighting) function
@@ -633,16 +642,16 @@ vec4 secondary_fragment_color = vec4(0.0);
633)"; 642)";
634 643
635 // Do not do any sort of processing if it's obvious we're not going to pass the alpha test 644 // Do not do any sort of processing if it's obvious we're not going to pass the alpha test
636 if (state.alpha_test_func == Regs::CompareFunc::Never) { 645 if (state.alpha_test_func == Pica::FramebufferRegs::CompareFunc::Never) {
637 out += "discard; }"; 646 out += "discard; }";
638 return out; 647 return out;
639 } 648 }
640 649
641 // Append the scissor test 650 // Append the scissor test
642 if (state.scissor_test_mode != Regs::ScissorMode::Disabled) { 651 if (state.scissor_test_mode != RasterizerRegs::ScissorMode::Disabled) {
643 out += "if ("; 652 out += "if (";
644 // Negate the condition if we have to keep only the pixels outside the scissor box 653 // Negate the condition if we have to keep only the pixels outside the scissor box
645 if (state.scissor_test_mode == Regs::ScissorMode::Include) 654 if (state.scissor_test_mode == RasterizerRegs::ScissorMode::Include)
646 out += "!"; 655 out += "!";
647 out += "(gl_FragCoord.x >= scissor_x1 && " 656 out += "(gl_FragCoord.x >= scissor_x1 && "
648 "gl_FragCoord.y >= scissor_y1 && " 657 "gl_FragCoord.y >= scissor_y1 && "
@@ -652,7 +661,7 @@ vec4 secondary_fragment_color = vec4(0.0);
652 661
653 out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n"; 662 out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n";
654 out += "float depth = z_over_w * depth_scale + depth_offset;\n"; 663 out += "float depth = z_over_w * depth_scale + depth_offset;\n";
655 if (state.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) { 664 if (state.depthmap_enable == Pica::RasterizerRegs::DepthBuffering::WBuffering) {
656 out += "depth /= gl_FragCoord.w;\n"; 665 out += "depth /= gl_FragCoord.w;\n";
657 } 666 }
658 667
@@ -666,14 +675,14 @@ vec4 secondary_fragment_color = vec4(0.0);
666 for (size_t index = 0; index < state.tev_stages.size(); ++index) 675 for (size_t index = 0; index < state.tev_stages.size(); ++index)
667 WriteTevStage(out, config, (unsigned)index); 676 WriteTevStage(out, config, (unsigned)index);
668 677
669 if (state.alpha_test_func != Regs::CompareFunc::Always) { 678 if (state.alpha_test_func != Pica::FramebufferRegs::CompareFunc::Always) {
670 out += "if ("; 679 out += "if (";
671 AppendAlphaTestCondition(out, state.alpha_test_func); 680 AppendAlphaTestCondition(out, state.alpha_test_func);
672 out += ") discard;\n"; 681 out += ") discard;\n";
673 } 682 }
674 683
675 // Append fog combiner 684 // Append fog combiner
676 if (state.fog_mode == Regs::FogMode::Fog) { 685 if (state.fog_mode == Pica::TexturingRegs::FogMode::Fog) {
677 // Get index into fog LUT 686 // Get index into fog LUT
678 if (state.fog_flip) { 687 if (state.fog_flip) {
679 out += "float fog_index = (1.0 - depth) * 128.0;\n"; 688 out += "float fog_index = (1.0 - depth) * 128.0;\n";
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index cc49867c8..4b98dafc4 100644
--- a/src/video_core/renderer_opengl/pica_to_gl.h
+++ b/src/video_core/renderer_opengl/pica_to_gl.h
@@ -12,7 +12,7 @@
12#include "common/common_funcs.h" 12#include "common/common_funcs.h"
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/logging/log.h" 14#include "common/logging/log.h"
15#include "video_core/pica.h" 15#include "video_core/regs.h"
16 16
17using GLvec2 = std::array<GLfloat, 2>; 17using GLvec2 = std::array<GLfloat, 2>;
18using GLvec3 = std::array<GLfloat, 3>; 18using GLvec3 = std::array<GLfloat, 3>;
@@ -20,7 +20,7 @@ using GLvec4 = std::array<GLfloat, 4>;
20 20
21namespace PicaToGL { 21namespace PicaToGL {
22 22
23inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) { 23inline GLenum TextureFilterMode(Pica::TexturingRegs::TextureConfig::TextureFilter mode) {
24 static const GLenum filter_mode_table[] = { 24 static const GLenum filter_mode_table[] = {
25 GL_NEAREST, // TextureFilter::Nearest 25 GL_NEAREST, // TextureFilter::Nearest
26 GL_LINEAR, // TextureFilter::Linear 26 GL_LINEAR, // TextureFilter::Linear
@@ -47,7 +47,7 @@ inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) {
47 return gl_mode; 47 return gl_mode;
48} 48}
49 49
50inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { 50inline GLenum WrapMode(Pica::TexturingRegs::TextureConfig::WrapMode mode) {
51 static const GLenum wrap_mode_table[] = { 51 static const GLenum wrap_mode_table[] = {
52 GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge 52 GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge
53 GL_CLAMP_TO_BORDER, // WrapMode::ClampToBorder 53 GL_CLAMP_TO_BORDER, // WrapMode::ClampToBorder
@@ -76,7 +76,7 @@ inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) {
76 return gl_mode; 76 return gl_mode;
77} 77}
78 78
79inline GLenum BlendEquation(Pica::Regs::BlendEquation equation) { 79inline GLenum BlendEquation(Pica::FramebufferRegs::BlendEquation equation) {
80 static const GLenum blend_equation_table[] = { 80 static const GLenum blend_equation_table[] = {
81 GL_FUNC_ADD, // BlendEquation::Add 81 GL_FUNC_ADD, // BlendEquation::Add
82 GL_FUNC_SUBTRACT, // BlendEquation::Subtract 82 GL_FUNC_SUBTRACT, // BlendEquation::Subtract
@@ -96,7 +96,7 @@ inline GLenum BlendEquation(Pica::Regs::BlendEquation equation) {
96 return blend_equation_table[(unsigned)equation]; 96 return blend_equation_table[(unsigned)equation];
97} 97}
98 98
99inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) { 99inline GLenum BlendFunc(Pica::FramebufferRegs::BlendFactor factor) {
100 static const GLenum blend_func_table[] = { 100 static const GLenum blend_func_table[] = {
101 GL_ZERO, // BlendFactor::Zero 101 GL_ZERO, // BlendFactor::Zero
102 GL_ONE, // BlendFactor::One 102 GL_ONE, // BlendFactor::One
@@ -126,7 +126,7 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) {
126 return blend_func_table[(unsigned)factor]; 126 return blend_func_table[(unsigned)factor];
127} 127}
128 128
129inline GLenum LogicOp(Pica::Regs::LogicOp op) { 129inline GLenum LogicOp(Pica::FramebufferRegs::LogicOp op) {
130 static const GLenum logic_op_table[] = { 130 static const GLenum logic_op_table[] = {
131 GL_CLEAR, // Clear 131 GL_CLEAR, // Clear
132 GL_AND, // And 132 GL_AND, // And
@@ -157,7 +157,7 @@ inline GLenum LogicOp(Pica::Regs::LogicOp op) {
157 return logic_op_table[(unsigned)op]; 157 return logic_op_table[(unsigned)op];
158} 158}
159 159
160inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { 160inline GLenum CompareFunc(Pica::FramebufferRegs::CompareFunc func) {
161 static const GLenum compare_func_table[] = { 161 static const GLenum compare_func_table[] = {
162 GL_NEVER, // CompareFunc::Never 162 GL_NEVER, // CompareFunc::Never
163 GL_ALWAYS, // CompareFunc::Always 163 GL_ALWAYS, // CompareFunc::Always
@@ -180,7 +180,7 @@ inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
180 return compare_func_table[(unsigned)func]; 180 return compare_func_table[(unsigned)func];
181} 181}
182 182
183inline GLenum StencilOp(Pica::Regs::StencilAction action) { 183inline GLenum StencilOp(Pica::FramebufferRegs::StencilAction action) {
184 static const GLenum stencil_op_table[] = { 184 static const GLenum stencil_op_table[] = {
185 GL_KEEP, // StencilAction::Keep 185 GL_KEEP, // StencilAction::Keep
186 GL_ZERO, // StencilAction::Zero 186 GL_ZERO, // StencilAction::Zero
@@ -210,7 +210,7 @@ inline GLvec4 ColorRGBA8(const u32 color) {
210 }}; 210 }};
211} 211}
212 212
213inline std::array<GLfloat, 3> LightColor(const Pica::Regs::LightColor& color) { 213inline std::array<GLfloat, 3> LightColor(const Pica::LightingRegs::LightColor& color) {
214 return {{ 214 return {{
215 color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, 215 color.r / 255.0f, color.g / 255.0f, color.b / 255.0f,
216 }}; 216 }};
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp
index f5f7ea61d..c860375a1 100644
--- a/src/video_core/shader/shader.cpp
+++ b/src/video_core/shader/shader.cpp
@@ -7,8 +7,8 @@
7#include "common/bit_set.h" 7#include "common/bit_set.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "common/microprofile.h" 9#include "common/microprofile.h"
10#include "video_core/pica.h"
11#include "video_core/pica_state.h" 10#include "video_core/pica_state.h"
11#include "video_core/regs.h"
12#include "video_core/shader/shader.h" 12#include "video_core/shader/shader.h"
13#include "video_core/shader/shader_interpreter.h" 13#include "video_core/shader/shader_interpreter.h"
14#ifdef ARCHITECTURE_x86_64 14#ifdef ARCHITECTURE_x86_64
@@ -20,7 +20,7 @@ namespace Pica {
20 20
21namespace Shader { 21namespace Shader {
22 22
23OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer& input) { 23OutputVertex OutputVertex::FromAttributeBuffer(const RasterizerRegs& regs, AttributeBuffer& input) {
24 // Setup output data 24 // Setup output data
25 union { 25 union {
26 OutputVertex ret{}; 26 OutputVertex ret{};
@@ -33,16 +33,16 @@ OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer
33 for (unsigned int i = 0; i < num_attributes; ++i) { 33 for (unsigned int i = 0; i < num_attributes; ++i) {
34 const auto& output_register_map = regs.vs_output_attributes[i]; 34 const auto& output_register_map = regs.vs_output_attributes[i];
35 35
36 Regs::VSOutputAttributes::Semantic semantics[4] = { 36 RasterizerRegs::VSOutputAttributes::Semantic semantics[4] = {
37 output_register_map.map_x, output_register_map.map_y, output_register_map.map_z, 37 output_register_map.map_x, output_register_map.map_y, output_register_map.map_z,
38 output_register_map.map_w}; 38 output_register_map.map_w};
39 39
40 for (unsigned comp = 0; comp < 4; ++comp) { 40 for (unsigned comp = 0; comp < 4; ++comp) {
41 Regs::VSOutputAttributes::Semantic semantic = semantics[comp]; 41 RasterizerRegs::VSOutputAttributes::Semantic semantic = semantics[comp];
42 float24* out = &vertex_slots[semantic]; 42 float24* out = &vertex_slots[semantic];
43 if (semantic < vertex_slots.size()) { 43 if (semantic < vertex_slots.size()) {
44 *out = input.attr[i][comp]; 44 *out = input.attr[i][comp];
45 } else if (semantic != Regs::VSOutputAttributes::INVALID) { 45 } else if (semantic != RasterizerRegs::VSOutputAttributes::INVALID) {
46 LOG_ERROR(HW_GPU, "Invalid/unknown semantic id: %u", (unsigned int)semantic); 46 LOG_ERROR(HW_GPU, "Invalid/unknown semantic id: %u", (unsigned int)semantic);
47 } 47 }
48 } 48 }
@@ -66,7 +66,7 @@ OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer
66 return ret; 66 return ret;
67} 67}
68 68
69void UnitState::LoadInput(const Regs::ShaderConfig& config, const AttributeBuffer& input) { 69void UnitState::LoadInput(const ShaderRegs& config, const AttributeBuffer& input) {
70 const unsigned max_attribute = config.max_input_attribute_index; 70 const unsigned max_attribute = config.max_input_attribute_index;
71 71
72 for (unsigned attr = 0; attr <= max_attribute; ++attr) { 72 for (unsigned attr = 0; attr <= max_attribute; ++attr) {
@@ -75,7 +75,7 @@ void UnitState::LoadInput(const Regs::ShaderConfig& config, const AttributeBuffe
75 } 75 }
76} 76}
77 77
78void UnitState::WriteOutput(const Regs::ShaderConfig& config, AttributeBuffer& output) { 78void UnitState::WriteOutput(const ShaderRegs& config, AttributeBuffer& output) {
79 unsigned int output_i = 0; 79 unsigned int output_i = 0;
80 for (unsigned int reg : Common::BitSet<u32>(config.output_mask)) { 80 for (unsigned int reg : Common::BitSet<u32>(config.output_mask)) {
81 output.attr[output_i++] = registers.output[reg]; 81 output.attr[output_i++] = registers.output[reg];
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index b188d3edf..d52682479 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -12,8 +12,8 @@
12#include "common/common_funcs.h" 12#include "common/common_funcs.h"
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/vector_math.h" 14#include "common/vector_math.h"
15#include "video_core/pica.h"
16#include "video_core/pica_types.h" 15#include "video_core/pica_types.h"
16#include "video_core/regs.h"
17 17
18using nihstro::RegisterType; 18using nihstro::RegisterType;
19using nihstro::SourceRegister; 19using nihstro::SourceRegister;
@@ -39,19 +39,19 @@ struct OutputVertex {
39 INSERT_PADDING_WORDS(1); 39 INSERT_PADDING_WORDS(1);
40 Math::Vec2<float24> tc2; 40 Math::Vec2<float24> tc2;
41 41
42 static OutputVertex FromAttributeBuffer(const Regs& regs, AttributeBuffer& output); 42 static OutputVertex FromAttributeBuffer(const RasterizerRegs& regs, AttributeBuffer& output);
43}; 43};
44#define ASSERT_POS(var, pos) \ 44#define ASSERT_POS(var, pos) \
45 static_assert(offsetof(OutputVertex, var) == pos * sizeof(float24), "Semantic at wrong " \ 45 static_assert(offsetof(OutputVertex, var) == pos * sizeof(float24), "Semantic at wrong " \
46 "offset.") 46 "offset.")
47ASSERT_POS(pos, Regs::VSOutputAttributes::POSITION_X); 47ASSERT_POS(pos, RasterizerRegs::VSOutputAttributes::POSITION_X);
48ASSERT_POS(quat, Regs::VSOutputAttributes::QUATERNION_X); 48ASSERT_POS(quat, RasterizerRegs::VSOutputAttributes::QUATERNION_X);
49ASSERT_POS(color, Regs::VSOutputAttributes::COLOR_R); 49ASSERT_POS(color, RasterizerRegs::VSOutputAttributes::COLOR_R);
50ASSERT_POS(tc0, Regs::VSOutputAttributes::TEXCOORD0_U); 50ASSERT_POS(tc0, RasterizerRegs::VSOutputAttributes::TEXCOORD0_U);
51ASSERT_POS(tc1, Regs::VSOutputAttributes::TEXCOORD1_U); 51ASSERT_POS(tc1, RasterizerRegs::VSOutputAttributes::TEXCOORD1_U);
52ASSERT_POS(tc0_w, Regs::VSOutputAttributes::TEXCOORD0_W); 52ASSERT_POS(tc0_w, RasterizerRegs::VSOutputAttributes::TEXCOORD0_W);
53ASSERT_POS(view, Regs::VSOutputAttributes::VIEW_X); 53ASSERT_POS(view, RasterizerRegs::VSOutputAttributes::VIEW_X);
54ASSERT_POS(tc2, Regs::VSOutputAttributes::TEXCOORD2_U); 54ASSERT_POS(tc2, RasterizerRegs::VSOutputAttributes::TEXCOORD2_U);
55#undef ASSERT_POS 55#undef ASSERT_POS
56static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); 56static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
57static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size"); 57static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size");
@@ -116,9 +116,9 @@ struct UnitState {
116 * @param config Shader configuration registers corresponding to the unit. 116 * @param config Shader configuration registers corresponding to the unit.
117 * @param input Attribute buffer to load into the input registers. 117 * @param input Attribute buffer to load into the input registers.
118 */ 118 */
119 void LoadInput(const Regs::ShaderConfig& config, const AttributeBuffer& input); 119 void LoadInput(const ShaderRegs& config, const AttributeBuffer& input);
120 120
121 void WriteOutput(const Regs::ShaderConfig& config, AttributeBuffer& output); 121 void WriteOutput(const ShaderRegs& config, AttributeBuffer& output);
122}; 122};
123 123
124struct ShaderSetup { 124struct ShaderSetup {
diff --git a/src/video_core/shader/shader_interpreter.cpp b/src/video_core/shader/shader_interpreter.cpp
index 81522b8f5..f4d1c46c5 100644
--- a/src/video_core/shader/shader_interpreter.cpp
+++ b/src/video_core/shader/shader_interpreter.cpp
@@ -669,7 +669,7 @@ void InterpreterEngine::Run(const ShaderSetup& setup, UnitState& state) const {
669 669
670DebugData<true> InterpreterEngine::ProduceDebugInfo(const ShaderSetup& setup, 670DebugData<true> InterpreterEngine::ProduceDebugInfo(const ShaderSetup& setup,
671 const AttributeBuffer& input, 671 const AttributeBuffer& input,
672 const Regs::ShaderConfig& config) const { 672 const ShaderRegs& config) const {
673 UnitState state; 673 UnitState state;
674 DebugData<true> debug_data; 674 DebugData<true> debug_data;
675 675
diff --git a/src/video_core/shader/shader_interpreter.h b/src/video_core/shader/shader_interpreter.h
index d7a61e122..5682b3a39 100644
--- a/src/video_core/shader/shader_interpreter.h
+++ b/src/video_core/shader/shader_interpreter.h
@@ -23,7 +23,7 @@ public:
23 * @return Debug information for this shader with regards to the given vertex 23 * @return Debug information for this shader with regards to the given vertex
24 */ 24 */
25 DebugData<true> ProduceDebugInfo(const ShaderSetup& setup, const AttributeBuffer& input, 25 DebugData<true> ProduceDebugInfo(const ShaderSetup& setup, const AttributeBuffer& input,
26 const Regs::ShaderConfig& config) const; 26 const ShaderRegs& config) const;
27}; 27};
28 28
29} // namespace 29} // namespace
diff --git a/src/video_core/texture/texture_decode.cpp b/src/video_core/texture/texture_decode.cpp
index f611a1aa9..40d363184 100644
--- a/src/video_core/texture/texture_decode.cpp
+++ b/src/video_core/texture/texture_decode.cpp
@@ -10,12 +10,12 @@
10#include "common/math_util.h" 10#include "common/math_util.h"
11#include "common/swap.h" 11#include "common/swap.h"
12#include "common/vector_math.h" 12#include "common/vector_math.h"
13#include "video_core/pica.h" 13#include "video_core/regs_texturing.h"
14#include "video_core/texture/etc1.h" 14#include "video_core/texture/etc1.h"
15#include "video_core/texture/texture_decode.h" 15#include "video_core/texture/texture_decode.h"
16#include "video_core/utils.h" 16#include "video_core/utils.h"
17 17
18using TextureFormat = Pica::Regs::TextureFormat; 18using TextureFormat = Pica::TexturingRegs::TextureFormat;
19 19
20namespace Pica { 20namespace Pica {
21namespace Texture { 21namespace Texture {
@@ -82,32 +82,32 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
82 using VideoCore::MortonInterleave; 82 using VideoCore::MortonInterleave;
83 83
84 switch (info.format) { 84 switch (info.format) {
85 case Regs::TextureFormat::RGBA8: { 85 case TextureFormat::RGBA8: {
86 auto res = Color::DecodeRGBA8(source + MortonInterleave(x, y) * 4); 86 auto res = Color::DecodeRGBA8(source + MortonInterleave(x, y) * 4);
87 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; 87 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
88 } 88 }
89 89
90 case Regs::TextureFormat::RGB8: { 90 case TextureFormat::RGB8: {
91 auto res = Color::DecodeRGB8(source + MortonInterleave(x, y) * 3); 91 auto res = Color::DecodeRGB8(source + MortonInterleave(x, y) * 3);
92 return {res.r(), res.g(), res.b(), 255}; 92 return {res.r(), res.g(), res.b(), 255};
93 } 93 }
94 94
95 case Regs::TextureFormat::RGB5A1: { 95 case TextureFormat::RGB5A1: {
96 auto res = Color::DecodeRGB5A1(source + MortonInterleave(x, y) * 2); 96 auto res = Color::DecodeRGB5A1(source + MortonInterleave(x, y) * 2);
97 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; 97 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
98 } 98 }
99 99
100 case Regs::TextureFormat::RGB565: { 100 case TextureFormat::RGB565: {
101 auto res = Color::DecodeRGB565(source + MortonInterleave(x, y) * 2); 101 auto res = Color::DecodeRGB565(source + MortonInterleave(x, y) * 2);
102 return {res.r(), res.g(), res.b(), 255}; 102 return {res.r(), res.g(), res.b(), 255};
103 } 103 }
104 104
105 case Regs::TextureFormat::RGBA4: { 105 case TextureFormat::RGBA4: {
106 auto res = Color::DecodeRGBA4(source + MortonInterleave(x, y) * 2); 106 auto res = Color::DecodeRGBA4(source + MortonInterleave(x, y) * 2);
107 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; 107 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
108 } 108 }
109 109
110 case Regs::TextureFormat::IA8: { 110 case TextureFormat::IA8: {
111 const u8* source_ptr = source + MortonInterleave(x, y) * 2; 111 const u8* source_ptr = source + MortonInterleave(x, y) * 2;
112 112
113 if (disable_alpha) { 113 if (disable_alpha) {
@@ -118,17 +118,17 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
118 } 118 }
119 } 119 }
120 120
121 case Regs::TextureFormat::RG8: { 121 case TextureFormat::RG8: {
122 auto res = Color::DecodeRG8(source + MortonInterleave(x, y) * 2); 122 auto res = Color::DecodeRG8(source + MortonInterleave(x, y) * 2);
123 return {res.r(), res.g(), 0, 255}; 123 return {res.r(), res.g(), 0, 255};
124 } 124 }
125 125
126 case Regs::TextureFormat::I8: { 126 case TextureFormat::I8: {
127 const u8* source_ptr = source + MortonInterleave(x, y); 127 const u8* source_ptr = source + MortonInterleave(x, y);
128 return {*source_ptr, *source_ptr, *source_ptr, 255}; 128 return {*source_ptr, *source_ptr, *source_ptr, 255};
129 } 129 }
130 130
131 case Regs::TextureFormat::A8: { 131 case TextureFormat::A8: {
132 const u8* source_ptr = source + MortonInterleave(x, y); 132 const u8* source_ptr = source + MortonInterleave(x, y);
133 133
134 if (disable_alpha) { 134 if (disable_alpha) {
@@ -138,7 +138,7 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
138 } 138 }
139 } 139 }
140 140
141 case Regs::TextureFormat::IA4: { 141 case TextureFormat::IA4: {
142 const u8* source_ptr = source + MortonInterleave(x, y); 142 const u8* source_ptr = source + MortonInterleave(x, y);
143 143
144 u8 i = Color::Convert4To8(((*source_ptr) & 0xF0) >> 4); 144 u8 i = Color::Convert4To8(((*source_ptr) & 0xF0) >> 4);
@@ -152,7 +152,7 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
152 } 152 }
153 } 153 }
154 154
155 case Regs::TextureFormat::I4: { 155 case TextureFormat::I4: {
156 u32 morton_offset = MortonInterleave(x, y); 156 u32 morton_offset = MortonInterleave(x, y);
157 const u8* source_ptr = source + morton_offset / 2; 157 const u8* source_ptr = source + morton_offset / 2;
158 158
@@ -162,7 +162,7 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
162 return {i, i, i, 255}; 162 return {i, i, i, 255};
163 } 163 }
164 164
165 case Regs::TextureFormat::A4: { 165 case TextureFormat::A4: {
166 u32 morton_offset = MortonInterleave(x, y); 166 u32 morton_offset = MortonInterleave(x, y);
167 const u8* source_ptr = source + morton_offset / 2; 167 const u8* source_ptr = source + morton_offset / 2;
168 168
@@ -176,9 +176,9 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
176 } 176 }
177 } 177 }
178 178
179 case Regs::TextureFormat::ETC1: 179 case TextureFormat::ETC1:
180 case Regs::TextureFormat::ETC1A4: { 180 case TextureFormat::ETC1A4: {
181 bool has_alpha = (info.format == Regs::TextureFormat::ETC1A4); 181 bool has_alpha = (info.format == TextureFormat::ETC1A4);
182 size_t subtile_size = has_alpha ? 16 : 8; 182 size_t subtile_size = has_alpha ? 16 : 8;
183 183
184 // ETC1 further subdivides each 8x8 tile into four 4x4 subtiles 184 // ETC1 further subdivides each 8x8 tile into four 4x4 subtiles
@@ -214,8 +214,8 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
214 } 214 }
215} 215}
216 216
217TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config, 217TextureInfo TextureInfo::FromPicaRegister(const TexturingRegs::TextureConfig& config,
218 const Regs::TextureFormat& format) { 218 const TexturingRegs::TextureFormat& format) {
219 TextureInfo info; 219 TextureInfo info;
220 info.physical_address = config.GetPhysicalAddress(); 220 info.physical_address = config.GetPhysicalAddress();
221 info.width = config.width; 221 info.width = config.width;
diff --git a/src/video_core/texture/texture_decode.h b/src/video_core/texture/texture_decode.h
index 5c636939a..8507cfeb8 100644
--- a/src/video_core/texture/texture_decode.h
+++ b/src/video_core/texture/texture_decode.h
@@ -6,27 +6,27 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/vector_math.h" 8#include "common/vector_math.h"
9#include "video_core/pica.h" 9#include "video_core/regs_texturing.h"
10 10
11namespace Pica { 11namespace Pica {
12namespace Texture { 12namespace Texture {
13 13
14/// Returns the byte size of a 8*8 tile of the specified texture format. 14/// Returns the byte size of a 8*8 tile of the specified texture format.
15size_t CalculateTileSize(Pica::Regs::TextureFormat format); 15size_t CalculateTileSize(TexturingRegs::TextureFormat format);
16 16
17struct TextureInfo { 17struct TextureInfo {
18 PAddr physical_address; 18 PAddr physical_address;
19 unsigned int width; 19 unsigned int width;
20 unsigned int height; 20 unsigned int height;
21 ptrdiff_t stride; 21 ptrdiff_t stride;
22 Pica::Regs::TextureFormat format; 22 TexturingRegs::TextureFormat format;
23 23
24 static TextureInfo FromPicaRegister(const Pica::Regs::TextureConfig& config, 24 static TextureInfo FromPicaRegister(const TexturingRegs::TextureConfig& config,
25 const Pica::Regs::TextureFormat& format); 25 const TexturingRegs::TextureFormat& format);
26 26
27 /// Calculates stride from format and width, assuming that the entire texture is contiguous. 27 /// Calculates stride from format and width, assuming that the entire texture is contiguous.
28 void SetDefaultStride() { 28 void SetDefaultStride() {
29 stride = Pica::Texture::CalculateTileSize(format) * (width / 8); 29 stride = CalculateTileSize(format) * (width / 8);
30 } 30 }
31}; 31};
32 32
diff --git a/src/video_core/vertex_loader.cpp b/src/video_core/vertex_loader.cpp
index bf83b61ca..37c5224a9 100644
--- a/src/video_core/vertex_loader.cpp
+++ b/src/video_core/vertex_loader.cpp
@@ -8,15 +8,15 @@
8#include "common/vector_math.h" 8#include "common/vector_math.h"
9#include "core/memory.h" 9#include "core/memory.h"
10#include "video_core/debug_utils/debug_utils.h" 10#include "video_core/debug_utils/debug_utils.h"
11#include "video_core/pica.h"
12#include "video_core/pica_state.h" 11#include "video_core/pica_state.h"
13#include "video_core/pica_types.h" 12#include "video_core/pica_types.h"
13#include "video_core/regs_pipeline.h"
14#include "video_core/shader/shader.h" 14#include "video_core/shader/shader.h"
15#include "video_core/vertex_loader.h" 15#include "video_core/vertex_loader.h"
16 16
17namespace Pica { 17namespace Pica {
18 18
19void VertexLoader::Setup(const Pica::Regs& regs) { 19void VertexLoader::Setup(const PipelineRegs& regs) {
20 ASSERT_MSG(!is_setup, "VertexLoader is not intended to be setup more than once."); 20 ASSERT_MSG(!is_setup, "VertexLoader is not intended to be setup more than once.");
21 21
22 const auto& attribute_config = regs.vertex_attributes; 22 const auto& attribute_config = regs.vertex_attributes;
@@ -85,15 +85,16 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex,
85 memory_accesses.AddAccess( 85 memory_accesses.AddAccess(
86 source_addr, 86 source_addr,
87 vertex_attribute_elements[i] * 87 vertex_attribute_elements[i] *
88 ((vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) 88 ((vertex_attribute_formats[i] == PipelineRegs::VertexAttributeFormat::FLOAT)
89 ? 4 89 ? 4
90 : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) 90 : (vertex_attribute_formats[i] ==
91 PipelineRegs::VertexAttributeFormat::SHORT)
91 ? 2 92 ? 2
92 : 1)); 93 : 1));
93 } 94 }
94 95
95 switch (vertex_attribute_formats[i]) { 96 switch (vertex_attribute_formats[i]) {
96 case Regs::VertexAttributeFormat::BYTE: { 97 case PipelineRegs::VertexAttributeFormat::BYTE: {
97 const s8* srcdata = 98 const s8* srcdata =
98 reinterpret_cast<const s8*>(Memory::GetPhysicalPointer(source_addr)); 99 reinterpret_cast<const s8*>(Memory::GetPhysicalPointer(source_addr));
99 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 100 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
@@ -101,7 +102,7 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex,
101 } 102 }
102 break; 103 break;
103 } 104 }
104 case Regs::VertexAttributeFormat::UBYTE: { 105 case PipelineRegs::VertexAttributeFormat::UBYTE: {
105 const u8* srcdata = 106 const u8* srcdata =
106 reinterpret_cast<const u8*>(Memory::GetPhysicalPointer(source_addr)); 107 reinterpret_cast<const u8*>(Memory::GetPhysicalPointer(source_addr));
107 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 108 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
@@ -109,7 +110,7 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex,
109 } 110 }
110 break; 111 break;
111 } 112 }
112 case Regs::VertexAttributeFormat::SHORT: { 113 case PipelineRegs::VertexAttributeFormat::SHORT: {
113 const s16* srcdata = 114 const s16* srcdata =
114 reinterpret_cast<const s16*>(Memory::GetPhysicalPointer(source_addr)); 115 reinterpret_cast<const s16*>(Memory::GetPhysicalPointer(source_addr));
115 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 116 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
@@ -117,7 +118,7 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex,
117 } 118 }
118 break; 119 break;
119 } 120 }
120 case Regs::VertexAttributeFormat::FLOAT: { 121 case PipelineRegs::VertexAttributeFormat::FLOAT: {
121 const float* srcdata = 122 const float* srcdata =
122 reinterpret_cast<const float*>(Memory::GetPhysicalPointer(source_addr)); 123 reinterpret_cast<const float*>(Memory::GetPhysicalPointer(source_addr));
123 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 124 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
diff --git a/src/video_core/vertex_loader.h b/src/video_core/vertex_loader.h
index 51f3d45b4..02db10aee 100644
--- a/src/video_core/vertex_loader.h
+++ b/src/video_core/vertex_loader.h
@@ -2,7 +2,7 @@
2 2
3#include <array> 3#include <array>
4#include "common/common_types.h" 4#include "common/common_types.h"
5#include "video_core/pica.h" 5#include "video_core/regs_pipeline.h"
6 6
7namespace Pica { 7namespace Pica {
8 8
@@ -17,11 +17,11 @@ struct AttributeBuffer;
17class VertexLoader { 17class VertexLoader {
18public: 18public:
19 VertexLoader() = default; 19 VertexLoader() = default;
20 explicit VertexLoader(const Pica::Regs& regs) { 20 explicit VertexLoader(const PipelineRegs& regs) {
21 Setup(regs); 21 Setup(regs);
22 } 22 }
23 23
24 void Setup(const Pica::Regs& regs); 24 void Setup(const PipelineRegs& regs);
25 void LoadVertex(u32 base_address, int index, int vertex, Shader::AttributeBuffer& input, 25 void LoadVertex(u32 base_address, int index, int vertex, Shader::AttributeBuffer& input,
26 DebugUtils::MemoryAccessTracker& memory_accesses); 26 DebugUtils::MemoryAccessTracker& memory_accesses);
27 27
@@ -32,7 +32,7 @@ public:
32private: 32private:
33 std::array<u32, 16> vertex_attribute_sources; 33 std::array<u32, 16> vertex_attribute_sources;
34 std::array<u32, 16> vertex_attribute_strides{}; 34 std::array<u32, 16> vertex_attribute_strides{};
35 std::array<Regs::VertexAttributeFormat, 16> vertex_attribute_formats; 35 std::array<PipelineRegs::VertexAttributeFormat, 16> vertex_attribute_formats;
36 std::array<u32, 16> vertex_attribute_elements{}; 36 std::array<u32, 16> vertex_attribute_elements{};
37 std::array<bool, 16> vertex_attribute_is_default; 37 std::array<bool, 16> vertex_attribute_is_default;
38 int num_total_attributes = 0; 38 int num_total_attributes = 0;