summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
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 @@
#include "citra_qt/util/util.h"
#include "common/vector_math.h"
#include "video_core/debug_utils/debug_utils.h"
-#include "video_core/pica.h"
#include "video_core/pica_state.h"
+#include "video_core/regs.h"
#include "video_core/texture/texture_decode.h"
namespace {
@@ -123,15 +123,16 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&
void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
const unsigned int command_id =
list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt();
- if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) ||
- COMMAND_IN_RANGE(command_id, texture2)) {
+ if (COMMAND_IN_RANGE(command_id, texturing.texture0) ||
+ COMMAND_IN_RANGE(command_id, texturing.texture1) ||
+ COMMAND_IN_RANGE(command_id, texturing.texture2)) {
unsigned texture_index;
- if (COMMAND_IN_RANGE(command_id, texture0)) {
+ if (COMMAND_IN_RANGE(command_id, texturing.texture0)) {
texture_index = 0;
- } else if (COMMAND_IN_RANGE(command_id, texture1)) {
+ } else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) {
texture_index = 1;
- } else if (COMMAND_IN_RANGE(command_id, texture2)) {
+ } else if (COMMAND_IN_RANGE(command_id, texturing.texture2)) {
texture_index = 2;
} else {
UNREACHABLE_MSG("Unknown texture command");
@@ -146,19 +147,20 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
const unsigned int command_id =
list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt();
- if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) ||
- COMMAND_IN_RANGE(command_id, texture2)) {
+ if (COMMAND_IN_RANGE(command_id, texturing.texture0) ||
+ COMMAND_IN_RANGE(command_id, texturing.texture1) ||
+ COMMAND_IN_RANGE(command_id, texturing.texture2)) {
unsigned texture_index;
- if (COMMAND_IN_RANGE(command_id, texture0)) {
+ if (COMMAND_IN_RANGE(command_id, texturing.texture0)) {
texture_index = 0;
- } else if (COMMAND_IN_RANGE(command_id, texture1)) {
+ } else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) {
texture_index = 1;
} else {
texture_index = 2;
}
- const auto texture = Pica::g_state.regs.GetTextures()[texture_index];
+ const auto texture = Pica::g_state.regs.texturing.GetTextures()[texture_index];
const auto config = texture.config;
const auto format = texture.format;
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 @@
#include "common/color.h"
#include "core/hw/gpu.h"
#include "core/memory.h"
-#include "video_core/pica.h"
#include "video_core/pica_state.h"
+#include "video_core/regs.h"
#include "video_core/texture/texture_decode.h"
#include "video_core/utils.h"
@@ -414,30 +414,30 @@ void GraphicsSurfaceWidget::OnUpdate() {
// TODO: Store a reference to the registers in the debug context instead of accessing them
// directly...
- const auto& framebuffer = Pica::g_state.regs.framebuffer;
+ const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer;
surface_address = framebuffer.GetColorBufferPhysicalAddress();
surface_width = framebuffer.GetWidth();
surface_height = framebuffer.GetHeight();
switch (framebuffer.color_format) {
- case Pica::Regs::ColorFormat::RGBA8:
+ case Pica::FramebufferRegs::ColorFormat::RGBA8:
surface_format = Format::RGBA8;
break;
- case Pica::Regs::ColorFormat::RGB8:
+ case Pica::FramebufferRegs::ColorFormat::RGB8:
surface_format = Format::RGB8;
break;
- case Pica::Regs::ColorFormat::RGB5A1:
+ case Pica::FramebufferRegs::ColorFormat::RGB5A1:
surface_format = Format::RGB5A1;
break;
- case Pica::Regs::ColorFormat::RGB565:
+ case Pica::FramebufferRegs::ColorFormat::RGB565:
surface_format = Format::RGB565;
break;
- case Pica::Regs::ColorFormat::RGBA4:
+ case Pica::FramebufferRegs::ColorFormat::RGBA4:
surface_format = Format::RGBA4;
break;
@@ -450,22 +450,22 @@ void GraphicsSurfaceWidget::OnUpdate() {
}
case Source::DepthBuffer: {
- const auto& framebuffer = Pica::g_state.regs.framebuffer;
+ const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer;
surface_address = framebuffer.GetDepthBufferPhysicalAddress();
surface_width = framebuffer.GetWidth();
surface_height = framebuffer.GetHeight();
switch (framebuffer.depth_format) {
- case Pica::Regs::DepthFormat::D16:
+ case Pica::FramebufferRegs::DepthFormat::D16:
surface_format = Format::D16;
break;
- case Pica::Regs::DepthFormat::D24:
+ case Pica::FramebufferRegs::DepthFormat::D24:
surface_format = Format::D24;
break;
- case Pica::Regs::DepthFormat::D24S8:
+ case Pica::FramebufferRegs::DepthFormat::D24S8:
surface_format = Format::D24X8;
break;
@@ -478,14 +478,14 @@ void GraphicsSurfaceWidget::OnUpdate() {
}
case Source::StencilBuffer: {
- const auto& framebuffer = Pica::g_state.regs.framebuffer;
+ const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer;
surface_address = framebuffer.GetDepthBufferPhysicalAddress();
surface_width = framebuffer.GetWidth();
surface_height = framebuffer.GetHeight();
switch (framebuffer.depth_format) {
- case Pica::Regs::DepthFormat::D24S8:
+ case Pica::FramebufferRegs::DepthFormat::D24S8:
surface_format = Format::X24S8;
break;
@@ -512,7 +512,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
break;
}
- const auto texture = Pica::g_state.regs.GetTextures()[texture_index];
+ const auto texture = Pica::g_state.regs.texturing.GetTextures()[texture_index];
auto info = Pica::Texture::TextureInfo::FromPicaRegister(texture.config, texture.format);
surface_address = info.physical_address;
@@ -574,7 +574,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
info.physical_address = surface_address;
info.width = surface_width;
info.height = surface_height;
- info.format = static_cast<Pica::Regs::TextureFormat>(surface_format);
+ info.format = static_cast<Pica::TexturingRegs::TextureFormat>(surface_format);
info.SetDefaultStride();
for (unsigned int y = 0; y < surface_height; ++y) {
@@ -689,7 +689,8 @@ void GraphicsSurfaceWidget::SaveSurface() {
unsigned int GraphicsSurfaceWidget::NibblesPerPixel(GraphicsSurfaceWidget::Format format) {
if (format <= Format::MaxTextureFormat) {
- return Pica::Regs::NibblesPerPixel(static_cast<Pica::Regs::TextureFormat>(format));
+ return Pica::TexturingRegs::NibblesPerPixel(
+ static_cast<Pica::TexturingRegs::TextureFormat>(format));
}
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 @@
#include "core/hw/lcd.h"
#include "core/tracer/recorder.h"
#include "nihstro/float24.h"
-#include "video_core/pica.h"
#include "video_core/pica_state.h"
GraphicsTracingWidget::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 @@
#include <QTreeView>
#include "citra_qt/debugger/graphics/graphics_vertex_shader.h"
#include "citra_qt/util/util.h"
-#include "video_core/pica.h"
#include "video_core/pica_state.h"
#include "video_core/shader/debug_data.h"
#include "video_core/shader/shader.h"
@@ -359,7 +358,7 @@ void GraphicsVertexShaderWidget::DumpShader() {
auto& config = Pica::g_state.regs.vs;
Pica::DebugUtils::DumpShader(filename.toStdString(), config, setup,
- Pica::g_state.regs.vs_output_attributes);
+ Pica::g_state.regs.rasterizer.vs_output_attributes);
}
GraphicsVertexShaderWidget::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
pica.cpp
primitive_assembly.cpp
rasterizer.cpp
+ regs.cpp
renderer_base.cpp
renderer_opengl/gl_rasterizer.cpp
renderer_opengl/gl_rasterizer_cache.cpp
@@ -32,6 +33,13 @@ set(HEADERS
primitive_assembly.h
rasterizer.h
rasterizer_interface.h
+ regs.h
+ regs_framebuffer.h
+ regs_lighting.h
+ regs_pipeline.h
+ regs_rasterizer.h
+ regs_shader.h
+ regs_texturing.h
renderer_base.h
renderer_opengl/gl_rasterizer.h
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 @@
#include "common/logging/log.h"
#include "common/vector_math.h"
#include "video_core/clipper.h"
-#include "video_core/pica.h"
#include "video_core/pica_state.h"
#include "video_core/pica_types.h"
#include "video_core/rasterizer.h"
+#include "video_core/regs.h"
#include "video_core/shader/shader.h"
using Pica::Rasterizer::Vertex;
@@ -64,10 +64,10 @@ static void InitScreenCoordinates(Vertex& vtx) {
} viewport;
const auto& regs = g_state.regs;
- viewport.halfsize_x = float24::FromRaw(regs.viewport_size_x);
- viewport.halfsize_y = float24::FromRaw(regs.viewport_size_y);
- viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.viewport_corner.x));
- viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.viewport_corner.y));
+ viewport.halfsize_x = float24::FromRaw(regs.rasterizer.viewport_size_x);
+ viewport.halfsize_y = float24::FromRaw(regs.rasterizer.viewport_size_y);
+ viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.rasterizer.viewport_corner.x));
+ viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.rasterizer.viewport_corner.y));
float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w;
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 @@
#include "core/tracer/recorder.h"
#include "video_core/command_processor.h"
#include "video_core/debug_utils/debug_utils.h"
-#include "video_core/pica.h"
#include "video_core/pica_state.h"
#include "video_core/pica_types.h"
#include "video_core/primitive_assembly.h"
#include "video_core/rasterizer_interface.h"
+#include "video_core/regs.h"
#include "video_core/renderer_base.h"
#include "video_core/shader/shader.h"
#include "video_core/vertex_loader.h"
@@ -74,23 +74,23 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D);
break;
- case PICA_REG_INDEX_WORKAROUND(triangle_topology, 0x25E):
- g_state.primitive_assembler.Reconfigure(regs.triangle_topology);
+ case PICA_REG_INDEX(pipeline.triangle_topology):
+ g_state.primitive_assembler.Reconfigure(regs.pipeline.triangle_topology);
break;
- case PICA_REG_INDEX_WORKAROUND(restart_primitive, 0x25F):
+ case PICA_REG_INDEX(pipeline.restart_primitive):
g_state.primitive_assembler.Reset();
break;
- case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.index, 0x232):
+ case PICA_REG_INDEX(pipeline.vs_default_attributes_setup.index):
g_state.immediate.current_attribute = 0;
default_attr_counter = 0;
break;
// Load default vertex input attributes
- case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233):
- case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234):
- case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235): {
+ case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[0], 0x233):
+ case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[1], 0x234):
+ case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[2], 0x235): {
// TODO: Does actual hardware indeed keep an intermediate buffer or does
// it directly write the values?
default_attr_write_buffer[default_attr_counter++] = value;
@@ -102,7 +102,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
if (default_attr_counter >= 3) {
default_attr_counter = 0;
- auto& setup = regs.vs_default_attributes_setup;
+ auto& setup = regs.pipeline.vs_default_attributes_setup;
if (setup.index >= 16) {
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) {
immediate_input.attr[immediate_attribute_id] = attribute;
- if (immediate_attribute_id < regs.max_input_attrib_index) {
+ if (immediate_attribute_id < regs.pipeline.max_input_attrib_index) {
immediate_attribute_id += 1;
} else {
MICROPROFILE_SCOPE(GPU_Drawing);
@@ -165,15 +165,16 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
};
g_state.primitive_assembler.SubmitVertex(
- Shader::OutputVertex::FromAttributeBuffer(regs, output), AddTriangle);
+ Shader::OutputVertex::FromAttributeBuffer(regs.rasterizer, output),
+ AddTriangle);
}
}
}
break;
}
- case PICA_REG_INDEX(gpu_mode):
- if (regs.gpu_mode == Regs::GPUMode::Configuring) {
+ case PICA_REG_INDEX(pipeline.gpu_mode):
+ if (regs.pipeline.gpu_mode == PipelineRegs::GPUMode::Configuring) {
MICROPROFILE_SCOPE(GPU_Drawing);
// 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) {
}
break;
- case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c):
- case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): {
- unsigned index = static_cast<unsigned>(id - PICA_REG_INDEX(command_buffer.trigger[0]));
- u32* head_ptr =
- (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index));
+ case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[0], 0x23c):
+ case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[1], 0x23d): {
+ unsigned index =
+ static_cast<unsigned>(id - PICA_REG_INDEX(pipeline.command_buffer.trigger[0]));
+ u32* head_ptr = (u32*)Memory::GetPhysicalPointer(
+ regs.pipeline.command_buffer.GetPhysicalAddress(index));
g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
- g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32);
+ g_state.cmd_list.length = regs.pipeline.command_buffer.GetSize(index) / sizeof(u32);
break;
}
// It seems like these trigger vertex rendering
- case PICA_REG_INDEX(trigger_draw):
- case PICA_REG_INDEX(trigger_draw_indexed): {
+ case PICA_REG_INDEX(pipeline.trigger_draw):
+ case PICA_REG_INDEX(pipeline.trigger_draw_indexed): {
MICROPROFILE_SCOPE(GPU_Drawing);
#if PICA_LOG_TEV
@@ -209,13 +211,13 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
// Processes information about internal vertex attributes to figure out how a vertex is
// loaded.
// Later, these can be compiled and cached.
- const u32 base_address = regs.vertex_attributes.GetPhysicalBaseAddress();
- VertexLoader loader(regs);
+ const u32 base_address = regs.pipeline.vertex_attributes.GetPhysicalBaseAddress();
+ VertexLoader loader(regs.pipeline);
// Load vertices
- bool is_indexed = (id == PICA_REG_INDEX(trigger_draw_indexed));
+ bool is_indexed = (id == PICA_REG_INDEX(pipeline.trigger_draw_indexed));
- const auto& index_info = regs.index_array;
+ const auto& index_info = regs.pipeline.index_array;
const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset);
const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8);
bool index_u16 = index_info.format != 0;
@@ -224,13 +226,13 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
if (g_debug_context && g_debug_context->recorder) {
for (int i = 0; i < 3; ++i) {
- const auto texture = regs.GetTextures()[i];
+ const auto texture = regs.texturing.GetTextures()[i];
if (!texture.enabled)
continue;
u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
g_debug_context->recorder->MemoryAccessed(
- texture_data, Pica::Regs::NibblesPerPixel(texture.format) *
+ texture_data, Pica::TexturingRegs::NibblesPerPixel(texture.format) *
texture.config.width / 2 * texture.config.height,
texture.config.GetPhysicalAddress());
}
@@ -253,11 +255,11 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
shader_engine->SetupBatch(g_state.vs, regs.vs.main_offset);
- for (unsigned int index = 0; index < regs.num_vertices; ++index) {
+ for (unsigned int index = 0; index < regs.pipeline.num_vertices; ++index) {
// Indexed rendering doesn't use the start offset
unsigned int vertex =
is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index])
- : (index + regs.vertex_offset);
+ : (index + regs.pipeline.vertex_offset);
// -1 is a common special value used for primitive restart. Since it's unknown if
// 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) {
shader_unit.WriteOutput(regs.vs, output);
// Retrieve vertex from register data
- output_vertex = Shader::OutputVertex::FromAttributeBuffer(regs, output);
+ output_vertex = Shader::OutputVertex::FromAttributeBuffer(regs.rasterizer, output);
if (is_indexed) {
vertex_cache[vertex_cache_pos] = output_vertex;
@@ -437,16 +439,16 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
break;
}
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[0], 0xe8):
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[1], 0xe9):
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[2], 0xea):
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[3], 0xeb):
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[4], 0xec):
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[5], 0xed):
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[6], 0xee):
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[7], 0xef): {
- g_state.fog.lut[regs.fog_lut_offset % 128].raw = value;
- regs.fog_lut_offset.Assign(regs.fog_lut_offset + 1);
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[0], 0xe8):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[1], 0xe9):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[2], 0xea):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[3], 0xeb):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[4], 0xec):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[5], 0xed):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[6], 0xee):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[7], 0xef): {
+ g_state.fog.lut[regs.texturing.fog_lut_offset % 128].raw = value;
+ regs.texturing.fog_lut_offset.Assign(regs.texturing.fog_lut_offset + 1);
break;
}
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 @@
#include "common/math_util.h"
#include "common/vector_math.h"
#include "video_core/debug_utils/debug_utils.h"
-#include "video_core/pica.h"
#include "video_core/pica_state.h"
#include "video_core/pica_types.h"
#include "video_core/rasterizer_interface.h"
+#include "video_core/regs.h"
#include "video_core/renderer_base.h"
#include "video_core/shader/shader.h"
#include "video_core/texture/texture_decode.h"
@@ -88,9 +88,9 @@ std::shared_ptr<DebugContext> g_debug_context; // TODO: Get rid of this global
namespace DebugUtils {
-void DumpShader(const std::string& filename, const Regs::ShaderConfig& config,
+void DumpShader(const std::string& filename, const ShaderRegs& config,
const Shader::ShaderSetup& setup,
- const Regs::VSOutputAttributes* output_attributes) {
+ const RasterizerRegs::VSOutputAttributes* output_attributes) {
struct StuffToWrite {
const u8* pointer;
u32 size;
@@ -129,7 +129,7 @@ void DumpShader(const std::string& filename, const Regs::ShaderConfig& config,
// This is put into a try-catch block to make sure we notice unknown configurations.
std::vector<OutputRegisterInfo> output_info_table;
for (unsigned i = 0; i < 7; ++i) {
- using OutputAttributes = Pica::Regs::VSOutputAttributes;
+ using OutputAttributes = Pica::RasterizerRegs::VSOutputAttributes;
// TODO: It's still unclear how the attribute components map to the register!
// Once we know that, this code probably will not make much sense anymore.
@@ -331,7 +331,7 @@ static void FlushIOFile(png_structp png_ptr) {
}
#endif
-void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
+void DumpTexture(const TexturingRegs::TextureConfig& texture_config, u8* data) {
#ifndef HAVE_PNG
return;
#else
@@ -396,7 +396,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
info.width = texture_config.width;
info.height = texture_config.height;
info.stride = row_stride;
- info.format = g_state.regs.texture0_format;
+ info.format = g_state.regs.texturing.texture0_format;
Math::Vec4<u8> texture_color = Pica::Texture::LookupTexture(data, x, y, info);
buf[3 * x + y * row_stride] = texture_color.r();
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
return ret;
}
-static std::string GetTevStageConfigSourceString(const Pica::Regs::TevStageConfig::Source& source) {
- using Source = Pica::Regs::TevStageConfig::Source;
+static std::string GetTevStageConfigSourceString(
+ const TexturingRegs::TevStageConfig::Source& source) {
+
+ using Source = TexturingRegs::TevStageConfig::Source;
static const std::map<Source, std::string> source_map = {
{Source::PrimaryColor, "PrimaryColor"},
{Source::PrimaryFragmentColor, "PrimaryFragmentColor"},
@@ -457,9 +459,10 @@ static std::string GetTevStageConfigSourceString(const Pica::Regs::TevStageConfi
}
static std::string GetTevStageConfigColorSourceString(
- const Pica::Regs::TevStageConfig::Source& source,
- const Pica::Regs::TevStageConfig::ColorModifier modifier) {
- using ColorModifier = Pica::Regs::TevStageConfig::ColorModifier;
+ const TexturingRegs::TevStageConfig::Source& source,
+ const TexturingRegs::TevStageConfig::ColorModifier modifier) {
+
+ using ColorModifier = TexturingRegs::TevStageConfig::ColorModifier;
static const std::map<ColorModifier, std::string> color_modifier_map = {
{ColorModifier::SourceColor, "%source.rgb"},
{ColorModifier::OneMinusSourceColor, "(1.0 - %source.rgb)"},
@@ -483,9 +486,10 @@ static std::string GetTevStageConfigColorSourceString(
}
static std::string GetTevStageConfigAlphaSourceString(
- const Pica::Regs::TevStageConfig::Source& source,
- const Pica::Regs::TevStageConfig::AlphaModifier modifier) {
- using AlphaModifier = Pica::Regs::TevStageConfig::AlphaModifier;
+ const TexturingRegs::TevStageConfig::Source& source,
+ const TexturingRegs::TevStageConfig::AlphaModifier modifier) {
+
+ using AlphaModifier = TexturingRegs::TevStageConfig::AlphaModifier;
static const std::map<AlphaModifier, std::string> alpha_modifier_map = {
{AlphaModifier::SourceAlpha, "%source.a"},
{AlphaModifier::OneMinusSourceAlpha, "(1.0 - %source.a)"},
@@ -507,8 +511,9 @@ static std::string GetTevStageConfigAlphaSourceString(
}
static std::string GetTevStageConfigOperationString(
- const Pica::Regs::TevStageConfig::Operation& operation) {
- using Operation = Pica::Regs::TevStageConfig::Operation;
+ const TexturingRegs::TevStageConfig::Operation& operation) {
+
+ using Operation = TexturingRegs::TevStageConfig::Operation;
static const std::map<Operation, std::string> combiner_map = {
{Operation::Replace, "%source1"},
{Operation::Modulate, "(%source1 * %source2)"},
@@ -528,7 +533,7 @@ static std::string GetTevStageConfigOperationString(
return op_it->second;
}
-std::string GetTevStageConfigColorCombinerString(const Pica::Regs::TevStageConfig& tev_stage) {
+std::string GetTevStageConfigColorCombinerString(const TexturingRegs::TevStageConfig& tev_stage) {
auto op_str = GetTevStageConfigOperationString(tev_stage.color_op);
op_str = ReplacePattern(
op_str, "%source1",
@@ -541,7 +546,7 @@ std::string GetTevStageConfigColorCombinerString(const Pica::Regs::TevStageConfi
GetTevStageConfigColorSourceString(tev_stage.color_source3, tev_stage.color_modifier3));
}
-std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfig& tev_stage) {
+std::string GetTevStageConfigAlphaCombinerString(const TexturingRegs::TevStageConfig& tev_stage) {
auto op_str = GetTevStageConfigOperationString(tev_stage.alpha_op);
op_str = ReplacePattern(
op_str, "%source1",
@@ -554,7 +559,7 @@ std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfi
GetTevStageConfigAlphaSourceString(tev_stage.alpha_source3, tev_stage.alpha_modifier3));
}
-void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig, 6>& stages) {
+void DumpTevStageConfig(const std::array<TexturingRegs::TevStageConfig, 6>& stages) {
std::string stage_info = "Tev setup:\n";
for (size_t index = 0; index < stages.size(); ++index) {
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 @@
#include <vector>
#include "common/common_types.h"
#include "common/vector_math.h"
-#include "video_core/pica.h"
+#include "video_core/regs.h"
namespace CiTrace {
class Recorder;
@@ -182,9 +182,9 @@ namespace DebugUtils {
#define PICA_DUMP_TEXTURES 0
#define PICA_LOG_TEV 0
-void DumpShader(const std::string& filename, const Regs::ShaderConfig& config,
+void DumpShader(const std::string& filename, const ShaderRegs& config,
const Shader::ShaderSetup& setup,
- const Regs::VSOutputAttributes* output_attributes);
+ const RasterizerRegs::VSOutputAttributes* output_attributes);
// Utility class to log Pica commands.
struct PicaTrace {
@@ -205,13 +205,13 @@ inline bool IsPicaTracing() {
void OnPicaRegWrite(PicaTrace::Write write);
std::unique_ptr<PicaTrace> FinishPicaTracing();
-void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data);
+void DumpTexture(const TexturingRegs::TextureConfig& texture_config, u8* data);
-std::string GetTevStageConfigColorCombinerString(const Pica::Regs::TevStageConfig& tev_stage);
-std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfig& tev_stage);
+std::string GetTevStageConfigColorCombinerString(const TexturingRegs::TevStageConfig& tev_stage);
+std::string GetTevStageConfigAlphaCombinerString(const TexturingRegs::TevStageConfig& tev_stage);
/// Dumps the Tev stage config to log at trace level
-void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig, 6>& stages);
+void DumpTevStageConfig(const std::array<TexturingRegs::TevStageConfig, 6>& stages);
/**
* 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 @@
// Refer to the license.txt file included.
#include <cstring>
-#include <iterator>
-#include <unordered_map>
-#include <utility>
#include "video_core/pica.h"
#include "video_core/pica_state.h"
-#include "video_core/primitive_assembly.h"
-#include "video_core/shader/shader.h"
+#include "video_core/regs.h"
namespace Pica {
State g_state;
-static const std::pair<u16, const char*> register_names[] = {
- {0x010, "GPUREG_FINALIZE"},
-
- {0x040, "GPUREG_FACECULLING_CONFIG"},
- {0x041, "GPUREG_VIEWPORT_WIDTH"},
- {0x042, "GPUREG_VIEWPORT_INVW"},
- {0x043, "GPUREG_VIEWPORT_HEIGHT"},
- {0x044, "GPUREG_VIEWPORT_INVH"},
-
- {0x047, "GPUREG_FRAGOP_CLIP"},
- {0x048, "GPUREG_FRAGOP_CLIP_DATA0"},
- {0x049, "GPUREG_FRAGOP_CLIP_DATA1"},
- {0x04A, "GPUREG_FRAGOP_CLIP_DATA2"},
- {0x04B, "GPUREG_FRAGOP_CLIP_DATA3"},
-
- {0x04D, "GPUREG_DEPTHMAP_SCALE"},
- {0x04E, "GPUREG_DEPTHMAP_OFFSET"},
- {0x04F, "GPUREG_SH_OUTMAP_TOTAL"},
- {0x050, "GPUREG_SH_OUTMAP_O0"},
- {0x051, "GPUREG_SH_OUTMAP_O1"},
- {0x052, "GPUREG_SH_OUTMAP_O2"},
- {0x053, "GPUREG_SH_OUTMAP_O3"},
- {0x054, "GPUREG_SH_OUTMAP_O4"},
- {0x055, "GPUREG_SH_OUTMAP_O5"},
- {0x056, "GPUREG_SH_OUTMAP_O6"},
-
- {0x061, "GPUREG_EARLYDEPTH_FUNC"},
- {0x062, "GPUREG_EARLYDEPTH_TEST1"},
- {0x063, "GPUREG_EARLYDEPTH_CLEAR"},
- {0x064, "GPUREG_SH_OUTATTR_MODE"},
- {0x065, "GPUREG_SCISSORTEST_MODE"},
- {0x066, "GPUREG_SCISSORTEST_POS"},
- {0x067, "GPUREG_SCISSORTEST_DIM"},
- {0x068, "GPUREG_VIEWPORT_XY"},
-
- {0x06A, "GPUREG_EARLYDEPTH_DATA"},
-
- {0x06D, "GPUREG_DEPTHMAP_ENABLE"},
- {0x06E, "GPUREG_RENDERBUF_DIM"},
- {0x06F, "GPUREG_SH_OUTATTR_CLOCK"},
-
- {0x080, "GPUREG_TEXUNIT_CONFIG"},
- {0x081, "GPUREG_TEXUNIT0_BORDER_COLOR"},
- {0x082, "GPUREG_TEXUNIT0_DIM"},
- {0x083, "GPUREG_TEXUNIT0_PARAM"},
- {0x084, "GPUREG_TEXUNIT0_LOD"},
- {0x085, "GPUREG_TEXUNIT0_ADDR1"},
- {0x086, "GPUREG_TEXUNIT0_ADDR2"},
- {0x087, "GPUREG_TEXUNIT0_ADDR3"},
- {0x088, "GPUREG_TEXUNIT0_ADDR4"},
- {0x089, "GPUREG_TEXUNIT0_ADDR5"},
- {0x08A, "GPUREG_TEXUNIT0_ADDR6"},
- {0x08B, "GPUREG_TEXUNIT0_SHADOW"},
-
- {0x08E, "GPUREG_TEXUNIT0_TYPE"},
- {0x08F, "GPUREG_LIGHTING_ENABLE0"},
-
- {0x091, "GPUREG_TEXUNIT1_BORDER_COLOR"},
- {0x092, "GPUREG_TEXUNIT1_DIM"},
- {0x093, "GPUREG_TEXUNIT1_PARAM"},
- {0x094, "GPUREG_TEXUNIT1_LOD"},
- {0x095, "GPUREG_TEXUNIT1_ADDR"},
- {0x096, "GPUREG_TEXUNIT1_TYPE"},
-
- {0x099, "GPUREG_TEXUNIT2_BORDER_COLOR"},
- {0x09A, "GPUREG_TEXUNIT2_DIM"},
- {0x09B, "GPUREG_TEXUNIT2_PARAM"},
- {0x09C, "GPUREG_TEXUNIT2_LOD"},
- {0x09D, "GPUREG_TEXUNIT2_ADDR"},
- {0x09E, "GPUREG_TEXUNIT2_TYPE"},
-
- {0x0A8, "GPUREG_TEXUNIT3_PROCTEX0"},
- {0x0A9, "GPUREG_TEXUNIT3_PROCTEX1"},
- {0x0AA, "GPUREG_TEXUNIT3_PROCTEX2"},
- {0x0AB, "GPUREG_TEXUNIT3_PROCTEX3"},
- {0x0AC, "GPUREG_TEXUNIT3_PROCTEX4"},
- {0x0AD, "GPUREG_TEXUNIT3_PROCTEX5"},
-
- {0x0AF, "GPUREG_PROCTEX_LUT"},
- {0x0B0, "GPUREG_PROCTEX_LUT_DATA0"},
- {0x0B1, "GPUREG_PROCTEX_LUT_DATA1"},
- {0x0B2, "GPUREG_PROCTEX_LUT_DATA2"},
- {0x0B3, "GPUREG_PROCTEX_LUT_DATA3"},
- {0x0B4, "GPUREG_PROCTEX_LUT_DATA4"},
- {0x0B5, "GPUREG_PROCTEX_LUT_DATA5"},
- {0x0B6, "GPUREG_PROCTEX_LUT_DATA6"},
- {0x0B7, "GPUREG_PROCTEX_LUT_DATA7"},
-
- {0x0C0, "GPUREG_TEXENV0_SOURCE"},
- {0x0C1, "GPUREG_TEXENV0_OPERAND"},
- {0x0C2, "GPUREG_TEXENV0_COMBINER"},
- {0x0C3, "GPUREG_TEXENV0_COLOR"},
- {0x0C4, "GPUREG_TEXENV0_SCALE"},
-
- {0x0C8, "GPUREG_TEXENV1_SOURCE"},
- {0x0C9, "GPUREG_TEXENV1_OPERAND"},
- {0x0CA, "GPUREG_TEXENV1_COMBINER"},
- {0x0CB, "GPUREG_TEXENV1_COLOR"},
- {0x0CC, "GPUREG_TEXENV1_SCALE"},
-
- {0x0D0, "GPUREG_TEXENV2_SOURCE"},
- {0x0D1, "GPUREG_TEXENV2_OPERAND"},
- {0x0D2, "GPUREG_TEXENV2_COMBINER"},
- {0x0D3, "GPUREG_TEXENV2_COLOR"},
- {0x0D4, "GPUREG_TEXENV2_SCALE"},
-
- {0x0D8, "GPUREG_TEXENV3_SOURCE"},
- {0x0D9, "GPUREG_TEXENV3_OPERAND"},
- {0x0DA, "GPUREG_TEXENV3_COMBINER"},
- {0x0DB, "GPUREG_TEXENV3_COLOR"},
- {0x0DC, "GPUREG_TEXENV3_SCALE"},
-
- {0x0E0, "GPUREG_TEXENV_UPDATE_BUFFER"},
- {0x0E1, "GPUREG_FOG_COLOR"},
-
- {0x0E4, "GPUREG_GAS_ATTENUATION"},
- {0x0E5, "GPUREG_GAS_ACCMAX"},
- {0x0E6, "GPUREG_FOG_LUT_INDEX"},
-
- {0x0E8, "GPUREG_FOG_LUT_DATA0"},
- {0x0E9, "GPUREG_FOG_LUT_DATA1"},
- {0x0EA, "GPUREG_FOG_LUT_DATA2"},
- {0x0EB, "GPUREG_FOG_LUT_DATA3"},
- {0x0EC, "GPUREG_FOG_LUT_DATA4"},
- {0x0ED, "GPUREG_FOG_LUT_DATA5"},
- {0x0EE, "GPUREG_FOG_LUT_DATA6"},
- {0x0EF, "GPUREG_FOG_LUT_DATA7"},
- {0x0F0, "GPUREG_TEXENV4_SOURCE"},
- {0x0F1, "GPUREG_TEXENV4_OPERAND"},
- {0x0F2, "GPUREG_TEXENV4_COMBINER"},
- {0x0F3, "GPUREG_TEXENV4_COLOR"},
- {0x0F4, "GPUREG_TEXENV4_SCALE"},
-
- {0x0F8, "GPUREG_TEXENV5_SOURCE"},
- {0x0F9, "GPUREG_TEXENV5_OPERAND"},
- {0x0FA, "GPUREG_TEXENV5_COMBINER"},
- {0x0FB, "GPUREG_TEXENV5_COLOR"},
- {0x0FC, "GPUREG_TEXENV5_SCALE"},
- {0x0FD, "GPUREG_TEXENV_BUFFER_COLOR"},
-
- {0x100, "GPUREG_COLOR_OPERATION"},
- {0x101, "GPUREG_BLEND_FUNC"},
- {0x102, "GPUREG_LOGIC_OP"},
- {0x103, "GPUREG_BLEND_COLOR"},
- {0x104, "GPUREG_FRAGOP_ALPHA_TEST"},
- {0x105, "GPUREG_STENCIL_TEST"},
- {0x106, "GPUREG_STENCIL_OP"},
- {0x107, "GPUREG_DEPTH_COLOR_MASK"},
-
- {0x110, "GPUREG_FRAMEBUFFER_INVALIDATE"},
- {0x111, "GPUREG_FRAMEBUFFER_FLUSH"},
- {0x112, "GPUREG_COLORBUFFER_READ"},
- {0x113, "GPUREG_COLORBUFFER_WRITE"},
- {0x114, "GPUREG_DEPTHBUFFER_READ"},
- {0x115, "GPUREG_DEPTHBUFFER_WRITE"},
- {0x116, "GPUREG_DEPTHBUFFER_FORMAT"},
- {0x117, "GPUREG_COLORBUFFER_FORMAT"},
- {0x118, "GPUREG_EARLYDEPTH_TEST2"},
-
- {0x11B, "GPUREG_FRAMEBUFFER_BLOCK32"},
- {0x11C, "GPUREG_DEPTHBUFFER_LOC"},
- {0x11D, "GPUREG_COLORBUFFER_LOC"},
- {0x11E, "GPUREG_FRAMEBUFFER_DIM"},
-
- {0x120, "GPUREG_GAS_LIGHT_XY"},
- {0x121, "GPUREG_GAS_LIGHT_Z"},
- {0x122, "GPUREG_GAS_LIGHT_Z_COLOR"},
- {0x123, "GPUREG_GAS_LUT_INDEX"},
- {0x124, "GPUREG_GAS_LUT_DATA"},
-
- {0x126, "GPUREG_GAS_DELTAZ_DEPTH"},
-
- {0x130, "GPUREG_FRAGOP_SHADOW"},
-
- {0x140, "GPUREG_LIGHT0_SPECULAR0"},
- {0x141, "GPUREG_LIGHT0_SPECULAR1"},
- {0x142, "GPUREG_LIGHT0_DIFFUSE"},
- {0x143, "GPUREG_LIGHT0_AMBIENT"},
- {0x144, "GPUREG_LIGHT0_XY"},
- {0x145, "GPUREG_LIGHT0_Z"},
- {0x146, "GPUREG_LIGHT0_SPOTDIR_XY"},
- {0x147, "GPUREG_LIGHT0_SPOTDIR_Z"},
-
- {0x149, "GPUREG_LIGHT0_CONFIG"},
- {0x14A, "GPUREG_LIGHT0_ATTENUATION_BIAS"},
- {0x14B, "GPUREG_LIGHT0_ATTENUATION_SCALE"},
-
- {0x150, "GPUREG_LIGHT1_SPECULAR0"},
- {0x151, "GPUREG_LIGHT1_SPECULAR1"},
- {0x152, "GPUREG_LIGHT1_DIFFUSE"},
- {0x153, "GPUREG_LIGHT1_AMBIENT"},
- {0x154, "GPUREG_LIGHT1_XY"},
- {0x155, "GPUREG_LIGHT1_Z"},
- {0x156, "GPUREG_LIGHT1_SPOTDIR_XY"},
- {0x157, "GPUREG_LIGHT1_SPOTDIR_Z"},
-
- {0x159, "GPUREG_LIGHT1_CONFIG"},
- {0x15A, "GPUREG_LIGHT1_ATTENUATION_BIAS"},
- {0x15B, "GPUREG_LIGHT1_ATTENUATION_SCALE"},
-
- {0x160, "GPUREG_LIGHT2_SPECULAR0"},
- {0x161, "GPUREG_LIGHT2_SPECULAR1"},
- {0x162, "GPUREG_LIGHT2_DIFFUSE"},
- {0x163, "GPUREG_LIGHT2_AMBIENT"},
- {0x164, "GPUREG_LIGHT2_XY"},
- {0x165, "GPUREG_LIGHT2_Z"},
- {0x166, "GPUREG_LIGHT2_SPOTDIR_XY"},
- {0x167, "GPUREG_LIGHT2_SPOTDIR_Z"},
-
- {0x169, "GPUREG_LIGHT2_CONFIG"},
- {0x16A, "GPUREG_LIGHT2_ATTENUATION_BIAS"},
- {0x16B, "GPUREG_LIGHT2_ATTENUATION_SCALE"},
-
- {0x170, "GPUREG_LIGHT3_SPECULAR0"},
- {0x171, "GPUREG_LIGHT3_SPECULAR1"},
- {0x172, "GPUREG_LIGHT3_DIFFUSE"},
- {0x173, "GPUREG_LIGHT3_AMBIENT"},
- {0x174, "GPUREG_LIGHT3_XY"},
- {0x175, "GPUREG_LIGHT3_Z"},
- {0x176, "GPUREG_LIGHT3_SPOTDIR_XY"},
- {0x177, "GPUREG_LIGHT3_SPOTDIR_Z"},
-
- {0x179, "GPUREG_LIGHT3_CONFIG"},
- {0x17A, "GPUREG_LIGHT3_ATTENUATION_BIAS"},
- {0x17B, "GPUREG_LIGHT3_ATTENUATION_SCALE"},
-
- {0x180, "GPUREG_LIGHT4_SPECULAR0"},
- {0x181, "GPUREG_LIGHT4_SPECULAR1"},
- {0x182, "GPUREG_LIGHT4_DIFFUSE"},
- {0x183, "GPUREG_LIGHT4_AMBIENT"},
- {0x184, "GPUREG_LIGHT4_XY"},
- {0x185, "GPUREG_LIGHT4_Z"},
- {0x186, "GPUREG_LIGHT4_SPOTDIR_XY"},
- {0x187, "GPUREG_LIGHT4_SPOTDIR_Z"},
-
- {0x189, "GPUREG_LIGHT4_CONFIG"},
- {0x18A, "GPUREG_LIGHT4_ATTENUATION_BIAS"},
- {0x18B, "GPUREG_LIGHT4_ATTENUATION_SCALE"},
-
- {0x190, "GPUREG_LIGHT5_SPECULAR0"},
- {0x191, "GPUREG_LIGHT5_SPECULAR1"},
- {0x192, "GPUREG_LIGHT5_DIFFUSE"},
- {0x193, "GPUREG_LIGHT5_AMBIENT"},
- {0x194, "GPUREG_LIGHT5_XY"},
- {0x195, "GPUREG_LIGHT5_Z"},
- {0x196, "GPUREG_LIGHT5_SPOTDIR_XY"},
- {0x197, "GPUREG_LIGHT5_SPOTDIR_Z"},
-
- {0x199, "GPUREG_LIGHT5_CONFIG"},
- {0x19A, "GPUREG_LIGHT5_ATTENUATION_BIAS"},
- {0x19B, "GPUREG_LIGHT5_ATTENUATION_SCALE"},
-
- {0x1A0, "GPUREG_LIGHT6_SPECULAR0"},
- {0x1A1, "GPUREG_LIGHT6_SPECULAR1"},
- {0x1A2, "GPUREG_LIGHT6_DIFFUSE"},
- {0x1A3, "GPUREG_LIGHT6_AMBIENT"},
- {0x1A4, "GPUREG_LIGHT6_XY"},
- {0x1A5, "GPUREG_LIGHT6_Z"},
- {0x1A6, "GPUREG_LIGHT6_SPOTDIR_XY"},
- {0x1A7, "GPUREG_LIGHT6_SPOTDIR_Z"},
-
- {0x1A9, "GPUREG_LIGHT6_CONFIG"},
- {0x1AA, "GPUREG_LIGHT6_ATTENUATION_BIAS"},
- {0x1AB, "GPUREG_LIGHT6_ATTENUATION_SCALE"},
-
- {0x1B0, "GPUREG_LIGHT7_SPECULAR0"},
- {0x1B1, "GPUREG_LIGHT7_SPECULAR1"},
- {0x1B2, "GPUREG_LIGHT7_DIFFUSE"},
- {0x1B3, "GPUREG_LIGHT7_AMBIENT"},
- {0x1B4, "GPUREG_LIGHT7_XY"},
- {0x1B5, "GPUREG_LIGHT7_Z"},
- {0x1B6, "GPUREG_LIGHT7_SPOTDIR_XY"},
- {0x1B7, "GPUREG_LIGHT7_SPOTDIR_Z"},
-
- {0x1B9, "GPUREG_LIGHT7_CONFIG"},
- {0x1BA, "GPUREG_LIGHT7_ATTENUATION_BIAS"},
- {0x1BB, "GPUREG_LIGHT7_ATTENUATION_SCALE"},
-
- {0x1C0, "GPUREG_LIGHTING_AMBIENT"},
-
- {0x1C2, "GPUREG_LIGHTING_NUM_LIGHTS"},
- {0x1C3, "GPUREG_LIGHTING_CONFIG0"},
- {0x1C4, "GPUREG_LIGHTING_CONFIG1"},
- {0x1C5, "GPUREG_LIGHTING_LUT_INDEX"},
- {0x1C6, "GPUREG_LIGHTING_ENABLE1"},
-
- {0x1C8, "GPUREG_LIGHTING_LUT_DATA0"},
- {0x1C9, "GPUREG_LIGHTING_LUT_DATA1"},
- {0x1CA, "GPUREG_LIGHTING_LUT_DATA2"},
- {0x1CB, "GPUREG_LIGHTING_LUT_DATA3"},
- {0x1CC, "GPUREG_LIGHTING_LUT_DATA4"},
- {0x1CD, "GPUREG_LIGHTING_LUT_DATA5"},
- {0x1CE, "GPUREG_LIGHTING_LUT_DATA6"},
- {0x1CF, "GPUREG_LIGHTING_LUT_DATA7"},
- {0x1D0, "GPUREG_LIGHTING_LUTINPUT_ABS"},
- {0x1D1, "GPUREG_LIGHTING_LUTINPUT_SELECT"},
- {0x1D2, "GPUREG_LIGHTING_LUTINPUT_SCALE"},
-
- {0x1D9, "GPUREG_LIGHTING_LIGHT_PERMUTATION"},
-
- {0x200, "GPUREG_ATTRIBBUFFERS_LOC"},
- {0x201, "GPUREG_ATTRIBBUFFERS_FORMAT_LOW"},
- {0x202, "GPUREG_ATTRIBBUFFERS_FORMAT_HIGH"},
- {0x203, "GPUREG_ATTRIBBUFFER0_OFFSET"},
- {0x204, "GPUREG_ATTRIBBUFFER0_CONFIG1"},
- {0x205, "GPUREG_ATTRIBBUFFER0_CONFIG2"},
- {0x206, "GPUREG_ATTRIBBUFFER1_OFFSET"},
- {0x207, "GPUREG_ATTRIBBUFFER1_CONFIG1"},
- {0x208, "GPUREG_ATTRIBBUFFER1_CONFIG2"},
- {0x209, "GPUREG_ATTRIBBUFFER2_OFFSET"},
- {0x20A, "GPUREG_ATTRIBBUFFER2_CONFIG1"},
- {0x20B, "GPUREG_ATTRIBBUFFER2_CONFIG2"},
- {0x20C, "GPUREG_ATTRIBBUFFER3_OFFSET"},
- {0x20D, "GPUREG_ATTRIBBUFFER3_CONFIG1"},
- {0x20E, "GPUREG_ATTRIBBUFFER3_CONFIG2"},
- {0x20F, "GPUREG_ATTRIBBUFFER4_OFFSET"},
- {0x210, "GPUREG_ATTRIBBUFFER4_CONFIG1"},
- {0x211, "GPUREG_ATTRIBBUFFER4_CONFIG2"},
- {0x212, "GPUREG_ATTRIBBUFFER5_OFFSET"},
- {0x213, "GPUREG_ATTRIBBUFFER5_CONFIG1"},
- {0x214, "GPUREG_ATTRIBBUFFER5_CONFIG2"},
- {0x215, "GPUREG_ATTRIBBUFFER6_OFFSET"},
- {0x216, "GPUREG_ATTRIBBUFFER6_CONFIG1"},
- {0x217, "GPUREG_ATTRIBBUFFER6_CONFIG2"},
- {0x218, "GPUREG_ATTRIBBUFFER7_OFFSET"},
- {0x219, "GPUREG_ATTRIBBUFFER7_CONFIG1"},
- {0x21A, "GPUREG_ATTRIBBUFFER7_CONFIG2"},
- {0x21B, "GPUREG_ATTRIBBUFFER8_OFFSET"},
- {0x21C, "GPUREG_ATTRIBBUFFER8_CONFIG1"},
- {0x21D, "GPUREG_ATTRIBBUFFER8_CONFIG2"},
- {0x21E, "GPUREG_ATTRIBBUFFER9_OFFSET"},
- {0x21F, "GPUREG_ATTRIBBUFFER9_CONFIG1"},
- {0x220, "GPUREG_ATTRIBBUFFER9_CONFIG2"},
- {0x221, "GPUREG_ATTRIBBUFFER10_OFFSET"},
- {0x222, "GPUREG_ATTRIBBUFFER10_CONFIG1"},
- {0x223, "GPUREG_ATTRIBBUFFER10_CONFIG2"},
- {0x224, "GPUREG_ATTRIBBUFFER11_OFFSET"},
- {0x225, "GPUREG_ATTRIBBUFFER11_CONFIG1"},
- {0x226, "GPUREG_ATTRIBBUFFER11_CONFIG2"},
- {0x227, "GPUREG_INDEXBUFFER_CONFIG"},
- {0x228, "GPUREG_NUMVERTICES"},
- {0x229, "GPUREG_GEOSTAGE_CONFIG"},
- {0x22A, "GPUREG_VERTEX_OFFSET"},
-
- {0x22D, "GPUREG_POST_VERTEX_CACHE_NUM"},
- {0x22E, "GPUREG_DRAWARRAYS"},
- {0x22F, "GPUREG_DRAWELEMENTS"},
-
- {0x231, "GPUREG_VTX_FUNC"},
- {0x232, "GPUREG_FIXEDATTRIB_INDEX"},
- {0x233, "GPUREG_FIXEDATTRIB_DATA0"},
- {0x234, "GPUREG_FIXEDATTRIB_DATA1"},
- {0x235, "GPUREG_FIXEDATTRIB_DATA2"},
-
- {0x238, "GPUREG_CMDBUF_SIZE0"},
- {0x239, "GPUREG_CMDBUF_SIZE1"},
- {0x23A, "GPUREG_CMDBUF_ADDR0"},
- {0x23B, "GPUREG_CMDBUF_ADDR1"},
- {0x23C, "GPUREG_CMDBUF_JUMP0"},
- {0x23D, "GPUREG_CMDBUF_JUMP1"},
-
- {0x242, "GPUREG_VSH_NUM_ATTR"},
-
- {0x244, "GPUREG_VSH_COM_MODE"},
- {0x245, "GPUREG_START_DRAW_FUNC0"},
-
- {0x24A, "GPUREG_VSH_OUTMAP_TOTAL1"},
-
- {0x251, "GPUREG_VSH_OUTMAP_TOTAL2"},
- {0x252, "GPUREG_GSH_MISC0"},
- {0x253, "GPUREG_GEOSTAGE_CONFIG2"},
- {0x254, "GPUREG_GSH_MISC1"},
-
- {0x25E, "GPUREG_PRIMITIVE_CONFIG"},
- {0x25F, "GPUREG_RESTART_PRIMITIVE"},
-
- {0x280, "GPUREG_GSH_BOOLUNIFORM"},
- {0x281, "GPUREG_GSH_INTUNIFORM_I0"},
- {0x282, "GPUREG_GSH_INTUNIFORM_I1"},
- {0x283, "GPUREG_GSH_INTUNIFORM_I2"},
- {0x284, "GPUREG_GSH_INTUNIFORM_I3"},
-
- {0x289, "GPUREG_GSH_INPUTBUFFER_CONFIG"},
- {0x28A, "GPUREG_GSH_ENTRYPOINT"},
- {0x28B, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_LOW"},
- {0x28C, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_HIGH"},
- {0x28D, "GPUREG_GSH_OUTMAP_MASK"},
-
- {0x28F, "GPUREG_GSH_CODETRANSFER_END"},
- {0x290, "GPUREG_GSH_FLOATUNIFORM_INDEX"},
- {0x291, "GPUREG_GSH_FLOATUNIFORM_DATA0"},
- {0x292, "GPUREG_GSH_FLOATUNIFORM_DATA1"},
- {0x293, "GPUREG_GSH_FLOATUNIFORM_DATA2"},
- {0x294, "GPUREG_GSH_FLOATUNIFORM_DATA3"},
- {0x295, "GPUREG_GSH_FLOATUNIFORM_DATA4"},
- {0x296, "GPUREG_GSH_FLOATUNIFORM_DATA5"},
- {0x297, "GPUREG_GSH_FLOATUNIFORM_DATA6"},
- {0x298, "GPUREG_GSH_FLOATUNIFORM_DATA7"},
-
- {0x29B, "GPUREG_GSH_CODETRANSFER_INDEX"},
- {0x29C, "GPUREG_GSH_CODETRANSFER_DATA0"},
- {0x29D, "GPUREG_GSH_CODETRANSFER_DATA1"},
- {0x29E, "GPUREG_GSH_CODETRANSFER_DATA2"},
- {0x29F, "GPUREG_GSH_CODETRANSFER_DATA3"},
- {0x2A0, "GPUREG_GSH_CODETRANSFER_DATA4"},
- {0x2A1, "GPUREG_GSH_CODETRANSFER_DATA5"},
- {0x2A2, "GPUREG_GSH_CODETRANSFER_DATA6"},
- {0x2A3, "GPUREG_GSH_CODETRANSFER_DATA7"},
-
- {0x2A5, "GPUREG_GSH_OPDESCS_INDEX"},
- {0x2A6, "GPUREG_GSH_OPDESCS_DATA0"},
- {0x2A7, "GPUREG_GSH_OPDESCS_DATA1"},
- {0x2A8, "GPUREG_GSH_OPDESCS_DATA2"},
- {0x2A9, "GPUREG_GSH_OPDESCS_DATA3"},
- {0x2AA, "GPUREG_GSH_OPDESCS_DATA4"},
- {0x2AB, "GPUREG_GSH_OPDESCS_DATA5"},
- {0x2AC, "GPUREG_GSH_OPDESCS_DATA6"},
- {0x2AD, "GPUREG_GSH_OPDESCS_DATA7"},
-
- {0x2B0, "GPUREG_VSH_BOOLUNIFORM"},
- {0x2B1, "GPUREG_VSH_INTUNIFORM_I0"},
- {0x2B2, "GPUREG_VSH_INTUNIFORM_I1"},
- {0x2B3, "GPUREG_VSH_INTUNIFORM_I2"},
- {0x2B4, "GPUREG_VSH_INTUNIFORM_I3"},
-
- {0x2B9, "GPUREG_VSH_INPUTBUFFER_CONFIG"},
- {0x2BA, "GPUREG_VSH_ENTRYPOINT"},
- {0x2BB, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW"},
- {0x2BC, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_HIGH"},
- {0x2BD, "GPUREG_VSH_OUTMAP_MASK"},
-
- {0x2BF, "GPUREG_VSH_CODETRANSFER_END"},
- {0x2C0, "GPUREG_VSH_FLOATUNIFORM_INDEX"},
- {0x2C1, "GPUREG_VSH_FLOATUNIFORM_DATA0"},
- {0x2C2, "GPUREG_VSH_FLOATUNIFORM_DATA1"},
- {0x2C3, "GPUREG_VSH_FLOATUNIFORM_DATA2"},
- {0x2C4, "GPUREG_VSH_FLOATUNIFORM_DATA3"},
- {0x2C5, "GPUREG_VSH_FLOATUNIFORM_DATA4"},
- {0x2C6, "GPUREG_VSH_FLOATUNIFORM_DATA5"},
- {0x2C7, "GPUREG_VSH_FLOATUNIFORM_DATA6"},
- {0x2C8, "GPUREG_VSH_FLOATUNIFORM_DATA7"},
-
- {0x2CB, "GPUREG_VSH_CODETRANSFER_INDEX"},
- {0x2CC, "GPUREG_VSH_CODETRANSFER_DATA0"},
- {0x2CD, "GPUREG_VSH_CODETRANSFER_DATA1"},
- {0x2CE, "GPUREG_VSH_CODETRANSFER_DATA2"},
- {0x2CF, "GPUREG_VSH_CODETRANSFER_DATA3"},
- {0x2D0, "GPUREG_VSH_CODETRANSFER_DATA4"},
- {0x2D1, "GPUREG_VSH_CODETRANSFER_DATA5"},
- {0x2D2, "GPUREG_VSH_CODETRANSFER_DATA6"},
- {0x2D3, "GPUREG_VSH_CODETRANSFER_DATA7"},
-
- {0x2D5, "GPUREG_VSH_OPDESCS_INDEX"},
- {0x2D6, "GPUREG_VSH_OPDESCS_DATA0"},
- {0x2D7, "GPUREG_VSH_OPDESCS_DATA1"},
- {0x2D8, "GPUREG_VSH_OPDESCS_DATA2"},
- {0x2D9, "GPUREG_VSH_OPDESCS_DATA3"},
- {0x2DA, "GPUREG_VSH_OPDESCS_DATA4"},
- {0x2DB, "GPUREG_VSH_OPDESCS_DATA5"},
- {0x2DC, "GPUREG_VSH_OPDESCS_DATA6"},
- {0x2DD, "GPUREG_VSH_OPDESCS_DATA7"},
-};
-
-std::string Regs::GetCommandName(int index) {
- static std::unordered_map<u32, const char*> map;
-
- if (map.empty()) {
- map.insert(std::begin(register_names), std::end(register_names));
- }
-
- // Return empty string if no match is found
- auto it = map.find(index);
- if (it != map.end()) {
- return it->second;
- } else {
- return std::string();
- }
-}
-
void Init() {
g_state.Reset();
}
@@ -513,6 +30,6 @@ void State::Reset() {
Zero(gs);
Zero(cmd_list);
Zero(immediate);
- primitive_assembler.Reconfigure(Regs::TriangleTopology::List);
+ primitive_assembler.Reconfigure(PipelineRegs::TriangleTopology::List);
}
}
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 @@
#pragma once
-#include <array>
-#include <cstddef>
-#include <string>
-
-#ifndef _MSC_VER
-#include <type_traits> // for std::enable_if
-#endif
-
-#include "common/assert.h"
-#include "common/bit_field.h"
-#include "common/common_funcs.h"
-#include "common/common_types.h"
-#include "common/logging/log.h"
-#include "common/vector_math.h"
-
+#include "video_core/regs_texturing.h"
namespace Pica {
-// Returns index corresponding to the Regs member labeled by field_name
-// TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions
-// when used with array elements (e.g. PICA_REG_INDEX(vs_uniform_setup.set_value[1])).
-// For details cf.
-// https://connect.microsoft.com/VisualStudio/feedback/details/209229/offsetof-does-not-produce-a-constant-expression-for-array-members
-// Hopefully, this will be fixed sometime in the future.
-// For lack of better alternatives, we currently hardcode the offsets when constant
-// expressions are needed via PICA_REG_INDEX_WORKAROUND (on sane compilers, static_asserts
-// will then make sure the offsets indeed match the automatically calculated ones).
-#define PICA_REG_INDEX(field_name) (offsetof(Pica::Regs, field_name) / sizeof(u32))
-#if defined(_MSC_VER)
-#define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) (backup_workaround_index)
-#else
-// NOTE: Yeah, hacking in a static_assert here just to workaround the lacking MSVC compiler
-// really is this annoying. This macro just forwards its first argument to PICA_REG_INDEX
-// and then performs a (no-op) cast to size_t iff the second argument matches the expected
-// field offset. Otherwise, the compiler will fail to compile this code.
-#define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) \
- ((typename std::enable_if<backup_workaround_index == PICA_REG_INDEX(field_name), \
- size_t>::type)PICA_REG_INDEX(field_name))
-#endif // _MSC_VER
-
-struct Regs {
-
- INSERT_PADDING_WORDS(0x10);
-
- u32 trigger_irq;
-
- INSERT_PADDING_WORDS(0x2f);
-
- enum class CullMode : u32 {
- // Select which polygons are considered to be "frontfacing".
- KeepAll = 0,
- KeepClockWise = 1,
- KeepCounterClockWise = 2,
- // TODO: What does the third value imply?
- };
-
- union {
- BitField<0, 2, CullMode> cull_mode;
- };
-
- BitField<0, 24, u32> viewport_size_x;
-
- INSERT_PADDING_WORDS(0x1);
-
- BitField<0, 24, u32> viewport_size_y;
-
- INSERT_PADDING_WORDS(0x9);
-
- BitField<0, 24, u32> viewport_depth_range; // float24
- BitField<0, 24, u32> viewport_depth_near_plane; // float24
-
- BitField<0, 3, u32> vs_output_total;
-
- union VSOutputAttributes {
- // Maps components of output vertex attributes to semantics
- enum Semantic : u32 {
- POSITION_X = 0,
- POSITION_Y = 1,
- POSITION_Z = 2,
- POSITION_W = 3,
-
- QUATERNION_X = 4,
- QUATERNION_Y = 5,
- QUATERNION_Z = 6,
- QUATERNION_W = 7,
-
- COLOR_R = 8,
- COLOR_G = 9,
- COLOR_B = 10,
- COLOR_A = 11,
-
- TEXCOORD0_U = 12,
- TEXCOORD0_V = 13,
- TEXCOORD1_U = 14,
- TEXCOORD1_V = 15,
-
- TEXCOORD0_W = 16,
-
- VIEW_X = 18,
- VIEW_Y = 19,
- VIEW_Z = 20,
-
- TEXCOORD2_U = 22,
- TEXCOORD2_V = 23,
-
- INVALID = 31,
- };
-
- BitField<0, 5, Semantic> map_x;
- BitField<8, 5, Semantic> map_y;
- BitField<16, 5, Semantic> map_z;
- BitField<24, 5, Semantic> map_w;
- } vs_output_attributes[7];
-
- INSERT_PADDING_WORDS(0xe);
-
- enum class ScissorMode : u32 {
- Disabled = 0,
- Exclude = 1, // Exclude pixels inside the scissor box
-
- Include = 3 // Exclude pixels outside the scissor box
- };
-
- struct {
- BitField<0, 2, ScissorMode> mode;
-
- union {
- BitField<0, 16, u32> x1;
- BitField<16, 16, u32> y1;
- };
-
- union {
- BitField<0, 16, u32> x2;
- BitField<16, 16, u32> y2;
- };
- } scissor_test;
-
- union {
- BitField<0, 10, s32> x;
- BitField<16, 10, s32> y;
- } viewport_corner;
-
- INSERT_PADDING_WORDS(0x1);
-
- // TODO: early depth
- INSERT_PADDING_WORDS(0x1);
-
- INSERT_PADDING_WORDS(0x2);
-
- enum DepthBuffering : u32 {
- WBuffering = 0,
- ZBuffering = 1,
- };
- BitField<0, 1, DepthBuffering> depthmap_enable;
-
- INSERT_PADDING_WORDS(0x12);
-
- struct TextureConfig {
- enum TextureType : u32 {
- Texture2D = 0,
- TextureCube = 1,
- Shadow2D = 2,
- Projection2D = 3,
- ShadowCube = 4,
- Disabled = 5,
- };
-
- enum WrapMode : u32 {
- ClampToEdge = 0,
- ClampToBorder = 1,
- Repeat = 2,
- MirroredRepeat = 3,
- };
-
- enum TextureFilter : u32 {
- Nearest = 0,
- Linear = 1,
- };
-
- union {
- u32 raw;
- BitField<0, 8, u32> r;
- BitField<8, 8, u32> g;
- BitField<16, 8, u32> b;
- BitField<24, 8, u32> a;
- } border_color;
-
- union {
- BitField<0, 16, u32> height;
- BitField<16, 16, u32> width;
- };
-
- union {
- BitField<1, 1, TextureFilter> mag_filter;
- BitField<2, 1, TextureFilter> min_filter;
- BitField<8, 2, WrapMode> wrap_t;
- BitField<12, 2, WrapMode> wrap_s;
- BitField<28, 2, TextureType>
- type; ///< @note Only valid for texture 0 according to 3DBrew.
- };
-
- INSERT_PADDING_WORDS(0x1);
-
- u32 address;
-
- u32 GetPhysicalAddress() const {
- return DecodeAddressRegister(address);
- }
-
- // texture1 and texture2 store the texture format directly after the address
- // whereas texture0 inserts some additional flags inbetween.
- // Hence, we store the format separately so that all other parameters can be described
- // in a single structure.
- };
-
- enum class TextureFormat : u32 {
- RGBA8 = 0,
- RGB8 = 1,
- RGB5A1 = 2,
- RGB565 = 3,
- RGBA4 = 4,
- IA8 = 5,
- RG8 = 6, ///< @note Also called HILO8 in 3DBrew.
- I8 = 7,
- A8 = 8,
- IA4 = 9,
- I4 = 10,
- A4 = 11,
- ETC1 = 12, // compressed
- ETC1A4 = 13, // compressed
- };
-
- enum class LogicOp : u32 {
- Clear = 0,
- And = 1,
- AndReverse = 2,
- Copy = 3,
- Set = 4,
- CopyInverted = 5,
- NoOp = 6,
- Invert = 7,
- Nand = 8,
- Or = 9,
- Nor = 10,
- Xor = 11,
- Equiv = 12,
- AndInverted = 13,
- OrReverse = 14,
- OrInverted = 15,
- };
-
- static unsigned NibblesPerPixel(TextureFormat format) {
- switch (format) {
- case TextureFormat::RGBA8:
- return 8;
-
- case TextureFormat::RGB8:
- return 6;
-
- case TextureFormat::RGB5A1:
- case TextureFormat::RGB565:
- case TextureFormat::RGBA4:
- case TextureFormat::IA8:
- case TextureFormat::RG8:
- return 4;
-
- case TextureFormat::I4:
- case TextureFormat::A4:
- return 1;
-
- case TextureFormat::I8:
- case TextureFormat::A8:
- case TextureFormat::IA4:
- return 2;
-
- default: // placeholder for yet unknown formats
- UNIMPLEMENTED();
- return 0;
- }
- }
-
- union {
- BitField<0, 1, u32> texture0_enable;
- BitField<1, 1, u32> texture1_enable;
- BitField<2, 1, u32> texture2_enable;
- };
- TextureConfig texture0;
- INSERT_PADDING_WORDS(0x8);
- BitField<0, 4, TextureFormat> texture0_format;
- BitField<0, 1, u32> fragment_lighting_enable;
- INSERT_PADDING_WORDS(0x1);
- TextureConfig texture1;
- BitField<0, 4, TextureFormat> texture1_format;
- INSERT_PADDING_WORDS(0x2);
- TextureConfig texture2;
- BitField<0, 4, TextureFormat> texture2_format;
- INSERT_PADDING_WORDS(0x21);
-
- struct FullTextureConfig {
- const bool enabled;
- const TextureConfig config;
- const TextureFormat format;
- };
- const std::array<FullTextureConfig, 3> GetTextures() const {
- return {{
- {texture0_enable.ToBool(), texture0, texture0_format},
- {texture1_enable.ToBool(), texture1, texture1_format},
- {texture2_enable.ToBool(), texture2, texture2_format},
- }};
- }
-
- // 0xc0-0xff: Texture Combiner (akin to glTexEnv)
- struct TevStageConfig {
- enum class Source : u32 {
- PrimaryColor = 0x0,
- PrimaryFragmentColor = 0x1,
- SecondaryFragmentColor = 0x2,
-
- Texture0 = 0x3,
- Texture1 = 0x4,
- Texture2 = 0x5,
- Texture3 = 0x6,
-
- PreviousBuffer = 0xd,
- Constant = 0xe,
- Previous = 0xf,
- };
-
- enum class ColorModifier : u32 {
- SourceColor = 0x0,
- OneMinusSourceColor = 0x1,
- SourceAlpha = 0x2,
- OneMinusSourceAlpha = 0x3,
- SourceRed = 0x4,
- OneMinusSourceRed = 0x5,
-
- SourceGreen = 0x8,
- OneMinusSourceGreen = 0x9,
-
- SourceBlue = 0xc,
- OneMinusSourceBlue = 0xd,
- };
-
- enum class AlphaModifier : u32 {
- SourceAlpha = 0x0,
- OneMinusSourceAlpha = 0x1,
- SourceRed = 0x2,
- OneMinusSourceRed = 0x3,
- SourceGreen = 0x4,
- OneMinusSourceGreen = 0x5,
- SourceBlue = 0x6,
- OneMinusSourceBlue = 0x7,
- };
-
- enum class Operation : u32 {
- Replace = 0,
- Modulate = 1,
- Add = 2,
- AddSigned = 3,
- Lerp = 4,
- Subtract = 5,
- Dot3_RGB = 6,
-
- MultiplyThenAdd = 8,
- AddThenMultiply = 9,
- };
-
- union {
- u32 sources_raw;
- BitField<0, 4, Source> color_source1;
- BitField<4, 4, Source> color_source2;
- BitField<8, 4, Source> color_source3;
- BitField<16, 4, Source> alpha_source1;
- BitField<20, 4, Source> alpha_source2;
- BitField<24, 4, Source> alpha_source3;
- };
-
- union {
- u32 modifiers_raw;
- BitField<0, 4, ColorModifier> color_modifier1;
- BitField<4, 4, ColorModifier> color_modifier2;
- BitField<8, 4, ColorModifier> color_modifier3;
- BitField<12, 3, AlphaModifier> alpha_modifier1;
- BitField<16, 3, AlphaModifier> alpha_modifier2;
- BitField<20, 3, AlphaModifier> alpha_modifier3;
- };
-
- union {
- u32 ops_raw;
- BitField<0, 4, Operation> color_op;
- BitField<16, 4, Operation> alpha_op;
- };
-
- union {
- u32 const_color;
- BitField<0, 8, u32> const_r;
- BitField<8, 8, u32> const_g;
- BitField<16, 8, u32> const_b;
- BitField<24, 8, u32> const_a;
- };
-
- union {
- u32 scales_raw;
- BitField<0, 2, u32> color_scale;
- BitField<16, 2, u32> alpha_scale;
- };
-
- inline unsigned GetColorMultiplier() const {
- return (color_scale < 3) ? (1 << color_scale) : 1;
- }
-
- inline unsigned GetAlphaMultiplier() const {
- return (alpha_scale < 3) ? (1 << alpha_scale) : 1;
- }
- };
-
- TevStageConfig tev_stage0;
- INSERT_PADDING_WORDS(0x3);
- TevStageConfig tev_stage1;
- INSERT_PADDING_WORDS(0x3);
- TevStageConfig tev_stage2;
- INSERT_PADDING_WORDS(0x3);
- TevStageConfig tev_stage3;
- INSERT_PADDING_WORDS(0x3);
-
- enum class FogMode : u32 {
- None = 0,
- Fog = 5,
- Gas = 7,
- };
-
- union {
- BitField<0, 3, FogMode> fog_mode;
- BitField<16, 1, u32> fog_flip;
-
- union {
- // Tev stages 0-3 write their output to the combiner buffer if the corresponding bit in
- // these masks are set
- BitField<8, 4, u32> update_mask_rgb;
- BitField<12, 4, u32> update_mask_a;
-
- bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const {
- return (stage_index < 4) && (update_mask_rgb & (1 << stage_index));
- }
-
- bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const {
- return (stage_index < 4) && (update_mask_a & (1 << stage_index));
- }
- } tev_combiner_buffer_input;
- };
-
- union {
- u32 raw;
- BitField<0, 8, u32> r;
- BitField<8, 8, u32> g;
- BitField<16, 8, u32> b;
- } fog_color;
-
- INSERT_PADDING_WORDS(0x4);
-
- BitField<0, 16, u32> fog_lut_offset;
-
- INSERT_PADDING_WORDS(0x1);
-
- u32 fog_lut_data[8];
-
- TevStageConfig tev_stage4;
- INSERT_PADDING_WORDS(0x3);
- TevStageConfig tev_stage5;
-
- union {
- u32 raw;
- BitField<0, 8, u32> r;
- BitField<8, 8, u32> g;
- BitField<16, 8, u32> b;
- BitField<24, 8, u32> a;
- } tev_combiner_buffer_color;
-
- INSERT_PADDING_WORDS(0x2);
-
- const std::array<Regs::TevStageConfig, 6> GetTevStages() const {
- return {{tev_stage0, tev_stage1, tev_stage2, tev_stage3, tev_stage4, tev_stage5}};
- };
-
- enum class BlendEquation : u32 {
- Add = 0,
- Subtract = 1,
- ReverseSubtract = 2,
- Min = 3,
- Max = 4,
- };
-
- enum class BlendFactor : u32 {
- Zero = 0,
- One = 1,
- SourceColor = 2,
- OneMinusSourceColor = 3,
- DestColor = 4,
- OneMinusDestColor = 5,
- SourceAlpha = 6,
- OneMinusSourceAlpha = 7,
- DestAlpha = 8,
- OneMinusDestAlpha = 9,
- ConstantColor = 10,
- OneMinusConstantColor = 11,
- ConstantAlpha = 12,
- OneMinusConstantAlpha = 13,
- SourceAlphaSaturate = 14,
- };
-
- enum class CompareFunc : u32 {
- Never = 0,
- Always = 1,
- Equal = 2,
- NotEqual = 3,
- LessThan = 4,
- LessThanOrEqual = 5,
- GreaterThan = 6,
- GreaterThanOrEqual = 7,
- };
-
- enum class StencilAction : u32 {
- Keep = 0,
- Zero = 1,
- Replace = 2,
- Increment = 3,
- Decrement = 4,
- Invert = 5,
- IncrementWrap = 6,
- DecrementWrap = 7,
- };
-
- struct {
- union {
- // If false, logic blending is used
- BitField<8, 1, u32> alphablend_enable;
- };
-
- union {
- BitField<0, 8, BlendEquation> blend_equation_rgb;
- BitField<8, 8, BlendEquation> blend_equation_a;
-
- BitField<16, 4, BlendFactor> factor_source_rgb;
- BitField<20, 4, BlendFactor> factor_dest_rgb;
-
- BitField<24, 4, BlendFactor> factor_source_a;
- BitField<28, 4, BlendFactor> factor_dest_a;
- } alpha_blending;
-
- union {
- BitField<0, 4, LogicOp> logic_op;
- };
-
- union {
- u32 raw;
- BitField<0, 8, u32> r;
- BitField<8, 8, u32> g;
- BitField<16, 8, u32> b;
- BitField<24, 8, u32> a;
- } blend_const;
-
- union {
- BitField<0, 1, u32> enable;
- BitField<4, 3, CompareFunc> func;
- BitField<8, 8, u32> ref;
- } alpha_test;
-
- struct {
- union {
- // Raw value of this register
- u32 raw_func;
-
- // If true, enable stencil testing
- BitField<0, 1, u32> enable;
-
- // Comparison operation for stencil testing
- BitField<4, 3, CompareFunc> func;
-
- // Mask used to control writing to the stencil buffer
- BitField<8, 8, u32> write_mask;
-
- // Value to compare against for stencil testing
- BitField<16, 8, u32> reference_value;
-
- // Mask to apply on stencil test inputs
- BitField<24, 8, u32> input_mask;
- };
-
- union {
- // Raw value of this register
- u32 raw_op;
-
- // Action to perform when the stencil test fails
- BitField<0, 3, StencilAction> action_stencil_fail;
-
- // Action to perform when stencil testing passed but depth testing fails
- BitField<4, 3, StencilAction> action_depth_fail;
-
- // Action to perform when both stencil and depth testing pass
- BitField<8, 3, StencilAction> action_depth_pass;
- };
- } stencil_test;
-
- union {
- BitField<0, 1, u32> depth_test_enable;
- BitField<4, 3, CompareFunc> depth_test_func;
- BitField<8, 1, u32> red_enable;
- BitField<9, 1, u32> green_enable;
- BitField<10, 1, u32> blue_enable;
- BitField<11, 1, u32> alpha_enable;
- BitField<12, 1, u32> depth_write_enable;
- };
-
- INSERT_PADDING_WORDS(0x8);
- } output_merger;
-
- // Components are laid out in reverse byte order, most significant bits first.
- enum class ColorFormat : u32 {
- RGBA8 = 0,
- RGB8 = 1,
- RGB5A1 = 2,
- RGB565 = 3,
- RGBA4 = 4,
- };
-
- enum class DepthFormat : u32 {
- D16 = 0,
- D24 = 2,
- D24S8 = 3,
- };
-
- // Returns the number of bytes in the specified color format
- static unsigned BytesPerColorPixel(ColorFormat format) {
- switch (format) {
- case ColorFormat::RGBA8:
- return 4;
- case ColorFormat::RGB8:
- return 3;
- case ColorFormat::RGB5A1:
- case ColorFormat::RGB565:
- case ColorFormat::RGBA4:
- return 2;
- default:
- LOG_CRITICAL(HW_GPU, "Unknown color format %u", format);
- UNIMPLEMENTED();
- }
- }
-
- struct FramebufferConfig {
- INSERT_PADDING_WORDS(0x3);
-
- union {
- BitField<0, 4, u32> allow_color_write; // 0 = disable, else enable
- };
-
- INSERT_PADDING_WORDS(0x1);
-
- union {
- BitField<0, 2, u32> allow_depth_stencil_write; // 0 = disable, else enable
- };
-
- DepthFormat depth_format; // TODO: Should be a BitField!
- BitField<16, 3, ColorFormat> color_format;
-
- INSERT_PADDING_WORDS(0x4);
-
- u32 depth_buffer_address;
- u32 color_buffer_address;
-
- union {
- // Apparently, the framebuffer width is stored as expected,
- // while the height is stored as the actual height minus one.
- // Hence, don't access these fields directly but use the accessors
- // GetWidth() and GetHeight() instead.
- BitField<0, 11, u32> width;
- BitField<12, 10, u32> height;
- };
-
- INSERT_PADDING_WORDS(0x1);
-
- inline u32 GetColorBufferPhysicalAddress() const {
- return DecodeAddressRegister(color_buffer_address);
- }
- inline u32 GetDepthBufferPhysicalAddress() const {
- return DecodeAddressRegister(depth_buffer_address);
- }
-
- inline u32 GetWidth() const {
- return width;
- }
-
- inline u32 GetHeight() const {
- return height + 1;
- }
- } framebuffer;
-
- // Returns the number of bytes in the specified depth format
- static u32 BytesPerDepthPixel(DepthFormat format) {
- switch (format) {
- case DepthFormat::D16:
- return 2;
- case DepthFormat::D24:
- return 3;
- case DepthFormat::D24S8:
- return 4;
- default:
- LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
- UNIMPLEMENTED();
- }
- }
-
- // Returns the number of bits per depth component of the specified depth format
- static u32 DepthBitsPerPixel(DepthFormat format) {
- switch (format) {
- case DepthFormat::D16:
- return 16;
- case DepthFormat::D24:
- case DepthFormat::D24S8:
- return 24;
- default:
- LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
- UNIMPLEMENTED();
- }
- }
-
- INSERT_PADDING_WORDS(0x20);
-
- enum class LightingSampler {
- Distribution0 = 0,
- Distribution1 = 1,
- Fresnel = 3,
- ReflectBlue = 4,
- ReflectGreen = 5,
- ReflectRed = 6,
- SpotlightAttenuation = 8,
- DistanceAttenuation = 16,
- };
-
- /**
- * Pica fragment lighting supports using different LUTs for each lighting component:
- * Reflectance R, G, and B channels, distribution function for specular components 0 and 1,
- * fresnel factor, and spotlight attenuation. Furthermore, which LUTs are used for each channel
- * (or whether a channel is enabled at all) is specified by various pre-defined lighting
- * configurations. With configurations that require more LUTs, more cycles are required on HW to
- * perform lighting computations.
- */
- enum class LightingConfig {
- Config0 = 0, ///< Reflect Red, Distribution 0, Spotlight
- Config1 = 1, ///< Reflect Red, Fresnel, Spotlight
- Config2 = 2, ///< Reflect Red, Distribution 0/1
- Config3 = 3, ///< Distribution 0/1, Fresnel
- Config4 = 4, ///< Reflect Red/Green/Blue, Distribution 0/1, Spotlight
- Config5 = 5, ///< Reflect Red/Green/Blue, Distribution 0, Fresnel, Spotlight
- Config6 = 6, ///< Reflect Red, Distribution 0/1, Fresnel, Spotlight
- Config7 = 8, ///< Reflect Red/Green/Blue, Distribution 0/1, Fresnel, Spotlight
- ///< NOTE: '8' is intentional, '7' does not appear to be a valid configuration
- };
-
- /// Selects which lighting components are affected by fresnel
- enum class LightingFresnelSelector {
- None = 0, ///< Fresnel is disabled
- PrimaryAlpha = 1, ///< Primary (diffuse) lighting alpha is affected by fresnel
- SecondaryAlpha = 2, ///< Secondary (specular) lighting alpha is affected by fresnel
- Both =
- PrimaryAlpha |
- SecondaryAlpha, ///< Both primary and secondary lighting alphas are affected by fresnel
- };
-
- /// Factor used to scale the output of a lighting LUT
- enum class LightingScale {
- Scale1 = 0, ///< Scale is 1x
- Scale2 = 1, ///< Scale is 2x
- Scale4 = 2, ///< Scale is 4x
- Scale8 = 3, ///< Scale is 8x
- Scale1_4 = 6, ///< Scale is 0.25x
- Scale1_2 = 7, ///< Scale is 0.5x
- };
-
- enum class LightingLutInput {
- NH = 0, // Cosine of the angle between the normal and half-angle vectors
- VH = 1, // Cosine of the angle between the view and half-angle vectors
- NV = 2, // Cosine of the angle between the normal and the view vector
- LN = 3, // Cosine of the angle between the light and the normal vectors
- };
-
- enum class LightingBumpMode : u32 {
- None = 0,
- NormalMap = 1,
- TangentMap = 2,
- };
-
- union LightColor {
- BitField<0, 10, u32> b;
- BitField<10, 10, u32> g;
- BitField<20, 10, u32> r;
-
- Math::Vec3f ToVec3f() const {
- // These fields are 10 bits wide, however 255 corresponds to 1.0f for each color
- // component
- return Math::MakeVec((f32)r / 255.f, (f32)g / 255.f, (f32)b / 255.f);
- }
- };
-
- /// Returns true if the specified lighting sampler is supported by the current Pica lighting
- /// configuration
- static bool IsLightingSamplerSupported(LightingConfig config, LightingSampler sampler) {
- switch (sampler) {
- case LightingSampler::Distribution0:
- return (config != LightingConfig::Config1);
-
- case LightingSampler::Distribution1:
- return (config != LightingConfig::Config0) && (config != LightingConfig::Config1) &&
- (config != LightingConfig::Config5);
-
- case LightingSampler::Fresnel:
- return (config != LightingConfig::Config0) && (config != LightingConfig::Config2) &&
- (config != LightingConfig::Config4);
-
- case LightingSampler::ReflectRed:
- return (config != LightingConfig::Config3);
-
- case LightingSampler::ReflectGreen:
- case LightingSampler::ReflectBlue:
- return (config == LightingConfig::Config4) || (config == LightingConfig::Config5) ||
- (config == LightingConfig::Config7);
- default:
- UNREACHABLE_MSG("Regs::IsLightingSamplerSupported: Reached "
- "unreachable section, sampler should be one "
- "of Distribution0, Distribution1, Fresnel, "
- "ReflectRed, ReflectGreen or ReflectBlue, instead "
- "got %i",
- static_cast<int>(config));
- }
- }
-
- struct {
- struct LightSrc {
- LightColor specular_0; // material.specular_0 * light.specular_0
- LightColor specular_1; // material.specular_1 * light.specular_1
- LightColor diffuse; // material.diffuse * light.diffuse
- LightColor ambient; // material.ambient * light.ambient
-
- // Encoded as 16-bit floating point
- union {
- BitField<0, 16, u32> x;
- BitField<16, 16, u32> y;
- };
- union {
- BitField<0, 16, u32> z;
- };
-
- INSERT_PADDING_WORDS(0x3);
-
- union {
- BitField<0, 1, u32> directional;
- BitField<1, 1, u32> two_sided_diffuse; // When disabled, clamp dot-product to 0
- } config;
-
- BitField<0, 20, u32> dist_atten_bias;
- BitField<0, 20, u32> dist_atten_scale;
-
- INSERT_PADDING_WORDS(0x4);
- };
- static_assert(sizeof(LightSrc) == 0x10 * sizeof(u32),
- "LightSrc structure must be 0x10 words");
-
- LightSrc light[8];
- LightColor global_ambient; // Emission + (material.ambient * lighting.ambient)
- INSERT_PADDING_WORDS(0x1);
- BitField<0, 3, u32> max_light_index; // Number of enabled lights - 1
-
- union {
- BitField<2, 2, LightingFresnelSelector> fresnel_selector;
- BitField<4, 4, LightingConfig> config;
- BitField<22, 2, u32> bump_selector; // 0: Texture 0, 1: Texture 1, 2: Texture 2
- BitField<27, 1, u32> clamp_highlights;
- BitField<28, 2, LightingBumpMode> bump_mode;
- BitField<30, 1, u32> disable_bump_renorm;
- } config0;
-
- union {
- BitField<16, 1, u32> disable_lut_d0;
- BitField<17, 1, u32> disable_lut_d1;
- BitField<19, 1, u32> disable_lut_fr;
- BitField<20, 1, u32> disable_lut_rr;
- BitField<21, 1, u32> disable_lut_rg;
- BitField<22, 1, u32> disable_lut_rb;
-
- // Each bit specifies whether distance attenuation should be applied for the
- // corresponding light
-
- BitField<24, 1, u32> disable_dist_atten_light_0;
- BitField<25, 1, u32> disable_dist_atten_light_1;
- BitField<26, 1, u32> disable_dist_atten_light_2;
- BitField<27, 1, u32> disable_dist_atten_light_3;
- BitField<28, 1, u32> disable_dist_atten_light_4;
- BitField<29, 1, u32> disable_dist_atten_light_5;
- BitField<30, 1, u32> disable_dist_atten_light_6;
- BitField<31, 1, u32> disable_dist_atten_light_7;
- } config1;
-
- bool IsDistAttenDisabled(unsigned index) const {
- const unsigned disable[] = {
- config1.disable_dist_atten_light_0, config1.disable_dist_atten_light_1,
- config1.disable_dist_atten_light_2, config1.disable_dist_atten_light_3,
- config1.disable_dist_atten_light_4, config1.disable_dist_atten_light_5,
- config1.disable_dist_atten_light_6, config1.disable_dist_atten_light_7};
- return disable[index] != 0;
- }
-
- union {
- BitField<0, 8, u32> index; ///< Index at which to set data in the LUT
- BitField<8, 5, u32> type; ///< Type of LUT for which to set data
- } lut_config;
-
- BitField<0, 1, u32> disable;
- INSERT_PADDING_WORDS(0x1);
-
- // When data is written to any of these registers, it gets written to the lookup table of
- // the selected type at the selected index, specified above in the `lut_config` register.
- // With each write, `lut_config.index` is incremented. It does not matter which of these
- // registers is written to, the behavior will be the same.
- u32 lut_data[8];
-
- // These are used to specify if absolute (abs) value should be used for each LUT index. When
- // abs mode is disabled, LUT indexes are in the range of (-1.0, 1.0). Otherwise, they are in
- // the range of (0.0, 1.0).
- union {
- BitField<1, 1, u32> disable_d0;
- BitField<5, 1, u32> disable_d1;
- BitField<9, 1, u32> disable_sp;
- BitField<13, 1, u32> disable_fr;
- BitField<17, 1, u32> disable_rb;
- BitField<21, 1, u32> disable_rg;
- BitField<25, 1, u32> disable_rr;
- } abs_lut_input;
-
- union {
- BitField<0, 3, LightingLutInput> d0;
- BitField<4, 3, LightingLutInput> d1;
- BitField<8, 3, LightingLutInput> sp;
- BitField<12, 3, LightingLutInput> fr;
- BitField<16, 3, LightingLutInput> rb;
- BitField<20, 3, LightingLutInput> rg;
- BitField<24, 3, LightingLutInput> rr;
- } lut_input;
-
- union {
- BitField<0, 3, LightingScale> d0;
- BitField<4, 3, LightingScale> d1;
- BitField<8, 3, LightingScale> sp;
- BitField<12, 3, LightingScale> fr;
- BitField<16, 3, LightingScale> rb;
- BitField<20, 3, LightingScale> rg;
- BitField<24, 3, LightingScale> rr;
-
- static float GetScale(LightingScale scale) {
- switch (scale) {
- case LightingScale::Scale1:
- return 1.0f;
- case LightingScale::Scale2:
- return 2.0f;
- case LightingScale::Scale4:
- return 4.0f;
- case LightingScale::Scale8:
- return 8.0f;
- case LightingScale::Scale1_4:
- return 0.25f;
- case LightingScale::Scale1_2:
- return 0.5f;
- }
- return 0.0f;
- }
- } lut_scale;
-
- INSERT_PADDING_WORDS(0x6);
-
- union {
- // There are 8 light enable "slots", corresponding to the total number of lights
- // supported by Pica. For N enabled lights (specified by register 0x1c2, or 'src_num'
- // above), the first N slots below will be set to integers within the range of 0-7,
- // corresponding to the actual light that is enabled for each slot.
-
- BitField<0, 3, u32> slot_0;
- BitField<4, 3, u32> slot_1;
- BitField<8, 3, u32> slot_2;
- BitField<12, 3, u32> slot_3;
- BitField<16, 3, u32> slot_4;
- BitField<20, 3, u32> slot_5;
- BitField<24, 3, u32> slot_6;
- BitField<28, 3, u32> slot_7;
-
- unsigned GetNum(unsigned index) const {
- const unsigned enable_slots[] = {slot_0, slot_1, slot_2, slot_3,
- slot_4, slot_5, slot_6, slot_7};
- return enable_slots[index];
- }
- } light_enable;
- } lighting;
-
- INSERT_PADDING_WORDS(0x26);
-
- enum class VertexAttributeFormat : u64 {
- BYTE = 0,
- UBYTE = 1,
- SHORT = 2,
- FLOAT = 3,
- };
-
- struct {
- BitField<0, 29, u32> base_address;
-
- u32 GetPhysicalBaseAddress() const {
- return DecodeAddressRegister(base_address);
- }
-
- // Descriptor for internal vertex attributes
- union {
- BitField<0, 2, VertexAttributeFormat> format0; // size of one element
- BitField<2, 2, u64> size0; // number of elements minus 1
- BitField<4, 2, VertexAttributeFormat> format1;
- BitField<6, 2, u64> size1;
- BitField<8, 2, VertexAttributeFormat> format2;
- BitField<10, 2, u64> size2;
- BitField<12, 2, VertexAttributeFormat> format3;
- BitField<14, 2, u64> size3;
- BitField<16, 2, VertexAttributeFormat> format4;
- BitField<18, 2, u64> size4;
- BitField<20, 2, VertexAttributeFormat> format5;
- BitField<22, 2, u64> size5;
- BitField<24, 2, VertexAttributeFormat> format6;
- BitField<26, 2, u64> size6;
- BitField<28, 2, VertexAttributeFormat> format7;
- BitField<30, 2, u64> size7;
- BitField<32, 2, VertexAttributeFormat> format8;
- BitField<34, 2, u64> size8;
- BitField<36, 2, VertexAttributeFormat> format9;
- BitField<38, 2, u64> size9;
- BitField<40, 2, VertexAttributeFormat> format10;
- BitField<42, 2, u64> size10;
- BitField<44, 2, VertexAttributeFormat> format11;
- BitField<46, 2, u64> size11;
-
- BitField<48, 12, u64> attribute_mask;
-
- // number of total attributes minus 1
- BitField<60, 4, u64> max_attribute_index;
- };
-
- inline VertexAttributeFormat GetFormat(int n) const {
- VertexAttributeFormat formats[] = {format0, format1, format2, format3,
- format4, format5, format6, format7,
- format8, format9, format10, format11};
- return formats[n];
- }
-
- inline int GetNumElements(int n) const {
- u64 sizes[] = {size0, size1, size2, size3, size4, size5,
- size6, size7, size8, size9, size10, size11};
- return (int)sizes[n] + 1;
- }
-
- inline int GetElementSizeInBytes(int n) const {
- return (GetFormat(n) == VertexAttributeFormat::FLOAT)
- ? 4
- : (GetFormat(n) == VertexAttributeFormat::SHORT) ? 2 : 1;
- }
-
- inline int GetStride(int n) const {
- return GetNumElements(n) * GetElementSizeInBytes(n);
- }
-
- inline bool IsDefaultAttribute(int id) const {
- return (id >= 12) || (attribute_mask & (1ULL << id)) != 0;
- }
-
- inline int GetNumTotalAttributes() const {
- return (int)max_attribute_index + 1;
- }
-
- // Attribute loaders map the source vertex data to input attributes
- // This e.g. allows to load different attributes from different memory locations
- struct {
- // Source attribute data offset from the base address
- u32 data_offset;
-
- union {
- BitField<0, 4, u64> comp0;
- BitField<4, 4, u64> comp1;
- BitField<8, 4, u64> comp2;
- BitField<12, 4, u64> comp3;
- BitField<16, 4, u64> comp4;
- BitField<20, 4, u64> comp5;
- BitField<24, 4, u64> comp6;
- BitField<28, 4, u64> comp7;
- BitField<32, 4, u64> comp8;
- BitField<36, 4, u64> comp9;
- BitField<40, 4, u64> comp10;
- BitField<44, 4, u64> comp11;
-
- // bytes for a single vertex in this loader
- BitField<48, 8, u64> byte_count;
-
- BitField<60, 4, u64> component_count;
- };
-
- inline int GetComponent(int n) const {
- u64 components[] = {comp0, comp1, comp2, comp3, comp4, comp5,
- comp6, comp7, comp8, comp9, comp10, comp11};
- return (int)components[n];
- }
- } attribute_loaders[12];
- } vertex_attributes;
-
- struct {
- enum IndexFormat : u32 {
- BYTE = 0,
- SHORT = 1,
- };
-
- union {
- BitField<0, 31, u32> offset; // relative to base attribute address
- BitField<31, 1, IndexFormat> format;
- };
- } index_array;
-
- // Number of vertices to render
- u32 num_vertices;
-
- INSERT_PADDING_WORDS(0x1);
-
- // The index of the first vertex to render
- u32 vertex_offset;
-
- INSERT_PADDING_WORDS(0x3);
-
- // These two trigger rendering of triangles
- u32 trigger_draw;
- u32 trigger_draw_indexed;
-
- INSERT_PADDING_WORDS(0x2);
-
- // These registers are used to setup the default "fall-back" vertex shader attributes
- struct {
- // Index of the current default attribute
- u32 index;
-
- // Writing to these registers sets the "current" default attribute.
- u32 set_value[3];
- } vs_default_attributes_setup;
-
- INSERT_PADDING_WORDS(0x2);
-
- struct {
- // There are two channels that can be used to configure the next command buffer, which
- // can be then executed by writing to the "trigger" registers. There are two reasons why a
- // game might use this feature:
- // 1) With this, an arbitrary number of additional command buffers may be executed in
- // sequence without requiring any intervention of the CPU after the initial one is
- // kicked off.
- // 2) Games can configure these registers to provide a command list subroutine mechanism.
-
- BitField<0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer
- BitField<0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer
- u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to
-
- unsigned GetSize(unsigned index) const {
- ASSERT(index < 2);
- return 8 * size[index];
- }
-
- PAddr GetPhysicalAddress(unsigned index) const {
- ASSERT(index < 2);
- return (PAddr)(8 * addr[index]);
- }
- } command_buffer;
-
- INSERT_PADDING_WORDS(4);
-
- /// Number of input attributes to the vertex shader minus 1
- BitField<0, 4, u32> max_input_attrib_index;
-
- INSERT_PADDING_WORDS(2);
-
- enum class GPUMode : u32 {
- Drawing = 0,
- Configuring = 1,
- };
-
- GPUMode gpu_mode;
-
- INSERT_PADDING_WORDS(0x18);
-
- enum class TriangleTopology : u32 {
- List = 0,
- Strip = 1,
- Fan = 2,
- Shader = 3, // Programmable setup unit implemented in a geometry shader
- };
-
- BitField<8, 2, TriangleTopology> triangle_topology;
-
- u32 restart_primitive;
-
- INSERT_PADDING_WORDS(0x20);
-
- struct ShaderConfig {
- BitField<0, 16, u32> bool_uniforms;
-
- union {
- BitField<0, 8, u32> x;
- BitField<8, 8, u32> y;
- BitField<16, 8, u32> z;
- BitField<24, 8, u32> w;
- } int_uniforms[4];
-
- INSERT_PADDING_WORDS(0x4);
-
- union {
- // Number of input attributes to shader unit - 1
- BitField<0, 4, u32> max_input_attribute_index;
- };
-
- // Offset to shader program entry point (in words)
- BitField<0, 16, u32> main_offset;
-
- /// Maps input attributes to registers. 4-bits per attribute, specifying a register index
- u32 input_attribute_to_register_map_low;
- u32 input_attribute_to_register_map_high;
-
- unsigned int GetRegisterForAttribute(unsigned int attribute_index) const {
- u64 map = ((u64)input_attribute_to_register_map_high << 32) |
- (u64)input_attribute_to_register_map_low;
- return (map >> (attribute_index * 4)) & 0b1111;
- }
-
- BitField<0, 16, u32> output_mask;
-
- // 0x28E, CODETRANSFER_END
- INSERT_PADDING_WORDS(0x2);
-
- struct {
- enum Format : u32 {
- FLOAT24 = 0,
- FLOAT32 = 1,
- };
-
- bool IsFloat32() const {
- return format == FLOAT32;
- }
-
- union {
- // Index of the next uniform to write to
- // TODO: ctrulib uses 8 bits for this, however that seems to yield lots of invalid
- // indices
- // TODO: Maybe the uppermost index is for the geometry shader? Investigate!
- BitField<0, 7, u32> index;
-
- BitField<31, 1, Format> format;
- };
-
- // Writing to these registers sets the current uniform.
- u32 set_value[8];
-
- } uniform_setup;
-
- INSERT_PADDING_WORDS(0x2);
-
- struct {
- // Offset of the next instruction to write code to.
- // Incremented with each instruction write.
- u32 offset;
-
- // Writing to these registers sets the "current" word in the shader program.
- u32 set_word[8];
- } program;
-
- INSERT_PADDING_WORDS(0x1);
-
- // This register group is used to load an internal table of swizzling patterns,
- // which are indexed by each shader instruction to specify vector component swizzling.
- struct {
- // Offset of the next swizzle pattern to write code to.
- // Incremented with each instruction write.
- u32 offset;
-
- // Writing to these registers sets the current swizzle pattern in the table.
- u32 set_word[8];
- } swizzle_patterns;
-
- INSERT_PADDING_WORDS(0x2);
- };
-
- ShaderConfig gs;
- ShaderConfig vs;
-
- INSERT_PADDING_WORDS(0x20);
-
- // Map register indices to names readable by humans
- // Used for debugging purposes, so performance is not an issue here
- static std::string GetCommandName(int index);
-
- static constexpr size_t NumIds() {
- return sizeof(Regs) / sizeof(u32);
- }
-
- const u32& operator[](int index) const {
- const u32* content = reinterpret_cast<const u32*>(this);
- return content[index];
- }
-
- u32& operator[](int index) {
- u32* content = reinterpret_cast<u32*>(this);
- return content[index];
- }
-
-private:
- /*
- * Most physical addresses which Pica registers refer to are 8-byte aligned.
- * This function should be used to get the address from a raw register value.
- */
- static inline u32 DecodeAddressRegister(u32 register_value) {
- return register_value * 8;
- }
-};
-
-// TODO: MSVC does not support using offsetof() on non-static data members even though this
-// is technically allowed since C++11. This macro should be enabled once MSVC adds
-// support for that.
-#ifndef _MSC_VER
-#define ASSERT_REG_POSITION(field_name, position) \
- static_assert(offsetof(Regs, field_name) == position * 4, \
- "Field " #field_name " has invalid position")
-
-ASSERT_REG_POSITION(trigger_irq, 0x10);
-ASSERT_REG_POSITION(cull_mode, 0x40);
-ASSERT_REG_POSITION(viewport_size_x, 0x41);
-ASSERT_REG_POSITION(viewport_size_y, 0x43);
-ASSERT_REG_POSITION(viewport_depth_range, 0x4d);
-ASSERT_REG_POSITION(viewport_depth_near_plane, 0x4e);
-ASSERT_REG_POSITION(vs_output_attributes[0], 0x50);
-ASSERT_REG_POSITION(vs_output_attributes[1], 0x51);
-ASSERT_REG_POSITION(scissor_test, 0x65);
-ASSERT_REG_POSITION(viewport_corner, 0x68);
-ASSERT_REG_POSITION(depthmap_enable, 0x6D);
-ASSERT_REG_POSITION(texture0_enable, 0x80);
-ASSERT_REG_POSITION(texture0, 0x81);
-ASSERT_REG_POSITION(texture0_format, 0x8e);
-ASSERT_REG_POSITION(fragment_lighting_enable, 0x8f);
-ASSERT_REG_POSITION(texture1, 0x91);
-ASSERT_REG_POSITION(texture1_format, 0x96);
-ASSERT_REG_POSITION(texture2, 0x99);
-ASSERT_REG_POSITION(texture2_format, 0x9e);
-ASSERT_REG_POSITION(tev_stage0, 0xc0);
-ASSERT_REG_POSITION(tev_stage1, 0xc8);
-ASSERT_REG_POSITION(tev_stage2, 0xd0);
-ASSERT_REG_POSITION(tev_stage3, 0xd8);
-ASSERT_REG_POSITION(tev_combiner_buffer_input, 0xe0);
-ASSERT_REG_POSITION(fog_mode, 0xe0);
-ASSERT_REG_POSITION(fog_color, 0xe1);
-ASSERT_REG_POSITION(fog_lut_offset, 0xe6);
-ASSERT_REG_POSITION(fog_lut_data, 0xe8);
-ASSERT_REG_POSITION(tev_stage4, 0xf0);
-ASSERT_REG_POSITION(tev_stage5, 0xf8);
-ASSERT_REG_POSITION(tev_combiner_buffer_color, 0xfd);
-ASSERT_REG_POSITION(output_merger, 0x100);
-ASSERT_REG_POSITION(framebuffer, 0x110);
-ASSERT_REG_POSITION(lighting, 0x140);
-ASSERT_REG_POSITION(vertex_attributes, 0x200);
-ASSERT_REG_POSITION(index_array, 0x227);
-ASSERT_REG_POSITION(num_vertices, 0x228);
-ASSERT_REG_POSITION(vertex_offset, 0x22a);
-ASSERT_REG_POSITION(trigger_draw, 0x22e);
-ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f);
-ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232);
-ASSERT_REG_POSITION(command_buffer, 0x238);
-ASSERT_REG_POSITION(gpu_mode, 0x245);
-ASSERT_REG_POSITION(triangle_topology, 0x25e);
-ASSERT_REG_POSITION(restart_primitive, 0x25f);
-ASSERT_REG_POSITION(gs, 0x280);
-ASSERT_REG_POSITION(vs, 0x2b0);
-
-#undef ASSERT_REG_POSITION
-#endif // !defined(_MSC_VER)
-
-static_assert(sizeof(Regs::ShaderConfig) == 0x30 * sizeof(u32),
- "ShaderConfig structure has incorrect size");
-
-// The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value
-// anyway.
-static_assert(sizeof(Regs) <= 0x300 * sizeof(u32),
- "Register set structure larger than it should be");
-static_assert(sizeof(Regs) >= 0x300 * sizeof(u32),
- "Register set structure smaller than it should be");
-
/// Initialize Pica state
void Init();
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 @@
#include <array>
#include "common/bit_field.h"
#include "common/common_types.h"
-#include "video_core/pica.h"
#include "video_core/primitive_assembly.h"
+#include "video_core/regs.h"
#include "video_core/shader/shader.h"
namespace 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 @@
// Refer to the license.txt file included.
#include "common/logging/log.h"
-#include "video_core/pica.h"
#include "video_core/primitive_assembly.h"
+#include "video_core/regs_pipeline.h"
#include "video_core/shader/shader.h"
namespace Pica {
template <typename VertexType>
-PrimitiveAssembler<VertexType>::PrimitiveAssembler(Regs::TriangleTopology topology)
+PrimitiveAssembler<VertexType>::PrimitiveAssembler(PipelineRegs::TriangleTopology topology)
: topology(topology), buffer_index(0) {}
template <typename VertexType>
@@ -18,8 +18,8 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx,
TriangleHandler triangle_handler) {
switch (topology) {
// TODO: Figure out what's different with TriangleTopology::Shader.
- case Regs::TriangleTopology::List:
- case Regs::TriangleTopology::Shader:
+ case PipelineRegs::TriangleTopology::List:
+ case PipelineRegs::TriangleTopology::Shader:
if (buffer_index < 2) {
buffer[buffer_index++] = vtx;
} else {
@@ -29,8 +29,8 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx,
}
break;
- case Regs::TriangleTopology::Strip:
- case Regs::TriangleTopology::Fan:
+ case PipelineRegs::TriangleTopology::Strip:
+ case PipelineRegs::TriangleTopology::Fan:
if (strip_ready)
triangle_handler(buffer[0], buffer[1], vtx);
@@ -38,9 +38,9 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx,
strip_ready |= (buffer_index == 1);
- if (topology == Regs::TriangleTopology::Strip)
+ if (topology == PipelineRegs::TriangleTopology::Strip)
buffer_index = !buffer_index;
- else if (topology == Regs::TriangleTopology::Fan)
+ else if (topology == PipelineRegs::TriangleTopology::Fan)
buffer_index = 1;
break;
@@ -57,7 +57,7 @@ void PrimitiveAssembler<VertexType>::Reset() {
}
template <typename VertexType>
-void PrimitiveAssembler<VertexType>::Reconfigure(Regs::TriangleTopology topology) {
+void PrimitiveAssembler<VertexType>::Reconfigure(PipelineRegs::TriangleTopology topology) {
Reset();
this->topology = topology;
}
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 @@
#pragma once
#include <functional>
-#include "video_core/pica.h"
+#include "video_core/regs_pipeline.h"
namespace Pica {
@@ -18,7 +18,8 @@ struct PrimitiveAssembler {
using TriangleHandler =
std::function<void(const VertexType& v0, const VertexType& v1, const VertexType& v2)>;
- PrimitiveAssembler(Regs::TriangleTopology topology = Regs::TriangleTopology::List);
+ PrimitiveAssembler(
+ PipelineRegs::TriangleTopology topology = PipelineRegs::TriangleTopology::List);
/*
* Queues a vertex, builds primitives from the vertex queue according to the given
@@ -36,10 +37,10 @@ struct PrimitiveAssembler {
/**
* Reconfigures the PrimitiveAssembler to use a different triangle topology.
*/
- void Reconfigure(Regs::TriangleTopology topology);
+ void Reconfigure(PipelineRegs::TriangleTopology topology);
private:
- Regs::TriangleTopology topology;
+ PipelineRegs::TriangleTopology topology;
int buffer_index;
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 @@
#include "core/hw/gpu.h"
#include "core/memory.h"
#include "video_core/debug_utils/debug_utils.h"
-#include "video_core/pica.h"
#include "video_core/pica_state.h"
#include "video_core/pica_types.h"
#include "video_core/rasterizer.h"
+#include "video_core/regs.h"
#include "video_core/shader/shader.h"
#include "video_core/texture/texture_decode.h"
#include "video_core/utils.h"
@@ -29,7 +29,7 @@ namespace Pica {
namespace Rasterizer {
static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
- const auto& framebuffer = g_state.regs.framebuffer;
+ const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
// 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) {
u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset;
switch (framebuffer.color_format) {
- case Regs::ColorFormat::RGBA8:
+ case FramebufferRegs::ColorFormat::RGBA8:
Color::EncodeRGBA8(color, dst_pixel);
break;
- case Regs::ColorFormat::RGB8:
+ case FramebufferRegs::ColorFormat::RGB8:
Color::EncodeRGB8(color, dst_pixel);
break;
- case Regs::ColorFormat::RGB5A1:
+ case FramebufferRegs::ColorFormat::RGB5A1:
Color::EncodeRGB5A1(color, dst_pixel);
break;
- case Regs::ColorFormat::RGB565:
+ case FramebufferRegs::ColorFormat::RGB565:
Color::EncodeRGB565(color, dst_pixel);
break;
- case Regs::ColorFormat::RGBA4:
+ case FramebufferRegs::ColorFormat::RGBA4:
Color::EncodeRGBA4(color, dst_pixel);
break;
@@ -72,7 +72,7 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
}
static const Math::Vec4<u8> GetPixel(int x, int y) {
- const auto& framebuffer = g_state.regs.framebuffer;
+ const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
y = framebuffer.height - y;
@@ -85,19 +85,19 @@ static const Math::Vec4<u8> GetPixel(int x, int y) {
u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset;
switch (framebuffer.color_format) {
- case Regs::ColorFormat::RGBA8:
+ case FramebufferRegs::ColorFormat::RGBA8:
return Color::DecodeRGBA8(src_pixel);
- case Regs::ColorFormat::RGB8:
+ case FramebufferRegs::ColorFormat::RGB8:
return Color::DecodeRGB8(src_pixel);
- case Regs::ColorFormat::RGB5A1:
+ case FramebufferRegs::ColorFormat::RGB5A1:
return Color::DecodeRGB5A1(src_pixel);
- case Regs::ColorFormat::RGB565:
+ case FramebufferRegs::ColorFormat::RGB565:
return Color::DecodeRGB565(src_pixel);
- case Regs::ColorFormat::RGBA4:
+ case FramebufferRegs::ColorFormat::RGBA4:
return Color::DecodeRGBA4(src_pixel);
default:
@@ -110,25 +110,25 @@ static const Math::Vec4<u8> GetPixel(int x, int y) {
}
static u32 GetDepth(int x, int y) {
- const auto& framebuffer = g_state.regs.framebuffer;
+ const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
y = framebuffer.height - y;
const u32 coarse_y = y & ~7;
- u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format);
+ u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
u32 stride = framebuffer.width * bytes_per_pixel;
u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
u8* src_pixel = depth_buffer + src_offset;
switch (framebuffer.depth_format) {
- case Regs::DepthFormat::D16:
+ case FramebufferRegs::DepthFormat::D16:
return Color::DecodeD16(src_pixel);
- case Regs::DepthFormat::D24:
+ case FramebufferRegs::DepthFormat::D24:
return Color::DecodeD24(src_pixel);
- case Regs::DepthFormat::D24S8:
+ case FramebufferRegs::DepthFormat::D24S8:
return Color::DecodeD24S8(src_pixel).x;
default:
LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
@@ -138,21 +138,21 @@ static u32 GetDepth(int x, int y) {
}
static u8 GetStencil(int x, int y) {
- const auto& framebuffer = g_state.regs.framebuffer;
+ const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
y = framebuffer.height - y;
const u32 coarse_y = y & ~7;
- u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format);
+ u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
u32 stride = framebuffer.width * bytes_per_pixel;
u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
u8* src_pixel = depth_buffer + src_offset;
switch (framebuffer.depth_format) {
- case Regs::DepthFormat::D24S8:
+ case FramebufferRegs::DepthFormat::D24S8:
return Color::DecodeD24S8(src_pixel).y;
default:
@@ -165,29 +165,29 @@ static u8 GetStencil(int x, int y) {
}
static void SetDepth(int x, int y, u32 value) {
- const auto& framebuffer = g_state.regs.framebuffer;
+ const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
y = framebuffer.height - y;
const u32 coarse_y = y & ~7;
- u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format);
+ u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
u32 stride = framebuffer.width * bytes_per_pixel;
u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
u8* dst_pixel = depth_buffer + dst_offset;
switch (framebuffer.depth_format) {
- case Regs::DepthFormat::D16:
+ case FramebufferRegs::DepthFormat::D16:
Color::EncodeD16(value, dst_pixel);
break;
- case Regs::DepthFormat::D24:
+ case FramebufferRegs::DepthFormat::D24:
Color::EncodeD24(value, dst_pixel);
break;
- case Regs::DepthFormat::D24S8:
+ case FramebufferRegs::DepthFormat::D24S8:
Color::EncodeD24X8(value, dst_pixel);
break;
@@ -199,26 +199,26 @@ static void SetDepth(int x, int y, u32 value) {
}
static void SetStencil(int x, int y, u8 value) {
- const auto& framebuffer = g_state.regs.framebuffer;
+ const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
y = framebuffer.height - y;
const u32 coarse_y = y & ~7;
- u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format);
+ u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format);
u32 stride = framebuffer.width * bytes_per_pixel;
u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
u8* dst_pixel = depth_buffer + dst_offset;
switch (framebuffer.depth_format) {
- case Pica::Regs::DepthFormat::D16:
- case Pica::Regs::DepthFormat::D24:
+ case Pica::FramebufferRegs::DepthFormat::D16:
+ case Pica::FramebufferRegs::DepthFormat::D24:
// Nothing to do
break;
- case Pica::Regs::DepthFormat::D24S8:
+ case Pica::FramebufferRegs::DepthFormat::D24S8:
Color::EncodeX24S8(value, dst_pixel);
break;
@@ -229,32 +229,32 @@ static void SetStencil(int x, int y, u8 value) {
}
}
-static u8 PerformStencilAction(Regs::StencilAction action, u8 old_stencil, u8 ref) {
+static u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref) {
switch (action) {
- case Regs::StencilAction::Keep:
+ case FramebufferRegs::StencilAction::Keep:
return old_stencil;
- case Regs::StencilAction::Zero:
+ case FramebufferRegs::StencilAction::Zero:
return 0;
- case Regs::StencilAction::Replace:
+ case FramebufferRegs::StencilAction::Replace:
return ref;
- case Regs::StencilAction::Increment:
+ case FramebufferRegs::StencilAction::Increment:
// Saturated increment
return std::min<u8>(old_stencil, 254) + 1;
- case Regs::StencilAction::Decrement:
+ case FramebufferRegs::StencilAction::Decrement:
// Saturated decrement
return std::max<u8>(old_stencil, 1) - 1;
- case Regs::StencilAction::Invert:
+ case FramebufferRegs::StencilAction::Invert:
return ~old_stencil;
- case Regs::StencilAction::IncrementWrap:
+ case FramebufferRegs::StencilAction::IncrementWrap:
return old_stencil + 1;
- case Regs::StencilAction::DecrementWrap:
+ case FramebufferRegs::StencilAction::DecrementWrap:
return old_stencil - 1;
default:
@@ -327,14 +327,14 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
ScreenToRasterizerCoordinates(v1.screenpos),
ScreenToRasterizerCoordinates(v2.screenpos)};
- if (regs.cull_mode == Regs::CullMode::KeepAll) {
+ if (regs.rasterizer.cull_mode == RasterizerRegs::CullMode::KeepAll) {
// Make sure we always end up with a triangle wound counter-clockwise
if (!reversed && SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) {
ProcessTriangleInternal(v0, v2, v1, true);
return;
}
} else {
- if (!reversed && regs.cull_mode == Regs::CullMode::KeepClockWise) {
+ if (!reversed && regs.rasterizer.cull_mode == RasterizerRegs::CullMode::KeepClockWise) {
// Reverse vertex order and use the CCW code path.
ProcessTriangleInternal(v0, v2, v1, true);
return;
@@ -351,13 +351,13 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y});
// Convert the scissor box coordinates to 12.4 fixed point
- u16 scissor_x1 = (u16)(regs.scissor_test.x1 << 4);
- u16 scissor_y1 = (u16)(regs.scissor_test.y1 << 4);
+ u16 scissor_x1 = (u16)(regs.rasterizer.scissor_test.x1 << 4);
+ u16 scissor_y1 = (u16)(regs.rasterizer.scissor_test.y1 << 4);
// x2,y2 have +1 added to cover the entire sub-pixel area
- u16 scissor_x2 = (u16)((regs.scissor_test.x2 + 1) << 4);
- u16 scissor_y2 = (u16)((regs.scissor_test.y2 + 1) << 4);
+ u16 scissor_x2 = (u16)((regs.rasterizer.scissor_test.x2 + 1) << 4);
+ u16 scissor_y2 = (u16)((regs.rasterizer.scissor_test.y2 + 1) << 4);
- if (regs.scissor_test.mode == Regs::ScissorMode::Include) {
+ if (regs.rasterizer.scissor_test.mode == RasterizerRegs::ScissorMode::Include) {
// Calculate the new bounds
min_x = std::max(min_x, scissor_x1);
min_y = std::max(min_y, scissor_y1);
@@ -397,12 +397,13 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w);
- auto textures = regs.GetTextures();
- auto tev_stages = regs.GetTevStages();
+ auto textures = regs.texturing.GetTextures();
+ auto tev_stages = regs.texturing.GetTevStages();
- bool stencil_action_enable = g_state.regs.output_merger.stencil_test.enable &&
- g_state.regs.framebuffer.depth_format == Regs::DepthFormat::D24S8;
- const auto stencil_test = g_state.regs.output_merger.stencil_test;
+ bool stencil_action_enable =
+ g_state.regs.framebuffer.output_merger.stencil_test.enable &&
+ g_state.regs.framebuffer.framebuffer.depth_format == FramebufferRegs::DepthFormat::D24S8;
+ const auto stencil_test = g_state.regs.framebuffer.output_merger.stencil_test;
// Enter rasterization loop, starting at the center of the topleft bounding box corner.
// 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
// Do not process the pixel if it's inside the scissor box and the scissor mode is set
// to Exclude
- if (regs.scissor_test.mode == Regs::ScissorMode::Exclude) {
+ if (regs.rasterizer.scissor_test.mode == RasterizerRegs::ScissorMode::Exclude) {
if (x >= scissor_x1 && x < scissor_x2 && y >= scissor_y1 && y < scissor_y2)
continue;
}
@@ -441,12 +442,14 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
// Not fully accurate. About 3 bits in precision are missing.
// Z-Buffer (z / w * scale + offset)
- float depth_scale = float24::FromRaw(regs.viewport_depth_range).ToFloat32();
- float depth_offset = float24::FromRaw(regs.viewport_depth_near_plane).ToFloat32();
+ float depth_scale = float24::FromRaw(regs.rasterizer.viewport_depth_range).ToFloat32();
+ float depth_offset =
+ float24::FromRaw(regs.rasterizer.viewport_depth_near_plane).ToFloat32();
float depth = interpolated_z_over_w * depth_scale + depth_offset;
// Potentially switch to W-Buffer
- if (regs.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) {
+ if (regs.rasterizer.depthmap_enable ==
+ Pica::RasterizerRegs::DepthBuffering::WBuffering) {
// W-Buffer (z * scale + w * offset = (z / w * scale + offset) * w)
depth *= interpolated_w_inverse.ToFloat32() * wsum;
}
@@ -513,9 +516,9 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
// TODO: Refactor so cubemaps and shadowmaps can be handled
if (i == 0) {
switch (texture.config.type) {
- case Regs::TextureConfig::Texture2D:
+ case TexturingRegs::TextureConfig::Texture2D:
break;
- case Regs::TextureConfig::Projection2D: {
+ case TexturingRegs::TextureConfig::Projection2D: {
auto tc0_w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w);
u /= tc0_w;
v /= tc0_w;
@@ -534,21 +537,21 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
int t = (int)(v * float24::FromFloat32(static_cast<float>(texture.config.height)))
.ToFloat32();
- static auto GetWrappedTexCoord = [](Regs::TextureConfig::WrapMode mode, int val,
- unsigned size) {
+ static auto GetWrappedTexCoord = [](TexturingRegs::TextureConfig::WrapMode mode,
+ int val, unsigned size) {
switch (mode) {
- case Regs::TextureConfig::ClampToEdge:
+ case TexturingRegs::TextureConfig::ClampToEdge:
val = std::max(val, 0);
val = std::min(val, (int)size - 1);
return val;
- case Regs::TextureConfig::ClampToBorder:
+ case TexturingRegs::TextureConfig::ClampToBorder:
return val;
- case Regs::TextureConfig::Repeat:
+ case TexturingRegs::TextureConfig::Repeat:
return (int)((unsigned)val % size);
- case Regs::TextureConfig::MirroredRepeat: {
+ case TexturingRegs::TextureConfig::MirroredRepeat: {
unsigned int coord = ((unsigned)val % (2 * size));
if (coord >= size)
coord = 2 * size - 1 - coord;
@@ -562,9 +565,9 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
}
};
- if ((texture.config.wrap_s == Regs::TextureConfig::ClampToBorder &&
+ if ((texture.config.wrap_s == TexturingRegs::TextureConfig::ClampToBorder &&
(s < 0 || static_cast<u32>(s) >= texture.config.width)) ||
- (texture.config.wrap_t == Regs::TextureConfig::ClampToBorder &&
+ (texture.config.wrap_t == TexturingRegs::TextureConfig::ClampToBorder &&
(t < 0 || static_cast<u32>(t) >= texture.config.height))) {
auto border_color = texture.config.border_color;
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
Math::Vec4<u8> combiner_output;
Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0};
Math::Vec4<u8> next_combiner_buffer = {
- regs.tev_combiner_buffer_color.r, regs.tev_combiner_buffer_color.g,
- regs.tev_combiner_buffer_color.b, regs.tev_combiner_buffer_color.a,
+ regs.texturing.tev_combiner_buffer_color.r,
+ regs.texturing.tev_combiner_buffer_color.g,
+ regs.texturing.tev_combiner_buffer_color.b,
+ regs.texturing.tev_combiner_buffer_color.a,
};
for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size();
++tev_stage_index) {
const auto& tev_stage = tev_stages[tev_stage_index];
- using Source = Regs::TevStageConfig::Source;
- using ColorModifier = Regs::TevStageConfig::ColorModifier;
- using AlphaModifier = Regs::TevStageConfig::AlphaModifier;
- using Operation = Regs::TevStageConfig::Operation;
+ using Source = TexturingRegs::TevStageConfig::Source;
+ using ColorModifier = TexturingRegs::TevStageConfig::ColorModifier;
+ using AlphaModifier = TexturingRegs::TevStageConfig::AlphaModifier;
+ using Operation = TexturingRegs::TevStageConfig::Operation;
auto GetSource = [&](Source source) -> Math::Vec4<u8> {
switch (source) {
@@ -862,54 +867,54 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
combiner_buffer = next_combiner_buffer;
- if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(
+ if (regs.texturing.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(
tev_stage_index)) {
next_combiner_buffer.r() = combiner_output.r();
next_combiner_buffer.g() = combiner_output.g();
next_combiner_buffer.b() = combiner_output.b();
}
- if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(
+ if (regs.texturing.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(
tev_stage_index)) {
next_combiner_buffer.a() = combiner_output.a();
}
}
- const auto& output_merger = regs.output_merger;
+ const auto& output_merger = regs.framebuffer.output_merger;
// TODO: Does alpha testing happen before or after stencil?
if (output_merger.alpha_test.enable) {
bool pass = false;
switch (output_merger.alpha_test.func) {
- case Regs::CompareFunc::Never:
+ case FramebufferRegs::CompareFunc::Never:
pass = false;
break;
- case Regs::CompareFunc::Always:
+ case FramebufferRegs::CompareFunc::Always:
pass = true;
break;
- case Regs::CompareFunc::Equal:
+ case FramebufferRegs::CompareFunc::Equal:
pass = combiner_output.a() == output_merger.alpha_test.ref;
break;
- case Regs::CompareFunc::NotEqual:
+ case FramebufferRegs::CompareFunc::NotEqual:
pass = combiner_output.a() != output_merger.alpha_test.ref;
break;
- case Regs::CompareFunc::LessThan:
+ case FramebufferRegs::CompareFunc::LessThan:
pass = combiner_output.a() < output_merger.alpha_test.ref;
break;
- case Regs::CompareFunc::LessThanOrEqual:
+ case FramebufferRegs::CompareFunc::LessThanOrEqual:
pass = combiner_output.a() <= output_merger.alpha_test.ref;
break;
- case Regs::CompareFunc::GreaterThan:
+ case FramebufferRegs::CompareFunc::GreaterThan:
pass = combiner_output.a() > output_merger.alpha_test.ref;
break;
- case Regs::CompareFunc::GreaterThanOrEqual:
+ case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
pass = combiner_output.a() >= output_merger.alpha_test.ref;
break;
}
@@ -922,16 +927,16 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
// Not fully accurate. We'd have to know what data type is used to
// store the depth etc. Using float for now until we know more
// about Pica datatypes
- if (regs.fog_mode == Regs::FogMode::Fog) {
+ if (regs.texturing.fog_mode == TexturingRegs::FogMode::Fog) {
const Math::Vec3<u8> fog_color = {
- static_cast<u8>(regs.fog_color.r.Value()),
- static_cast<u8>(regs.fog_color.g.Value()),
- static_cast<u8>(regs.fog_color.b.Value()),
+ static_cast<u8>(regs.texturing.fog_color.r.Value()),
+ static_cast<u8>(regs.texturing.fog_color.g.Value()),
+ static_cast<u8>(regs.texturing.fog_color.b.Value()),
};
// Get index into fog LUT
float fog_index;
- if (g_state.regs.fog_flip) {
+ if (g_state.regs.texturing.fog_flip) {
fog_index = (1.0f - depth) * 128.0f;
} else {
fog_index = depth * 128.0f;
@@ -955,10 +960,10 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
u8 old_stencil = 0;
auto UpdateStencil = [stencil_test, x, y,
- &old_stencil](Pica::Regs::StencilAction action) {
+ &old_stencil](Pica::FramebufferRegs::StencilAction action) {
u8 new_stencil =
PerformStencilAction(action, old_stencil, stencil_test.reference_value);
- if (g_state.regs.framebuffer.allow_depth_stencil_write != 0)
+ if (g_state.regs.framebuffer.framebuffer.allow_depth_stencil_write != 0)
SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) |
(old_stencil & ~stencil_test.write_mask));
};
@@ -970,35 +975,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
bool pass = false;
switch (stencil_test.func) {
- case Regs::CompareFunc::Never:
+ case FramebufferRegs::CompareFunc::Never:
pass = false;
break;
- case Regs::CompareFunc::Always:
+ case FramebufferRegs::CompareFunc::Always:
pass = true;
break;
- case Regs::CompareFunc::Equal:
+ case FramebufferRegs::CompareFunc::Equal:
pass = (ref == dest);
break;
- case Regs::CompareFunc::NotEqual:
+ case FramebufferRegs::CompareFunc::NotEqual:
pass = (ref != dest);
break;
- case Regs::CompareFunc::LessThan:
+ case FramebufferRegs::CompareFunc::LessThan:
pass = (ref < dest);
break;
- case Regs::CompareFunc::LessThanOrEqual:
+ case FramebufferRegs::CompareFunc::LessThanOrEqual:
pass = (ref <= dest);
break;
- case Regs::CompareFunc::GreaterThan:
+ case FramebufferRegs::CompareFunc::GreaterThan:
pass = (ref > dest);
break;
- case Regs::CompareFunc::GreaterThanOrEqual:
+ case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
pass = (ref >= dest);
break;
}
@@ -1010,7 +1015,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
}
// Convert float to integer
- unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format);
+ unsigned num_bits =
+ FramebufferRegs::DepthBitsPerPixel(regs.framebuffer.framebuffer.depth_format);
u32 z = (u32)(depth * ((1 << num_bits) - 1));
if (output_merger.depth_test_enable) {
@@ -1019,35 +1025,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
bool pass = false;
switch (output_merger.depth_test_func) {
- case Regs::CompareFunc::Never:
+ case FramebufferRegs::CompareFunc::Never:
pass = false;
break;
- case Regs::CompareFunc::Always:
+ case FramebufferRegs::CompareFunc::Always:
pass = true;
break;
- case Regs::CompareFunc::Equal:
+ case FramebufferRegs::CompareFunc::Equal:
pass = z == ref_z;
break;
- case Regs::CompareFunc::NotEqual:
+ case FramebufferRegs::CompareFunc::NotEqual:
pass = z != ref_z;
break;
- case Regs::CompareFunc::LessThan:
+ case FramebufferRegs::CompareFunc::LessThan:
pass = z < ref_z;
break;
- case Regs::CompareFunc::LessThanOrEqual:
+ case FramebufferRegs::CompareFunc::LessThanOrEqual:
pass = z <= ref_z;
break;
- case Regs::CompareFunc::GreaterThan:
+ case FramebufferRegs::CompareFunc::GreaterThan:
pass = z > ref_z;
break;
- case Regs::CompareFunc::GreaterThanOrEqual:
+ case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
pass = z >= ref_z;
break;
}
@@ -1059,8 +1065,11 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
}
}
- if (regs.framebuffer.allow_depth_stencil_write != 0 && output_merger.depth_write_enable)
+ if (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 &&
+ output_merger.depth_write_enable) {
+
SetDepth(x >> 4, y >> 4, z);
+ }
// The stencil depth_pass action is executed even if depth testing is disabled
if (stencil_action_enable)
@@ -1072,7 +1081,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
if (output_merger.alphablend_enable) {
auto params = output_merger.alpha_blending;
- auto LookupFactor = [&](unsigned channel, Regs::BlendFactor factor) -> u8 {
+ auto LookupFactor = [&](unsigned channel,
+ FramebufferRegs::BlendFactor factor) -> u8 {
DEBUG_ASSERT(channel < 4);
const Math::Vec4<u8> blend_const = {
@@ -1083,49 +1093,49 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
};
switch (factor) {
- case Regs::BlendFactor::Zero:
+ case FramebufferRegs::BlendFactor::Zero:
return 0;
- case Regs::BlendFactor::One:
+ case FramebufferRegs::BlendFactor::One:
return 255;
- case Regs::BlendFactor::SourceColor:
+ case FramebufferRegs::BlendFactor::SourceColor:
return combiner_output[channel];
- case Regs::BlendFactor::OneMinusSourceColor:
+ case FramebufferRegs::BlendFactor::OneMinusSourceColor:
return 255 - combiner_output[channel];
- case Regs::BlendFactor::DestColor:
+ case FramebufferRegs::BlendFactor::DestColor:
return dest[channel];
- case Regs::BlendFactor::OneMinusDestColor:
+ case FramebufferRegs::BlendFactor::OneMinusDestColor:
return 255 - dest[channel];
- case Regs::BlendFactor::SourceAlpha:
+ case FramebufferRegs::BlendFactor::SourceAlpha:
return combiner_output.a();
- case Regs::BlendFactor::OneMinusSourceAlpha:
+ case FramebufferRegs::BlendFactor::OneMinusSourceAlpha:
return 255 - combiner_output.a();
- case Regs::BlendFactor::DestAlpha:
+ case FramebufferRegs::BlendFactor::DestAlpha:
return dest.a();
- case Regs::BlendFactor::OneMinusDestAlpha:
+ case FramebufferRegs::BlendFactor::OneMinusDestAlpha:
return 255 - dest.a();
- case Regs::BlendFactor::ConstantColor:
+ case FramebufferRegs::BlendFactor::ConstantColor:
return blend_const[channel];
- case Regs::BlendFactor::OneMinusConstantColor:
+ case FramebufferRegs::BlendFactor::OneMinusConstantColor:
return 255 - blend_const[channel];
- case Regs::BlendFactor::ConstantAlpha:
+ case FramebufferRegs::BlendFactor::ConstantAlpha:
return blend_const.a();
- case Regs::BlendFactor::OneMinusConstantAlpha:
+ case FramebufferRegs::BlendFactor::OneMinusConstantAlpha:
return 255 - blend_const.a();
- case Regs::BlendFactor::SourceAlphaSaturate:
+ case FramebufferRegs::BlendFactor::SourceAlphaSaturate:
// Returns 1.0 for the alpha channel
if (channel == 3)
return 255;
@@ -1143,36 +1153,37 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
static auto EvaluateBlendEquation = [](
const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
- Regs::BlendEquation equation) {
+ FramebufferRegs::BlendEquation equation) {
+
Math::Vec4<int> result;
auto src_result = (src * srcfactor).Cast<int>();
auto dst_result = (dest * destfactor).Cast<int>();
switch (equation) {
- case Regs::BlendEquation::Add:
+ case FramebufferRegs::BlendEquation::Add:
result = (src_result + dst_result) / 255;
break;
- case Regs::BlendEquation::Subtract:
+ case FramebufferRegs::BlendEquation::Subtract:
result = (src_result - dst_result) / 255;
break;
- case Regs::BlendEquation::ReverseSubtract:
+ case FramebufferRegs::BlendEquation::ReverseSubtract:
result = (dst_result - src_result) / 255;
break;
// TODO: How do these two actually work?
// OpenGL doesn't include the blend factors in the min/max computations,
// but is this what the 3DS actually does?
- case Regs::BlendEquation::Min:
+ case FramebufferRegs::BlendEquation::Min:
result.r() = std::min(src.r(), dest.r());
result.g() = std::min(src.g(), dest.g());
result.b() = std::min(src.b(), dest.b());
result.a() = std::min(src.a(), dest.a());
break;
- case Regs::BlendEquation::Max:
+ case FramebufferRegs::BlendEquation::Max:
result.r() = std::max(src.r(), dest.r());
result.g() = std::max(src.g(), dest.g());
result.b() = std::max(src.b(), dest.b());
@@ -1205,54 +1216,54 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
dstfactor, params.blend_equation_a)
.a();
} else {
- static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 {
+ static auto LogicOp = [](u8 src, u8 dest, FramebufferRegs::LogicOp op) -> u8 {
switch (op) {
- case Regs::LogicOp::Clear:
+ case FramebufferRegs::LogicOp::Clear:
return 0;
- case Regs::LogicOp::And:
+ case FramebufferRegs::LogicOp::And:
return src & dest;
- case Regs::LogicOp::AndReverse:
+ case FramebufferRegs::LogicOp::AndReverse:
return src & ~dest;
- case Regs::LogicOp::Copy:
+ case FramebufferRegs::LogicOp::Copy:
return src;
- case Regs::LogicOp::Set:
+ case FramebufferRegs::LogicOp::Set:
return 255;
- case Regs::LogicOp::CopyInverted:
+ case FramebufferRegs::LogicOp::CopyInverted:
return ~src;
- case Regs::LogicOp::NoOp:
+ case FramebufferRegs::LogicOp::NoOp:
return dest;
- case Regs::LogicOp::Invert:
+ case FramebufferRegs::LogicOp::Invert:
return ~dest;
- case Regs::LogicOp::Nand:
+ case FramebufferRegs::LogicOp::Nand:
return ~(src & dest);
- case Regs::LogicOp::Or:
+ case FramebufferRegs::LogicOp::Or:
return src | dest;
- case Regs::LogicOp::Nor:
+ case FramebufferRegs::LogicOp::Nor:
return ~(src | dest);
- case Regs::LogicOp::Xor:
+ case FramebufferRegs::LogicOp::Xor:
return src ^ dest;
- case Regs::LogicOp::Equiv:
+ case FramebufferRegs::LogicOp::Equiv:
return ~(src ^ dest);
- case Regs::LogicOp::AndInverted:
+ case FramebufferRegs::LogicOp::AndInverted:
return ~src & dest;
- case Regs::LogicOp::OrReverse:
+ case FramebufferRegs::LogicOp::OrReverse:
return src | ~dest;
- case Regs::LogicOp::OrInverted:
+ case FramebufferRegs::LogicOp::OrInverted:
return ~src | dest;
}
};
@@ -1271,7 +1282,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
output_merger.alpha_enable ? blend_output.a() : dest.a(),
};
- if (regs.framebuffer.allow_color_write != 0)
+ if (regs.framebuffer.framebuffer.allow_color_write != 0)
DrawPixel(x >> 4, y >> 4, result);
}
}
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 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <iterator>
+#include <unordered_map>
+#include <utility>
+
+#include "common/common_types.h"
+#include "video_core/regs.h"
+
+namespace Pica {
+
+static const std::pair<u16, const char*> register_names[] = {
+ {0x010, "GPUREG_FINALIZE"},
+
+ {0x040, "GPUREG_FACECULLING_CONFIG"},
+ {0x041, "GPUREG_VIEWPORT_WIDTH"},
+ {0x042, "GPUREG_VIEWPORT_INVW"},
+ {0x043, "GPUREG_VIEWPORT_HEIGHT"},
+ {0x044, "GPUREG_VIEWPORT_INVH"},
+
+ {0x047, "GPUREG_FRAGOP_CLIP"},
+ {0x048, "GPUREG_FRAGOP_CLIP_DATA0"},
+ {0x049, "GPUREG_FRAGOP_CLIP_DATA1"},
+ {0x04A, "GPUREG_FRAGOP_CLIP_DATA2"},
+ {0x04B, "GPUREG_FRAGOP_CLIP_DATA3"},
+
+ {0x04D, "GPUREG_DEPTHMAP_SCALE"},
+ {0x04E, "GPUREG_DEPTHMAP_OFFSET"},
+ {0x04F, "GPUREG_SH_OUTMAP_TOTAL"},
+ {0x050, "GPUREG_SH_OUTMAP_O0"},
+ {0x051, "GPUREG_SH_OUTMAP_O1"},
+ {0x052, "GPUREG_SH_OUTMAP_O2"},
+ {0x053, "GPUREG_SH_OUTMAP_O3"},
+ {0x054, "GPUREG_SH_OUTMAP_O4"},
+ {0x055, "GPUREG_SH_OUTMAP_O5"},
+ {0x056, "GPUREG_SH_OUTMAP_O6"},
+
+ {0x061, "GPUREG_EARLYDEPTH_FUNC"},
+ {0x062, "GPUREG_EARLYDEPTH_TEST1"},
+ {0x063, "GPUREG_EARLYDEPTH_CLEAR"},
+ {0x064, "GPUREG_SH_OUTATTR_MODE"},
+ {0x065, "GPUREG_SCISSORTEST_MODE"},
+ {0x066, "GPUREG_SCISSORTEST_POS"},
+ {0x067, "GPUREG_SCISSORTEST_DIM"},
+ {0x068, "GPUREG_VIEWPORT_XY"},
+
+ {0x06A, "GPUREG_EARLYDEPTH_DATA"},
+
+ {0x06D, "GPUREG_DEPTHMAP_ENABLE"},
+ {0x06E, "GPUREG_RENDERBUF_DIM"},
+ {0x06F, "GPUREG_SH_OUTATTR_CLOCK"},
+
+ {0x080, "GPUREG_TEXUNIT_CONFIG"},
+ {0x081, "GPUREG_TEXUNIT0_BORDER_COLOR"},
+ {0x082, "GPUREG_TEXUNIT0_DIM"},
+ {0x083, "GPUREG_TEXUNIT0_PARAM"},
+ {0x084, "GPUREG_TEXUNIT0_LOD"},
+ {0x085, "GPUREG_TEXUNIT0_ADDR1"},
+ {0x086, "GPUREG_TEXUNIT0_ADDR2"},
+ {0x087, "GPUREG_TEXUNIT0_ADDR3"},
+ {0x088, "GPUREG_TEXUNIT0_ADDR4"},
+ {0x089, "GPUREG_TEXUNIT0_ADDR5"},
+ {0x08A, "GPUREG_TEXUNIT0_ADDR6"},
+ {0x08B, "GPUREG_TEXUNIT0_SHADOW"},
+
+ {0x08E, "GPUREG_TEXUNIT0_TYPE"},
+ {0x08F, "GPUREG_LIGHTING_ENABLE0"},
+
+ {0x091, "GPUREG_TEXUNIT1_BORDER_COLOR"},
+ {0x092, "GPUREG_TEXUNIT1_DIM"},
+ {0x093, "GPUREG_TEXUNIT1_PARAM"},
+ {0x094, "GPUREG_TEXUNIT1_LOD"},
+ {0x095, "GPUREG_TEXUNIT1_ADDR"},
+ {0x096, "GPUREG_TEXUNIT1_TYPE"},
+
+ {0x099, "GPUREG_TEXUNIT2_BORDER_COLOR"},
+ {0x09A, "GPUREG_TEXUNIT2_DIM"},
+ {0x09B, "GPUREG_TEXUNIT2_PARAM"},
+ {0x09C, "GPUREG_TEXUNIT2_LOD"},
+ {0x09D, "GPUREG_TEXUNIT2_ADDR"},
+ {0x09E, "GPUREG_TEXUNIT2_TYPE"},
+
+ {0x0A8, "GPUREG_TEXUNIT3_PROCTEX0"},
+ {0x0A9, "GPUREG_TEXUNIT3_PROCTEX1"},
+ {0x0AA, "GPUREG_TEXUNIT3_PROCTEX2"},
+ {0x0AB, "GPUREG_TEXUNIT3_PROCTEX3"},
+ {0x0AC, "GPUREG_TEXUNIT3_PROCTEX4"},
+ {0x0AD, "GPUREG_TEXUNIT3_PROCTEX5"},
+
+ {0x0AF, "GPUREG_PROCTEX_LUT"},
+ {0x0B0, "GPUREG_PROCTEX_LUT_DATA0"},
+ {0x0B1, "GPUREG_PROCTEX_LUT_DATA1"},
+ {0x0B2, "GPUREG_PROCTEX_LUT_DATA2"},
+ {0x0B3, "GPUREG_PROCTEX_LUT_DATA3"},
+ {0x0B4, "GPUREG_PROCTEX_LUT_DATA4"},
+ {0x0B5, "GPUREG_PROCTEX_LUT_DATA5"},
+ {0x0B6, "GPUREG_PROCTEX_LUT_DATA6"},
+ {0x0B7, "GPUREG_PROCTEX_LUT_DATA7"},
+
+ {0x0C0, "GPUREG_TEXENV0_SOURCE"},
+ {0x0C1, "GPUREG_TEXENV0_OPERAND"},
+ {0x0C2, "GPUREG_TEXENV0_COMBINER"},
+ {0x0C3, "GPUREG_TEXENV0_COLOR"},
+ {0x0C4, "GPUREG_TEXENV0_SCALE"},
+
+ {0x0C8, "GPUREG_TEXENV1_SOURCE"},
+ {0x0C9, "GPUREG_TEXENV1_OPERAND"},
+ {0x0CA, "GPUREG_TEXENV1_COMBINER"},
+ {0x0CB, "GPUREG_TEXENV1_COLOR"},
+ {0x0CC, "GPUREG_TEXENV1_SCALE"},
+
+ {0x0D0, "GPUREG_TEXENV2_SOURCE"},
+ {0x0D1, "GPUREG_TEXENV2_OPERAND"},
+ {0x0D2, "GPUREG_TEXENV2_COMBINER"},
+ {0x0D3, "GPUREG_TEXENV2_COLOR"},
+ {0x0D4, "GPUREG_TEXENV2_SCALE"},
+
+ {0x0D8, "GPUREG_TEXENV3_SOURCE"},
+ {0x0D9, "GPUREG_TEXENV3_OPERAND"},
+ {0x0DA, "GPUREG_TEXENV3_COMBINER"},
+ {0x0DB, "GPUREG_TEXENV3_COLOR"},
+ {0x0DC, "GPUREG_TEXENV3_SCALE"},
+
+ {0x0E0, "GPUREG_TEXENV_UPDATE_BUFFER"},
+ {0x0E1, "GPUREG_FOG_COLOR"},
+
+ {0x0E4, "GPUREG_GAS_ATTENUATION"},
+ {0x0E5, "GPUREG_GAS_ACCMAX"},
+ {0x0E6, "GPUREG_FOG_LUT_INDEX"},
+
+ {0x0E8, "GPUREG_FOG_LUT_DATA0"},
+ {0x0E9, "GPUREG_FOG_LUT_DATA1"},
+ {0x0EA, "GPUREG_FOG_LUT_DATA2"},
+ {0x0EB, "GPUREG_FOG_LUT_DATA3"},
+ {0x0EC, "GPUREG_FOG_LUT_DATA4"},
+ {0x0ED, "GPUREG_FOG_LUT_DATA5"},
+ {0x0EE, "GPUREG_FOG_LUT_DATA6"},
+ {0x0EF, "GPUREG_FOG_LUT_DATA7"},
+ {0x0F0, "GPUREG_TEXENV4_SOURCE"},
+ {0x0F1, "GPUREG_TEXENV4_OPERAND"},
+ {0x0F2, "GPUREG_TEXENV4_COMBINER"},
+ {0x0F3, "GPUREG_TEXENV4_COLOR"},
+ {0x0F4, "GPUREG_TEXENV4_SCALE"},
+
+ {0x0F8, "GPUREG_TEXENV5_SOURCE"},
+ {0x0F9, "GPUREG_TEXENV5_OPERAND"},
+ {0x0FA, "GPUREG_TEXENV5_COMBINER"},
+ {0x0FB, "GPUREG_TEXENV5_COLOR"},
+ {0x0FC, "GPUREG_TEXENV5_SCALE"},
+ {0x0FD, "GPUREG_TEXENV_BUFFER_COLOR"},
+
+ {0x100, "GPUREG_COLOR_OPERATION"},
+ {0x101, "GPUREG_BLEND_FUNC"},
+ {0x102, "GPUREG_LOGIC_OP"},
+ {0x103, "GPUREG_BLEND_COLOR"},
+ {0x104, "GPUREG_FRAGOP_ALPHA_TEST"},
+ {0x105, "GPUREG_STENCIL_TEST"},
+ {0x106, "GPUREG_STENCIL_OP"},
+ {0x107, "GPUREG_DEPTH_COLOR_MASK"},
+
+ {0x110, "GPUREG_FRAMEBUFFER_INVALIDATE"},
+ {0x111, "GPUREG_FRAMEBUFFER_FLUSH"},
+ {0x112, "GPUREG_COLORBUFFER_READ"},
+ {0x113, "GPUREG_COLORBUFFER_WRITE"},
+ {0x114, "GPUREG_DEPTHBUFFER_READ"},
+ {0x115, "GPUREG_DEPTHBUFFER_WRITE"},
+ {0x116, "GPUREG_DEPTHBUFFER_FORMAT"},
+ {0x117, "GPUREG_COLORBUFFER_FORMAT"},
+ {0x118, "GPUREG_EARLYDEPTH_TEST2"},
+
+ {0x11B, "GPUREG_FRAMEBUFFER_BLOCK32"},
+ {0x11C, "GPUREG_DEPTHBUFFER_LOC"},
+ {0x11D, "GPUREG_COLORBUFFER_LOC"},
+ {0x11E, "GPUREG_FRAMEBUFFER_DIM"},
+
+ {0x120, "GPUREG_GAS_LIGHT_XY"},
+ {0x121, "GPUREG_GAS_LIGHT_Z"},
+ {0x122, "GPUREG_GAS_LIGHT_Z_COLOR"},
+ {0x123, "GPUREG_GAS_LUT_INDEX"},
+ {0x124, "GPUREG_GAS_LUT_DATA"},
+
+ {0x126, "GPUREG_GAS_DELTAZ_DEPTH"},
+
+ {0x130, "GPUREG_FRAGOP_SHADOW"},
+
+ {0x140, "GPUREG_LIGHT0_SPECULAR0"},
+ {0x141, "GPUREG_LIGHT0_SPECULAR1"},
+ {0x142, "GPUREG_LIGHT0_DIFFUSE"},
+ {0x143, "GPUREG_LIGHT0_AMBIENT"},
+ {0x144, "GPUREG_LIGHT0_XY"},
+ {0x145, "GPUREG_LIGHT0_Z"},
+ {0x146, "GPUREG_LIGHT0_SPOTDIR_XY"},
+ {0x147, "GPUREG_LIGHT0_SPOTDIR_Z"},
+
+ {0x149, "GPUREG_LIGHT0_CONFIG"},
+ {0x14A, "GPUREG_LIGHT0_ATTENUATION_BIAS"},
+ {0x14B, "GPUREG_LIGHT0_ATTENUATION_SCALE"},
+
+ {0x150, "GPUREG_LIGHT1_SPECULAR0"},
+ {0x151, "GPUREG_LIGHT1_SPECULAR1"},
+ {0x152, "GPUREG_LIGHT1_DIFFUSE"},
+ {0x153, "GPUREG_LIGHT1_AMBIENT"},
+ {0x154, "GPUREG_LIGHT1_XY"},
+ {0x155, "GPUREG_LIGHT1_Z"},
+ {0x156, "GPUREG_LIGHT1_SPOTDIR_XY"},
+ {0x157, "GPUREG_LIGHT1_SPOTDIR_Z"},
+
+ {0x159, "GPUREG_LIGHT1_CONFIG"},
+ {0x15A, "GPUREG_LIGHT1_ATTENUATION_BIAS"},
+ {0x15B, "GPUREG_LIGHT1_ATTENUATION_SCALE"},
+
+ {0x160, "GPUREG_LIGHT2_SPECULAR0"},
+ {0x161, "GPUREG_LIGHT2_SPECULAR1"},
+ {0x162, "GPUREG_LIGHT2_DIFFUSE"},
+ {0x163, "GPUREG_LIGHT2_AMBIENT"},
+ {0x164, "GPUREG_LIGHT2_XY"},
+ {0x165, "GPUREG_LIGHT2_Z"},
+ {0x166, "GPUREG_LIGHT2_SPOTDIR_XY"},
+ {0x167, "GPUREG_LIGHT2_SPOTDIR_Z"},
+
+ {0x169, "GPUREG_LIGHT2_CONFIG"},
+ {0x16A, "GPUREG_LIGHT2_ATTENUATION_BIAS"},
+ {0x16B, "GPUREG_LIGHT2_ATTENUATION_SCALE"},
+
+ {0x170, "GPUREG_LIGHT3_SPECULAR0"},
+ {0x171, "GPUREG_LIGHT3_SPECULAR1"},
+ {0x172, "GPUREG_LIGHT3_DIFFUSE"},
+ {0x173, "GPUREG_LIGHT3_AMBIENT"},
+ {0x174, "GPUREG_LIGHT3_XY"},
+ {0x175, "GPUREG_LIGHT3_Z"},
+ {0x176, "GPUREG_LIGHT3_SPOTDIR_XY"},
+ {0x177, "GPUREG_LIGHT3_SPOTDIR_Z"},
+
+ {0x179, "GPUREG_LIGHT3_CONFIG"},
+ {0x17A, "GPUREG_LIGHT3_ATTENUATION_BIAS"},
+ {0x17B, "GPUREG_LIGHT3_ATTENUATION_SCALE"},
+
+ {0x180, "GPUREG_LIGHT4_SPECULAR0"},
+ {0x181, "GPUREG_LIGHT4_SPECULAR1"},
+ {0x182, "GPUREG_LIGHT4_DIFFUSE"},
+ {0x183, "GPUREG_LIGHT4_AMBIENT"},
+ {0x184, "GPUREG_LIGHT4_XY"},
+ {0x185, "GPUREG_LIGHT4_Z"},
+ {0x186, "GPUREG_LIGHT4_SPOTDIR_XY"},
+ {0x187, "GPUREG_LIGHT4_SPOTDIR_Z"},
+
+ {0x189, "GPUREG_LIGHT4_CONFIG"},
+ {0x18A, "GPUREG_LIGHT4_ATTENUATION_BIAS"},
+ {0x18B, "GPUREG_LIGHT4_ATTENUATION_SCALE"},
+
+ {0x190, "GPUREG_LIGHT5_SPECULAR0"},
+ {0x191, "GPUREG_LIGHT5_SPECULAR1"},
+ {0x192, "GPUREG_LIGHT5_DIFFUSE"},
+ {0x193, "GPUREG_LIGHT5_AMBIENT"},
+ {0x194, "GPUREG_LIGHT5_XY"},
+ {0x195, "GPUREG_LIGHT5_Z"},
+ {0x196, "GPUREG_LIGHT5_SPOTDIR_XY"},
+ {0x197, "GPUREG_LIGHT5_SPOTDIR_Z"},
+
+ {0x199, "GPUREG_LIGHT5_CONFIG"},
+ {0x19A, "GPUREG_LIGHT5_ATTENUATION_BIAS"},
+ {0x19B, "GPUREG_LIGHT5_ATTENUATION_SCALE"},
+
+ {0x1A0, "GPUREG_LIGHT6_SPECULAR0"},
+ {0x1A1, "GPUREG_LIGHT6_SPECULAR1"},
+ {0x1A2, "GPUREG_LIGHT6_DIFFUSE"},
+ {0x1A3, "GPUREG_LIGHT6_AMBIENT"},
+ {0x1A4, "GPUREG_LIGHT6_XY"},
+ {0x1A5, "GPUREG_LIGHT6_Z"},
+ {0x1A6, "GPUREG_LIGHT6_SPOTDIR_XY"},
+ {0x1A7, "GPUREG_LIGHT6_SPOTDIR_Z"},
+
+ {0x1A9, "GPUREG_LIGHT6_CONFIG"},
+ {0x1AA, "GPUREG_LIGHT6_ATTENUATION_BIAS"},
+ {0x1AB, "GPUREG_LIGHT6_ATTENUATION_SCALE"},
+
+ {0x1B0, "GPUREG_LIGHT7_SPECULAR0"},
+ {0x1B1, "GPUREG_LIGHT7_SPECULAR1"},
+ {0x1B2, "GPUREG_LIGHT7_DIFFUSE"},
+ {0x1B3, "GPUREG_LIGHT7_AMBIENT"},
+ {0x1B4, "GPUREG_LIGHT7_XY"},
+ {0x1B5, "GPUREG_LIGHT7_Z"},
+ {0x1B6, "GPUREG_LIGHT7_SPOTDIR_XY"},
+ {0x1B7, "GPUREG_LIGHT7_SPOTDIR_Z"},
+
+ {0x1B9, "GPUREG_LIGHT7_CONFIG"},
+ {0x1BA, "GPUREG_LIGHT7_ATTENUATION_BIAS"},
+ {0x1BB, "GPUREG_LIGHT7_ATTENUATION_SCALE"},
+
+ {0x1C0, "GPUREG_LIGHTING_AMBIENT"},
+
+ {0x1C2, "GPUREG_LIGHTING_NUM_LIGHTS"},
+ {0x1C3, "GPUREG_LIGHTING_CONFIG0"},
+ {0x1C4, "GPUREG_LIGHTING_CONFIG1"},
+ {0x1C5, "GPUREG_LIGHTING_LUT_INDEX"},
+ {0x1C6, "GPUREG_LIGHTING_ENABLE1"},
+
+ {0x1C8, "GPUREG_LIGHTING_LUT_DATA0"},
+ {0x1C9, "GPUREG_LIGHTING_LUT_DATA1"},
+ {0x1CA, "GPUREG_LIGHTING_LUT_DATA2"},
+ {0x1CB, "GPUREG_LIGHTING_LUT_DATA3"},
+ {0x1CC, "GPUREG_LIGHTING_LUT_DATA4"},
+ {0x1CD, "GPUREG_LIGHTING_LUT_DATA5"},
+ {0x1CE, "GPUREG_LIGHTING_LUT_DATA6"},
+ {0x1CF, "GPUREG_LIGHTING_LUT_DATA7"},
+ {0x1D0, "GPUREG_LIGHTING_LUTINPUT_ABS"},
+ {0x1D1, "GPUREG_LIGHTING_LUTINPUT_SELECT"},
+ {0x1D2, "GPUREG_LIGHTING_LUTINPUT_SCALE"},
+
+ {0x1D9, "GPUREG_LIGHTING_LIGHT_PERMUTATION"},
+
+ {0x200, "GPUREG_ATTRIBBUFFERS_LOC"},
+ {0x201, "GPUREG_ATTRIBBUFFERS_FORMAT_LOW"},
+ {0x202, "GPUREG_ATTRIBBUFFERS_FORMAT_HIGH"},
+ {0x203, "GPUREG_ATTRIBBUFFER0_OFFSET"},
+ {0x204, "GPUREG_ATTRIBBUFFER0_CONFIG1"},
+ {0x205, "GPUREG_ATTRIBBUFFER0_CONFIG2"},
+ {0x206, "GPUREG_ATTRIBBUFFER1_OFFSET"},
+ {0x207, "GPUREG_ATTRIBBUFFER1_CONFIG1"},
+ {0x208, "GPUREG_ATTRIBBUFFER1_CONFIG2"},
+ {0x209, "GPUREG_ATTRIBBUFFER2_OFFSET"},
+ {0x20A, "GPUREG_ATTRIBBUFFER2_CONFIG1"},
+ {0x20B, "GPUREG_ATTRIBBUFFER2_CONFIG2"},
+ {0x20C, "GPUREG_ATTRIBBUFFER3_OFFSET"},
+ {0x20D, "GPUREG_ATTRIBBUFFER3_CONFIG1"},
+ {0x20E, "GPUREG_ATTRIBBUFFER3_CONFIG2"},
+ {0x20F, "GPUREG_ATTRIBBUFFER4_OFFSET"},
+ {0x210, "GPUREG_ATTRIBBUFFER4_CONFIG1"},
+ {0x211, "GPUREG_ATTRIBBUFFER4_CONFIG2"},
+ {0x212, "GPUREG_ATTRIBBUFFER5_OFFSET"},
+ {0x213, "GPUREG_ATTRIBBUFFER5_CONFIG1"},
+ {0x214, "GPUREG_ATTRIBBUFFER5_CONFIG2"},
+ {0x215, "GPUREG_ATTRIBBUFFER6_OFFSET"},
+ {0x216, "GPUREG_ATTRIBBUFFER6_CONFIG1"},
+ {0x217, "GPUREG_ATTRIBBUFFER6_CONFIG2"},
+ {0x218, "GPUREG_ATTRIBBUFFER7_OFFSET"},
+ {0x219, "GPUREG_ATTRIBBUFFER7_CONFIG1"},
+ {0x21A, "GPUREG_ATTRIBBUFFER7_CONFIG2"},
+ {0x21B, "GPUREG_ATTRIBBUFFER8_OFFSET"},
+ {0x21C, "GPUREG_ATTRIBBUFFER8_CONFIG1"},
+ {0x21D, "GPUREG_ATTRIBBUFFER8_CONFIG2"},
+ {0x21E, "GPUREG_ATTRIBBUFFER9_OFFSET"},
+ {0x21F, "GPUREG_ATTRIBBUFFER9_CONFIG1"},
+ {0x220, "GPUREG_ATTRIBBUFFER9_CONFIG2"},
+ {0x221, "GPUREG_ATTRIBBUFFER10_OFFSET"},
+ {0x222, "GPUREG_ATTRIBBUFFER10_CONFIG1"},
+ {0x223, "GPUREG_ATTRIBBUFFER10_CONFIG2"},
+ {0x224, "GPUREG_ATTRIBBUFFER11_OFFSET"},
+ {0x225, "GPUREG_ATTRIBBUFFER11_CONFIG1"},
+ {0x226, "GPUREG_ATTRIBBUFFER11_CONFIG2"},
+ {0x227, "GPUREG_INDEXBUFFER_CONFIG"},
+ {0x228, "GPUREG_NUMVERTICES"},
+ {0x229, "GPUREG_GEOSTAGE_CONFIG"},
+ {0x22A, "GPUREG_VERTEX_OFFSET"},
+
+ {0x22D, "GPUREG_POST_VERTEX_CACHE_NUM"},
+ {0x22E, "GPUREG_DRAWARRAYS"},
+ {0x22F, "GPUREG_DRAWELEMENTS"},
+
+ {0x231, "GPUREG_VTX_FUNC"},
+ {0x232, "GPUREG_FIXEDATTRIB_INDEX"},
+ {0x233, "GPUREG_FIXEDATTRIB_DATA0"},
+ {0x234, "GPUREG_FIXEDATTRIB_DATA1"},
+ {0x235, "GPUREG_FIXEDATTRIB_DATA2"},
+
+ {0x238, "GPUREG_CMDBUF_SIZE0"},
+ {0x239, "GPUREG_CMDBUF_SIZE1"},
+ {0x23A, "GPUREG_CMDBUF_ADDR0"},
+ {0x23B, "GPUREG_CMDBUF_ADDR1"},
+ {0x23C, "GPUREG_CMDBUF_JUMP0"},
+ {0x23D, "GPUREG_CMDBUF_JUMP1"},
+
+ {0x242, "GPUREG_VSH_NUM_ATTR"},
+
+ {0x244, "GPUREG_VSH_COM_MODE"},
+ {0x245, "GPUREG_START_DRAW_FUNC0"},
+
+ {0x24A, "GPUREG_VSH_OUTMAP_TOTAL1"},
+
+ {0x251, "GPUREG_VSH_OUTMAP_TOTAL2"},
+ {0x252, "GPUREG_GSH_MISC0"},
+ {0x253, "GPUREG_GEOSTAGE_CONFIG2"},
+ {0x254, "GPUREG_GSH_MISC1"},
+
+ {0x25E, "GPUREG_PRIMITIVE_CONFIG"},
+ {0x25F, "GPUREG_RESTART_PRIMITIVE"},
+
+ {0x280, "GPUREG_GSH_BOOLUNIFORM"},
+ {0x281, "GPUREG_GSH_INTUNIFORM_I0"},
+ {0x282, "GPUREG_GSH_INTUNIFORM_I1"},
+ {0x283, "GPUREG_GSH_INTUNIFORM_I2"},
+ {0x284, "GPUREG_GSH_INTUNIFORM_I3"},
+
+ {0x289, "GPUREG_GSH_INPUTBUFFER_CONFIG"},
+ {0x28A, "GPUREG_GSH_ENTRYPOINT"},
+ {0x28B, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_LOW"},
+ {0x28C, "GPUREG_GSH_ATTRIBUTES_PERMUTATION_HIGH"},
+ {0x28D, "GPUREG_GSH_OUTMAP_MASK"},
+
+ {0x28F, "GPUREG_GSH_CODETRANSFER_END"},
+ {0x290, "GPUREG_GSH_FLOATUNIFORM_INDEX"},
+ {0x291, "GPUREG_GSH_FLOATUNIFORM_DATA0"},
+ {0x292, "GPUREG_GSH_FLOATUNIFORM_DATA1"},
+ {0x293, "GPUREG_GSH_FLOATUNIFORM_DATA2"},
+ {0x294, "GPUREG_GSH_FLOATUNIFORM_DATA3"},
+ {0x295, "GPUREG_GSH_FLOATUNIFORM_DATA4"},
+ {0x296, "GPUREG_GSH_FLOATUNIFORM_DATA5"},
+ {0x297, "GPUREG_GSH_FLOATUNIFORM_DATA6"},
+ {0x298, "GPUREG_GSH_FLOATUNIFORM_DATA7"},
+
+ {0x29B, "GPUREG_GSH_CODETRANSFER_INDEX"},
+ {0x29C, "GPUREG_GSH_CODETRANSFER_DATA0"},
+ {0x29D, "GPUREG_GSH_CODETRANSFER_DATA1"},
+ {0x29E, "GPUREG_GSH_CODETRANSFER_DATA2"},
+ {0x29F, "GPUREG_GSH_CODETRANSFER_DATA3"},
+ {0x2A0, "GPUREG_GSH_CODETRANSFER_DATA4"},
+ {0x2A1, "GPUREG_GSH_CODETRANSFER_DATA5"},
+ {0x2A2, "GPUREG_GSH_CODETRANSFER_DATA6"},
+ {0x2A3, "GPUREG_GSH_CODETRANSFER_DATA7"},
+
+ {0x2A5, "GPUREG_GSH_OPDESCS_INDEX"},
+ {0x2A6, "GPUREG_GSH_OPDESCS_DATA0"},
+ {0x2A7, "GPUREG_GSH_OPDESCS_DATA1"},
+ {0x2A8, "GPUREG_GSH_OPDESCS_DATA2"},
+ {0x2A9, "GPUREG_GSH_OPDESCS_DATA3"},
+ {0x2AA, "GPUREG_GSH_OPDESCS_DATA4"},
+ {0x2AB, "GPUREG_GSH_OPDESCS_DATA5"},
+ {0x2AC, "GPUREG_GSH_OPDESCS_DATA6"},
+ {0x2AD, "GPUREG_GSH_OPDESCS_DATA7"},
+
+ {0x2B0, "GPUREG_VSH_BOOLUNIFORM"},
+ {0x2B1, "GPUREG_VSH_INTUNIFORM_I0"},
+ {0x2B2, "GPUREG_VSH_INTUNIFORM_I1"},
+ {0x2B3, "GPUREG_VSH_INTUNIFORM_I2"},
+ {0x2B4, "GPUREG_VSH_INTUNIFORM_I3"},
+
+ {0x2B9, "GPUREG_VSH_INPUTBUFFER_CONFIG"},
+ {0x2BA, "GPUREG_VSH_ENTRYPOINT"},
+ {0x2BB, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW"},
+ {0x2BC, "GPUREG_VSH_ATTRIBUTES_PERMUTATION_HIGH"},
+ {0x2BD, "GPUREG_VSH_OUTMAP_MASK"},
+
+ {0x2BF, "GPUREG_VSH_CODETRANSFER_END"},
+ {0x2C0, "GPUREG_VSH_FLOATUNIFORM_INDEX"},
+ {0x2C1, "GPUREG_VSH_FLOATUNIFORM_DATA0"},
+ {0x2C2, "GPUREG_VSH_FLOATUNIFORM_DATA1"},
+ {0x2C3, "GPUREG_VSH_FLOATUNIFORM_DATA2"},
+ {0x2C4, "GPUREG_VSH_FLOATUNIFORM_DATA3"},
+ {0x2C5, "GPUREG_VSH_FLOATUNIFORM_DATA4"},
+ {0x2C6, "GPUREG_VSH_FLOATUNIFORM_DATA5"},
+ {0x2C7, "GPUREG_VSH_FLOATUNIFORM_DATA6"},
+ {0x2C8, "GPUREG_VSH_FLOATUNIFORM_DATA7"},
+
+ {0x2CB, "GPUREG_VSH_CODETRANSFER_INDEX"},
+ {0x2CC, "GPUREG_VSH_CODETRANSFER_DATA0"},
+ {0x2CD, "GPUREG_VSH_CODETRANSFER_DATA1"},
+ {0x2CE, "GPUREG_VSH_CODETRANSFER_DATA2"},
+ {0x2CF, "GPUREG_VSH_CODETRANSFER_DATA3"},
+ {0x2D0, "GPUREG_VSH_CODETRANSFER_DATA4"},
+ {0x2D1, "GPUREG_VSH_CODETRANSFER_DATA5"},
+ {0x2D2, "GPUREG_VSH_CODETRANSFER_DATA6"},
+ {0x2D3, "GPUREG_VSH_CODETRANSFER_DATA7"},
+
+ {0x2D5, "GPUREG_VSH_OPDESCS_INDEX"},
+ {0x2D6, "GPUREG_VSH_OPDESCS_DATA0"},
+ {0x2D7, "GPUREG_VSH_OPDESCS_DATA1"},
+ {0x2D8, "GPUREG_VSH_OPDESCS_DATA2"},
+ {0x2D9, "GPUREG_VSH_OPDESCS_DATA3"},
+ {0x2DA, "GPUREG_VSH_OPDESCS_DATA4"},
+ {0x2DB, "GPUREG_VSH_OPDESCS_DATA5"},
+ {0x2DC, "GPUREG_VSH_OPDESCS_DATA6"},
+ {0x2DD, "GPUREG_VSH_OPDESCS_DATA7"},
+};
+
+std::string Regs::GetCommandName(int index) {
+ static std::unordered_map<u32, const char*> map;
+
+ if (map.empty()) {
+ map.insert(std::begin(register_names), std::end(register_names));
+ }
+
+ // Return empty string if no match is found
+ auto it = map.find(index);
+ if (it != map.end()) {
+ return it->second;
+ } else {
+ return std::string();
+ }
+}
+
+} // 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 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <cstddef>
+#include <string>
+#ifndef _MSC_VER
+#include <type_traits> // for std::enable_if
+#endif
+
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "video_core/regs_framebuffer.h"
+#include "video_core/regs_lighting.h"
+#include "video_core/regs_pipeline.h"
+#include "video_core/regs_rasterizer.h"
+#include "video_core/regs_shader.h"
+#include "video_core/regs_texturing.h"
+
+namespace Pica {
+
+// Returns index corresponding to the Regs member labeled by field_name
+// TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions
+// when used with array elements (e.g. PICA_REG_INDEX(vs_uniform_setup.set_value[1])).
+// For details cf.
+// https://connect.microsoft.com/VisualStudio/feedback/details/209229/offsetof-does-not-produce-a-constant-expression-for-array-members
+// Hopefully, this will be fixed sometime in the future.
+// For lack of better alternatives, we currently hardcode the offsets when constant
+// expressions are needed via PICA_REG_INDEX_WORKAROUND (on sane compilers, static_asserts
+// will then make sure the offsets indeed match the automatically calculated ones).
+#define PICA_REG_INDEX(field_name) (offsetof(Pica::Regs, field_name) / sizeof(u32))
+#if defined(_MSC_VER)
+#define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) (backup_workaround_index)
+#else
+// NOTE: Yeah, hacking in a static_assert here just to workaround the lacking MSVC compiler
+// really is this annoying. This macro just forwards its first argument to PICA_REG_INDEX
+// and then performs a (no-op) cast to size_t iff the second argument matches the expected
+// field offset. Otherwise, the compiler will fail to compile this code.
+#define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) \
+ ((typename std::enable_if<backup_workaround_index == PICA_REG_INDEX(field_name), \
+ size_t>::type)PICA_REG_INDEX(field_name))
+#endif // _MSC_VER
+
+struct Regs {
+ INSERT_PADDING_WORDS(0x10);
+ u32 trigger_irq;
+ INSERT_PADDING_WORDS(0x2f);
+ RasterizerRegs rasterizer;
+ TexturingRegs texturing;
+ FramebufferRegs framebuffer;
+ LightingRegs lighting;
+ PipelineRegs pipeline;
+ ShaderRegs gs;
+ ShaderRegs vs;
+ INSERT_PADDING_WORDS(0x20);
+
+ // Map register indices to names readable by humans
+ // Used for debugging purposes, so performance is not an issue here
+ static std::string GetCommandName(int index);
+
+ static constexpr size_t NumIds() {
+ return sizeof(Regs) / sizeof(u32);
+ }
+
+ const u32& operator[](int index) const {
+ const u32* content = reinterpret_cast<const u32*>(this);
+ return content[index];
+ }
+
+ u32& operator[](int index) {
+ u32* content = reinterpret_cast<u32*>(this);
+ return content[index];
+ }
+
+private:
+ /*
+ * Most physical addresses which Pica registers refer to are 8-byte aligned.
+ * This function should be used to get the address from a raw register value.
+ */
+ static inline u32 DecodeAddressRegister(u32 register_value) {
+ return register_value * 8;
+ }
+};
+
+// TODO: MSVC does not support using offsetof() on non-static data members even though this
+// is technically allowed since C++11. This macro should be enabled once MSVC adds
+// support for that.
+#ifndef _MSC_VER
+#define ASSERT_REG_POSITION(field_name, position) \
+ static_assert(offsetof(Regs, field_name) == position * 4, \
+ "Field " #field_name " has invalid position")
+
+ASSERT_REG_POSITION(trigger_irq, 0x10);
+
+ASSERT_REG_POSITION(rasterizer, 0x40);
+ASSERT_REG_POSITION(rasterizer.cull_mode, 0x40);
+ASSERT_REG_POSITION(rasterizer.viewport_size_x, 0x41);
+ASSERT_REG_POSITION(rasterizer.viewport_size_y, 0x43);
+ASSERT_REG_POSITION(rasterizer.viewport_depth_range, 0x4d);
+ASSERT_REG_POSITION(rasterizer.viewport_depth_near_plane, 0x4e);
+ASSERT_REG_POSITION(rasterizer.vs_output_attributes[0], 0x50);
+ASSERT_REG_POSITION(rasterizer.vs_output_attributes[1], 0x51);
+ASSERT_REG_POSITION(rasterizer.scissor_test, 0x65);
+ASSERT_REG_POSITION(rasterizer.viewport_corner, 0x68);
+ASSERT_REG_POSITION(rasterizer.depthmap_enable, 0x6D);
+
+ASSERT_REG_POSITION(texturing, 0x80);
+ASSERT_REG_POSITION(texturing.texture0_enable, 0x80);
+ASSERT_REG_POSITION(texturing.texture0, 0x81);
+ASSERT_REG_POSITION(texturing.texture0_format, 0x8e);
+ASSERT_REG_POSITION(texturing.fragment_lighting_enable, 0x8f);
+ASSERT_REG_POSITION(texturing.texture1, 0x91);
+ASSERT_REG_POSITION(texturing.texture1_format, 0x96);
+ASSERT_REG_POSITION(texturing.texture2, 0x99);
+ASSERT_REG_POSITION(texturing.texture2_format, 0x9e);
+ASSERT_REG_POSITION(texturing.tev_stage0, 0xc0);
+ASSERT_REG_POSITION(texturing.tev_stage1, 0xc8);
+ASSERT_REG_POSITION(texturing.tev_stage2, 0xd0);
+ASSERT_REG_POSITION(texturing.tev_stage3, 0xd8);
+ASSERT_REG_POSITION(texturing.tev_combiner_buffer_input, 0xe0);
+ASSERT_REG_POSITION(texturing.fog_mode, 0xe0);
+ASSERT_REG_POSITION(texturing.fog_color, 0xe1);
+ASSERT_REG_POSITION(texturing.fog_lut_offset, 0xe6);
+ASSERT_REG_POSITION(texturing.fog_lut_data, 0xe8);
+ASSERT_REG_POSITION(texturing.tev_stage4, 0xf0);
+ASSERT_REG_POSITION(texturing.tev_stage5, 0xf8);
+ASSERT_REG_POSITION(texturing.tev_combiner_buffer_color, 0xfd);
+
+ASSERT_REG_POSITION(framebuffer, 0x100);
+ASSERT_REG_POSITION(framebuffer.output_merger, 0x100);
+ASSERT_REG_POSITION(framebuffer.framebuffer, 0x110);
+
+ASSERT_REG_POSITION(lighting, 0x140);
+
+ASSERT_REG_POSITION(pipeline, 0x200);
+ASSERT_REG_POSITION(pipeline.vertex_attributes, 0x200);
+ASSERT_REG_POSITION(pipeline.index_array, 0x227);
+ASSERT_REG_POSITION(pipeline.num_vertices, 0x228);
+ASSERT_REG_POSITION(pipeline.vertex_offset, 0x22a);
+ASSERT_REG_POSITION(pipeline.trigger_draw, 0x22e);
+ASSERT_REG_POSITION(pipeline.trigger_draw_indexed, 0x22f);
+ASSERT_REG_POSITION(pipeline.vs_default_attributes_setup, 0x232);
+ASSERT_REG_POSITION(pipeline.command_buffer, 0x238);
+ASSERT_REG_POSITION(pipeline.gpu_mode, 0x245);
+ASSERT_REG_POSITION(pipeline.triangle_topology, 0x25e);
+ASSERT_REG_POSITION(pipeline.restart_primitive, 0x25f);
+
+ASSERT_REG_POSITION(gs, 0x280);
+ASSERT_REG_POSITION(vs, 0x2b0);
+
+#undef ASSERT_REG_POSITION
+#endif // !defined(_MSC_VER)
+
+// The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value
+// anyway.
+static_assert(sizeof(Regs) <= 0x300 * sizeof(u32),
+ "Register set structure larger than it should be");
+static_assert(sizeof(Regs) >= 0x300 * sizeof(u32),
+ "Register set structure smaller than it should be");
+
+} // 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 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+
+#include "common/assert.h"
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/logging/log.h"
+
+namespace Pica {
+
+struct FramebufferRegs {
+ enum class LogicOp : u32 {
+ Clear = 0,
+ And = 1,
+ AndReverse = 2,
+ Copy = 3,
+ Set = 4,
+ CopyInverted = 5,
+ NoOp = 6,
+ Invert = 7,
+ Nand = 8,
+ Or = 9,
+ Nor = 10,
+ Xor = 11,
+ Equiv = 12,
+ AndInverted = 13,
+ OrReverse = 14,
+ OrInverted = 15,
+ };
+
+ enum class BlendEquation : u32 {
+ Add = 0,
+ Subtract = 1,
+ ReverseSubtract = 2,
+ Min = 3,
+ Max = 4,
+ };
+
+ enum class BlendFactor : u32 {
+ Zero = 0,
+ One = 1,
+ SourceColor = 2,
+ OneMinusSourceColor = 3,
+ DestColor = 4,
+ OneMinusDestColor = 5,
+ SourceAlpha = 6,
+ OneMinusSourceAlpha = 7,
+ DestAlpha = 8,
+ OneMinusDestAlpha = 9,
+ ConstantColor = 10,
+ OneMinusConstantColor = 11,
+ ConstantAlpha = 12,
+ OneMinusConstantAlpha = 13,
+ SourceAlphaSaturate = 14,
+ };
+
+ enum class CompareFunc : u32 {
+ Never = 0,
+ Always = 1,
+ Equal = 2,
+ NotEqual = 3,
+ LessThan = 4,
+ LessThanOrEqual = 5,
+ GreaterThan = 6,
+ GreaterThanOrEqual = 7,
+ };
+
+ enum class StencilAction : u32 {
+ Keep = 0,
+ Zero = 1,
+ Replace = 2,
+ Increment = 3,
+ Decrement = 4,
+ Invert = 5,
+ IncrementWrap = 6,
+ DecrementWrap = 7,
+ };
+
+ struct {
+ union {
+ // If false, logic blending is used
+ BitField<8, 1, u32> alphablend_enable;
+ };
+
+ union {
+ BitField<0, 8, BlendEquation> blend_equation_rgb;
+ BitField<8, 8, BlendEquation> blend_equation_a;
+
+ BitField<16, 4, BlendFactor> factor_source_rgb;
+ BitField<20, 4, BlendFactor> factor_dest_rgb;
+
+ BitField<24, 4, BlendFactor> factor_source_a;
+ BitField<28, 4, BlendFactor> factor_dest_a;
+ } alpha_blending;
+
+ union {
+ BitField<0, 4, LogicOp> logic_op;
+ };
+
+ union {
+ u32 raw;
+ BitField<0, 8, u32> r;
+ BitField<8, 8, u32> g;
+ BitField<16, 8, u32> b;
+ BitField<24, 8, u32> a;
+ } blend_const;
+
+ union {
+ BitField<0, 1, u32> enable;
+ BitField<4, 3, CompareFunc> func;
+ BitField<8, 8, u32> ref;
+ } alpha_test;
+
+ struct {
+ union {
+ // Raw value of this register
+ u32 raw_func;
+
+ // If true, enable stencil testing
+ BitField<0, 1, u32> enable;
+
+ // Comparison operation for stencil testing
+ BitField<4, 3, CompareFunc> func;
+
+ // Mask used to control writing to the stencil buffer
+ BitField<8, 8, u32> write_mask;
+
+ // Value to compare against for stencil testing
+ BitField<16, 8, u32> reference_value;
+
+ // Mask to apply on stencil test inputs
+ BitField<24, 8, u32> input_mask;
+ };
+
+ union {
+ // Raw value of this register
+ u32 raw_op;
+
+ // Action to perform when the stencil test fails
+ BitField<0, 3, StencilAction> action_stencil_fail;
+
+ // Action to perform when stencil testing passed but depth testing fails
+ BitField<4, 3, StencilAction> action_depth_fail;
+
+ // Action to perform when both stencil and depth testing pass
+ BitField<8, 3, StencilAction> action_depth_pass;
+ };
+ } stencil_test;
+
+ union {
+ BitField<0, 1, u32> depth_test_enable;
+ BitField<4, 3, CompareFunc> depth_test_func;
+ BitField<8, 1, u32> red_enable;
+ BitField<9, 1, u32> green_enable;
+ BitField<10, 1, u32> blue_enable;
+ BitField<11, 1, u32> alpha_enable;
+ BitField<12, 1, u32> depth_write_enable;
+ };
+
+ INSERT_PADDING_WORDS(0x8);
+ } output_merger;
+
+ // Components are laid out in reverse byte order, most significant bits first.
+ enum class ColorFormat : u32 {
+ RGBA8 = 0,
+ RGB8 = 1,
+ RGB5A1 = 2,
+ RGB565 = 3,
+ RGBA4 = 4,
+ };
+
+ enum class DepthFormat : u32 {
+ D16 = 0,
+ D24 = 2,
+ D24S8 = 3,
+ };
+
+ // Returns the number of bytes in the specified color format
+ static unsigned BytesPerColorPixel(ColorFormat format) {
+ switch (format) {
+ case ColorFormat::RGBA8:
+ return 4;
+ case ColorFormat::RGB8:
+ return 3;
+ case ColorFormat::RGB5A1:
+ case ColorFormat::RGB565:
+ case ColorFormat::RGBA4:
+ return 2;
+ default:
+ LOG_CRITICAL(HW_GPU, "Unknown color format %u", format);
+ UNIMPLEMENTED();
+ }
+ }
+
+ struct FramebufferConfig {
+ INSERT_PADDING_WORDS(0x3);
+
+ union {
+ BitField<0, 4, u32> allow_color_write; // 0 = disable, else enable
+ };
+
+ INSERT_PADDING_WORDS(0x1);
+
+ union {
+ BitField<0, 2, u32> allow_depth_stencil_write; // 0 = disable, else enable
+ };
+
+ DepthFormat depth_format; // TODO: Should be a BitField!
+ BitField<16, 3, ColorFormat> color_format;
+
+ INSERT_PADDING_WORDS(0x4);
+
+ u32 depth_buffer_address;
+ u32 color_buffer_address;
+
+ union {
+ // Apparently, the framebuffer width is stored as expected,
+ // while the height is stored as the actual height minus one.
+ // Hence, don't access these fields directly but use the accessors
+ // GetWidth() and GetHeight() instead.
+ BitField<0, 11, u32> width;
+ BitField<12, 10, u32> height;
+ };
+
+ INSERT_PADDING_WORDS(0x1);
+
+ inline PAddr GetColorBufferPhysicalAddress() const {
+ return color_buffer_address * 8;
+ }
+ inline PAddr GetDepthBufferPhysicalAddress() const {
+ return depth_buffer_address * 8;
+ }
+
+ inline u32 GetWidth() const {
+ return width;
+ }
+
+ inline u32 GetHeight() const {
+ return height + 1;
+ }
+ } framebuffer;
+
+ // Returns the number of bytes in the specified depth format
+ static u32 BytesPerDepthPixel(DepthFormat format) {
+ switch (format) {
+ case DepthFormat::D16:
+ return 2;
+ case DepthFormat::D24:
+ return 3;
+ case DepthFormat::D24S8:
+ return 4;
+ default:
+ LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
+ UNIMPLEMENTED();
+ }
+ }
+
+ // Returns the number of bits per depth component of the specified depth format
+ static u32 DepthBitsPerPixel(DepthFormat format) {
+ switch (format) {
+ case DepthFormat::D16:
+ return 16;
+ case DepthFormat::D24:
+ case DepthFormat::D24S8:
+ return 24;
+ default:
+ LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format);
+ UNIMPLEMENTED();
+ }
+ }
+
+ INSERT_PADDING_WORDS(0x20);
+};
+
+static_assert(sizeof(FramebufferRegs) == 0x40 * sizeof(u32),
+ "FramebufferRegs struct has incorrect size");
+
+} // 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 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+
+#include "common/assert.h"
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/vector_math.h"
+
+namespace Pica {
+
+struct LightingRegs {
+ enum class LightingSampler {
+ Distribution0 = 0,
+ Distribution1 = 1,
+ Fresnel = 3,
+ ReflectBlue = 4,
+ ReflectGreen = 5,
+ ReflectRed = 6,
+ SpotlightAttenuation = 8,
+ DistanceAttenuation = 16,
+ };
+
+ /**
+ * Pica fragment lighting supports using different LUTs for each lighting component: Reflectance
+ * R, G, and B channels, distribution function for specular components 0 and 1, fresnel factor,
+ * and spotlight attenuation. Furthermore, which LUTs are used for each channel (or whether a
+ * channel is enabled at all) is specified by various pre-defined lighting configurations. With
+ * configurations that require more LUTs, more cycles are required on HW to perform lighting
+ * computations.
+ */
+ enum class LightingConfig {
+ Config0 = 0, ///< Reflect Red, Distribution 0, Spotlight
+ Config1 = 1, ///< Reflect Red, Fresnel, Spotlight
+ Config2 = 2, ///< Reflect Red, Distribution 0/1
+ Config3 = 3, ///< Distribution 0/1, Fresnel
+ Config4 = 4, ///< Reflect Red/Green/Blue, Distribution 0/1, Spotlight
+ Config5 = 5, ///< Reflect Red/Green/Blue, Distribution 0, Fresnel, Spotlight
+ Config6 = 6, ///< Reflect Red, Distribution 0/1, Fresnel, Spotlight
+
+ Config7 = 8, ///< Reflect Red/Green/Blue, Distribution 0/1, Fresnel, Spotlight
+ ///< NOTE: '8' is intentional, '7' does not appear to be a valid configuration
+ };
+
+ /// Selects which lighting components are affected by fresnel
+ enum class LightingFresnelSelector {
+ None = 0, ///< Fresnel is disabled
+ PrimaryAlpha = 1, ///< Primary (diffuse) lighting alpha is affected by fresnel
+ SecondaryAlpha = 2, ///< Secondary (specular) lighting alpha is affected by fresnel
+ Both =
+ PrimaryAlpha |
+ SecondaryAlpha, ///< Both primary and secondary lighting alphas are affected by fresnel
+ };
+
+ /// Factor used to scale the output of a lighting LUT
+ enum class LightingScale {
+ Scale1 = 0, ///< Scale is 1x
+ Scale2 = 1, ///< Scale is 2x
+ Scale4 = 2, ///< Scale is 4x
+ Scale8 = 3, ///< Scale is 8x
+
+ Scale1_4 = 6, ///< Scale is 0.25x
+ Scale1_2 = 7, ///< Scale is 0.5x
+ };
+
+ enum class LightingLutInput {
+ NH = 0, // Cosine of the angle between the normal and half-angle vectors
+ VH = 1, // Cosine of the angle between the view and half-angle vectors
+ NV = 2, // Cosine of the angle between the normal and the view vector
+ LN = 3, // Cosine of the angle between the light and the normal vectors
+ };
+
+ enum class LightingBumpMode : u32 {
+ None = 0,
+ NormalMap = 1,
+ TangentMap = 2,
+ };
+
+ union LightColor {
+ BitField<0, 10, u32> b;
+ BitField<10, 10, u32> g;
+ BitField<20, 10, u32> r;
+
+ Math::Vec3f ToVec3f() const {
+ // These fields are 10 bits wide, however 255 corresponds to 1.0f for each color
+ // component
+ return Math::MakeVec((f32)r / 255.f, (f32)g / 255.f, (f32)b / 255.f);
+ }
+ };
+
+ /// Returns true if the specified lighting sampler is supported by the current Pica lighting
+ /// configuration
+ static bool IsLightingSamplerSupported(LightingConfig config, LightingSampler sampler) {
+ switch (sampler) {
+ case LightingSampler::Distribution0:
+ return (config != LightingConfig::Config1);
+
+ case LightingSampler::Distribution1:
+ return (config != LightingConfig::Config0) && (config != LightingConfig::Config1) &&
+ (config != LightingConfig::Config5);
+
+ case LightingSampler::Fresnel:
+ return (config != LightingConfig::Config0) && (config != LightingConfig::Config2) &&
+ (config != LightingConfig::Config4);
+
+ case LightingSampler::ReflectRed:
+ return (config != LightingConfig::Config3);
+
+ case LightingSampler::ReflectGreen:
+ case LightingSampler::ReflectBlue:
+ return (config == LightingConfig::Config4) || (config == LightingConfig::Config5) ||
+ (config == LightingConfig::Config7);
+ default:
+ UNREACHABLE_MSG("Regs::IsLightingSamplerSupported: Reached "
+ "unreachable section, sampler should be one "
+ "of Distribution0, Distribution1, Fresnel, "
+ "ReflectRed, ReflectGreen or ReflectBlue, instead "
+ "got %i",
+ static_cast<int>(config));
+ }
+ }
+
+ struct LightSrc {
+ LightColor specular_0; // material.specular_0 * light.specular_0
+ LightColor specular_1; // material.specular_1 * light.specular_1
+ LightColor diffuse; // material.diffuse * light.diffuse
+ LightColor ambient; // material.ambient * light.ambient
+
+ // Encoded as 16-bit floating point
+ union {
+ BitField<0, 16, u32> x;
+ BitField<16, 16, u32> y;
+ };
+ union {
+ BitField<0, 16, u32> z;
+ };
+
+ INSERT_PADDING_WORDS(0x3);
+
+ union {
+ BitField<0, 1, u32> directional;
+ BitField<1, 1, u32> two_sided_diffuse; // When disabled, clamp dot-product to 0
+ } config;
+
+ BitField<0, 20, u32> dist_atten_bias;
+ BitField<0, 20, u32> dist_atten_scale;
+
+ INSERT_PADDING_WORDS(0x4);
+ };
+ static_assert(sizeof(LightSrc) == 0x10 * sizeof(u32), "LightSrc structure must be 0x10 words");
+
+ LightSrc light[8];
+ LightColor global_ambient; // Emission + (material.ambient * lighting.ambient)
+ INSERT_PADDING_WORDS(0x1);
+ BitField<0, 3, u32> max_light_index; // Number of enabled lights - 1
+
+ union {
+ BitField<2, 2, LightingFresnelSelector> fresnel_selector;
+ BitField<4, 4, LightingConfig> config;
+ BitField<22, 2, u32> bump_selector; // 0: Texture 0, 1: Texture 1, 2: Texture 2
+ BitField<27, 1, u32> clamp_highlights;
+ BitField<28, 2, LightingBumpMode> bump_mode;
+ BitField<30, 1, u32> disable_bump_renorm;
+ } config0;
+
+ union {
+ BitField<16, 1, u32> disable_lut_d0;
+ BitField<17, 1, u32> disable_lut_d1;
+ BitField<19, 1, u32> disable_lut_fr;
+ BitField<20, 1, u32> disable_lut_rr;
+ BitField<21, 1, u32> disable_lut_rg;
+ BitField<22, 1, u32> disable_lut_rb;
+
+ // Each bit specifies whether distance attenuation should be applied for the corresponding
+ // light.
+ BitField<24, 1, u32> disable_dist_atten_light_0;
+ BitField<25, 1, u32> disable_dist_atten_light_1;
+ BitField<26, 1, u32> disable_dist_atten_light_2;
+ BitField<27, 1, u32> disable_dist_atten_light_3;
+ BitField<28, 1, u32> disable_dist_atten_light_4;
+ BitField<29, 1, u32> disable_dist_atten_light_5;
+ BitField<30, 1, u32> disable_dist_atten_light_6;
+ BitField<31, 1, u32> disable_dist_atten_light_7;
+ } config1;
+
+ bool IsDistAttenDisabled(unsigned index) const {
+ const unsigned disable[] = {
+ config1.disable_dist_atten_light_0, config1.disable_dist_atten_light_1,
+ config1.disable_dist_atten_light_2, config1.disable_dist_atten_light_3,
+ config1.disable_dist_atten_light_4, config1.disable_dist_atten_light_5,
+ config1.disable_dist_atten_light_6, config1.disable_dist_atten_light_7};
+ return disable[index] != 0;
+ }
+
+ union {
+ BitField<0, 8, u32> index; ///< Index at which to set data in the LUT
+ BitField<8, 5, u32> type; ///< Type of LUT for which to set data
+ } lut_config;
+
+ BitField<0, 1, u32> disable;
+ INSERT_PADDING_WORDS(0x1);
+
+ // When data is written to any of these registers, it gets written to the lookup table of the
+ // selected type at the selected index, specified above in the `lut_config` register. With each
+ // write, `lut_config.index` is incremented. It does not matter which of these registers is
+ // written to, the behavior will be the same.
+ u32 lut_data[8];
+
+ // These are used to specify if absolute (abs) value should be used for each LUT index. When
+ // abs mode is disabled, LUT indexes are in the range of (-1.0, 1.0). Otherwise, they are in
+ // the range of (0.0, 1.0).
+ union {
+ BitField<1, 1, u32> disable_d0;
+ BitField<5, 1, u32> disable_d1;
+ BitField<9, 1, u32> disable_sp;
+ BitField<13, 1, u32> disable_fr;
+ BitField<17, 1, u32> disable_rb;
+ BitField<21, 1, u32> disable_rg;
+ BitField<25, 1, u32> disable_rr;
+ } abs_lut_input;
+
+ union {
+ BitField<0, 3, LightingLutInput> d0;
+ BitField<4, 3, LightingLutInput> d1;
+ BitField<8, 3, LightingLutInput> sp;
+ BitField<12, 3, LightingLutInput> fr;
+ BitField<16, 3, LightingLutInput> rb;
+ BitField<20, 3, LightingLutInput> rg;
+ BitField<24, 3, LightingLutInput> rr;
+ } lut_input;
+
+ union {
+ BitField<0, 3, LightingScale> d0;
+ BitField<4, 3, LightingScale> d1;
+ BitField<8, 3, LightingScale> sp;
+ BitField<12, 3, LightingScale> fr;
+ BitField<16, 3, LightingScale> rb;
+ BitField<20, 3, LightingScale> rg;
+ BitField<24, 3, LightingScale> rr;
+
+ static float GetScale(LightingScale scale) {
+ switch (scale) {
+ case LightingScale::Scale1:
+ return 1.0f;
+ case LightingScale::Scale2:
+ return 2.0f;
+ case LightingScale::Scale4:
+ return 4.0f;
+ case LightingScale::Scale8:
+ return 8.0f;
+ case LightingScale::Scale1_4:
+ return 0.25f;
+ case LightingScale::Scale1_2:
+ return 0.5f;
+ }
+ return 0.0f;
+ }
+ } lut_scale;
+
+ INSERT_PADDING_WORDS(0x6);
+
+ union {
+ // There are 8 light enable "slots", corresponding to the total number of lights supported
+ // by Pica. For N enabled lights (specified by register 0x1c2, or 'src_num' above), the
+ // first N slots below will be set to integers within the range of 0-7, corresponding to the
+ // actual light that is enabled for each slot.
+
+ BitField<0, 3, u32> slot_0;
+ BitField<4, 3, u32> slot_1;
+ BitField<8, 3, u32> slot_2;
+ BitField<12, 3, u32> slot_3;
+ BitField<16, 3, u32> slot_4;
+ BitField<20, 3, u32> slot_5;
+ BitField<24, 3, u32> slot_6;
+ BitField<28, 3, u32> slot_7;
+
+ unsigned GetNum(unsigned index) const {
+ const unsigned enable_slots[] = {slot_0, slot_1, slot_2, slot_3,
+ slot_4, slot_5, slot_6, slot_7};
+ return enable_slots[index];
+ }
+ } light_enable;
+
+ INSERT_PADDING_WORDS(0x26);
+};
+
+static_assert(sizeof(LightingRegs) == 0xC0 * sizeof(u32), "LightingRegs struct has incorrect size");
+
+} // 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 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+
+#include "common/assert.h"
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
+namespace Pica {
+
+struct PipelineRegs {
+ enum class VertexAttributeFormat : u64 {
+ BYTE = 0,
+ UBYTE = 1,
+ SHORT = 2,
+ FLOAT = 3,
+ };
+
+ struct {
+ BitField<0, 29, u32> base_address;
+
+ PAddr GetPhysicalBaseAddress() const {
+ return base_address * 8;
+ }
+
+ // Descriptor for internal vertex attributes
+ union {
+ BitField<0, 2, VertexAttributeFormat> format0; // size of one element
+ BitField<2, 2, u64> size0; // number of elements minus 1
+ BitField<4, 2, VertexAttributeFormat> format1;
+ BitField<6, 2, u64> size1;
+ BitField<8, 2, VertexAttributeFormat> format2;
+ BitField<10, 2, u64> size2;
+ BitField<12, 2, VertexAttributeFormat> format3;
+ BitField<14, 2, u64> size3;
+ BitField<16, 2, VertexAttributeFormat> format4;
+ BitField<18, 2, u64> size4;
+ BitField<20, 2, VertexAttributeFormat> format5;
+ BitField<22, 2, u64> size5;
+ BitField<24, 2, VertexAttributeFormat> format6;
+ BitField<26, 2, u64> size6;
+ BitField<28, 2, VertexAttributeFormat> format7;
+ BitField<30, 2, u64> size7;
+ BitField<32, 2, VertexAttributeFormat> format8;
+ BitField<34, 2, u64> size8;
+ BitField<36, 2, VertexAttributeFormat> format9;
+ BitField<38, 2, u64> size9;
+ BitField<40, 2, VertexAttributeFormat> format10;
+ BitField<42, 2, u64> size10;
+ BitField<44, 2, VertexAttributeFormat> format11;
+ BitField<46, 2, u64> size11;
+
+ BitField<48, 12, u64> attribute_mask;
+
+ // number of total attributes minus 1
+ BitField<60, 4, u64> max_attribute_index;
+ };
+
+ inline VertexAttributeFormat GetFormat(int n) const {
+ VertexAttributeFormat formats[] = {format0, format1, format2, format3,
+ format4, format5, format6, format7,
+ format8, format9, format10, format11};
+ return formats[n];
+ }
+
+ inline int GetNumElements(int n) const {
+ u64 sizes[] = {size0, size1, size2, size3, size4, size5,
+ size6, size7, size8, size9, size10, size11};
+ return (int)sizes[n] + 1;
+ }
+
+ inline int GetElementSizeInBytes(int n) const {
+ return (GetFormat(n) == VertexAttributeFormat::FLOAT)
+ ? 4
+ : (GetFormat(n) == VertexAttributeFormat::SHORT) ? 2 : 1;
+ }
+
+ inline int GetStride(int n) const {
+ return GetNumElements(n) * GetElementSizeInBytes(n);
+ }
+
+ inline bool IsDefaultAttribute(int id) const {
+ return (id >= 12) || (attribute_mask & (1ULL << id)) != 0;
+ }
+
+ inline int GetNumTotalAttributes() const {
+ return (int)max_attribute_index + 1;
+ }
+
+ // Attribute loaders map the source vertex data to input attributes
+ // This e.g. allows to load different attributes from different memory locations
+ struct {
+ // Source attribute data offset from the base address
+ u32 data_offset;
+
+ union {
+ BitField<0, 4, u64> comp0;
+ BitField<4, 4, u64> comp1;
+ BitField<8, 4, u64> comp2;
+ BitField<12, 4, u64> comp3;
+ BitField<16, 4, u64> comp4;
+ BitField<20, 4, u64> comp5;
+ BitField<24, 4, u64> comp6;
+ BitField<28, 4, u64> comp7;
+ BitField<32, 4, u64> comp8;
+ BitField<36, 4, u64> comp9;
+ BitField<40, 4, u64> comp10;
+ BitField<44, 4, u64> comp11;
+
+ // bytes for a single vertex in this loader
+ BitField<48, 8, u64> byte_count;
+
+ BitField<60, 4, u64> component_count;
+ };
+
+ inline int GetComponent(int n) const {
+ u64 components[] = {comp0, comp1, comp2, comp3, comp4, comp5,
+ comp6, comp7, comp8, comp9, comp10, comp11};
+ return (int)components[n];
+ }
+ } attribute_loaders[12];
+ } vertex_attributes;
+
+ struct {
+ enum IndexFormat : u32 {
+ BYTE = 0,
+ SHORT = 1,
+ };
+
+ union {
+ BitField<0, 31, u32> offset; // relative to base attribute address
+ BitField<31, 1, IndexFormat> format;
+ };
+ } index_array;
+
+ // Number of vertices to render
+ u32 num_vertices;
+
+ INSERT_PADDING_WORDS(0x1);
+
+ // The index of the first vertex to render
+ u32 vertex_offset;
+
+ INSERT_PADDING_WORDS(0x3);
+
+ // These two trigger rendering of triangles
+ u32 trigger_draw;
+ u32 trigger_draw_indexed;
+
+ INSERT_PADDING_WORDS(0x2);
+
+ // These registers are used to setup the default "fall-back" vertex shader attributes
+ struct {
+ // Index of the current default attribute
+ u32 index;
+
+ // Writing to these registers sets the "current" default attribute.
+ u32 set_value[3];
+ } vs_default_attributes_setup;
+
+ INSERT_PADDING_WORDS(0x2);
+
+ struct {
+ // There are two channels that can be used to configure the next command buffer, which can
+ // be then executed by writing to the "trigger" registers. There are two reasons why a game
+ // might use this feature:
+ // 1) With this, an arbitrary number of additional command buffers may be executed in
+ // sequence without requiring any intervention of the CPU after the initial one is
+ // kicked off.
+ // 2) Games can configure these registers to provide a command list subroutine mechanism.
+
+ BitField<0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer
+ BitField<0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer
+ u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to
+
+ unsigned GetSize(unsigned index) const {
+ ASSERT(index < 2);
+ return 8 * size[index];
+ }
+
+ PAddr GetPhysicalAddress(unsigned index) const {
+ ASSERT(index < 2);
+ return (PAddr)(8 * addr[index]);
+ }
+ } command_buffer;
+
+ INSERT_PADDING_WORDS(4);
+
+ /// Number of input attributes to the vertex shader minus 1
+ BitField<0, 4, u32> max_input_attrib_index;
+
+ INSERT_PADDING_WORDS(2);
+
+ enum class GPUMode : u32 {
+ Drawing = 0,
+ Configuring = 1,
+ };
+
+ GPUMode gpu_mode;
+
+ INSERT_PADDING_WORDS(0x18);
+
+ enum class TriangleTopology : u32 {
+ List = 0,
+ Strip = 1,
+ Fan = 2,
+ Shader = 3, // Programmable setup unit implemented in a geometry shader
+ };
+
+ BitField<8, 2, TriangleTopology> triangle_topology;
+
+ u32 restart_primitive;
+
+ INSERT_PADDING_WORDS(0x20);
+};
+
+static_assert(sizeof(PipelineRegs) == 0x80 * sizeof(u32), "PipelineRegs struct has incorrect size");
+
+} // 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 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
+namespace Pica {
+
+struct RasterizerRegs {
+ enum class CullMode : u32 {
+ // Select which polygons are considered to be "frontfacing".
+ KeepAll = 0,
+ KeepClockWise = 1,
+ KeepCounterClockWise = 2,
+ // TODO: What does the third value imply?
+ };
+
+ union {
+ BitField<0, 2, CullMode> cull_mode;
+ };
+
+ BitField<0, 24, u32> viewport_size_x;
+
+ INSERT_PADDING_WORDS(0x1);
+
+ BitField<0, 24, u32> viewport_size_y;
+
+ INSERT_PADDING_WORDS(0x9);
+
+ BitField<0, 24, u32> viewport_depth_range; // float24
+ BitField<0, 24, u32> viewport_depth_near_plane; // float24
+
+ BitField<0, 3, u32> vs_output_total;
+
+ union VSOutputAttributes {
+ // Maps components of output vertex attributes to semantics
+ enum Semantic : u32 {
+ POSITION_X = 0,
+ POSITION_Y = 1,
+ POSITION_Z = 2,
+ POSITION_W = 3,
+
+ QUATERNION_X = 4,
+ QUATERNION_Y = 5,
+ QUATERNION_Z = 6,
+ QUATERNION_W = 7,
+
+ COLOR_R = 8,
+ COLOR_G = 9,
+ COLOR_B = 10,
+ COLOR_A = 11,
+
+ TEXCOORD0_U = 12,
+ TEXCOORD0_V = 13,
+ TEXCOORD1_U = 14,
+ TEXCOORD1_V = 15,
+
+ TEXCOORD0_W = 16,
+
+ VIEW_X = 18,
+ VIEW_Y = 19,
+ VIEW_Z = 20,
+
+ TEXCOORD2_U = 22,
+ TEXCOORD2_V = 23,
+
+ INVALID = 31,
+ };
+
+ BitField<0, 5, Semantic> map_x;
+ BitField<8, 5, Semantic> map_y;
+ BitField<16, 5, Semantic> map_z;
+ BitField<24, 5, Semantic> map_w;
+ } vs_output_attributes[7];
+
+ INSERT_PADDING_WORDS(0xe);
+
+ enum class ScissorMode : u32 {
+ Disabled = 0,
+ Exclude = 1, // Exclude pixels inside the scissor box
+
+ Include = 3 // Exclude pixels outside the scissor box
+ };
+
+ struct {
+ BitField<0, 2, ScissorMode> mode;
+
+ union {
+ BitField<0, 16, u32> x1;
+ BitField<16, 16, u32> y1;
+ };
+
+ union {
+ BitField<0, 16, u32> x2;
+ BitField<16, 16, u32> y2;
+ };
+ } scissor_test;
+
+ union {
+ BitField<0, 10, s32> x;
+ BitField<16, 10, s32> y;
+ } viewport_corner;
+
+ INSERT_PADDING_WORDS(0x1);
+
+ // TODO: early depth
+ INSERT_PADDING_WORDS(0x1);
+
+ INSERT_PADDING_WORDS(0x2);
+
+ enum DepthBuffering : u32 {
+ WBuffering = 0,
+ ZBuffering = 1,
+ };
+ BitField<0, 1, DepthBuffering> depthmap_enable;
+
+ INSERT_PADDING_WORDS(0x12);
+};
+
+static_assert(sizeof(RasterizerRegs) == 0x40 * sizeof(u32),
+ "RasterizerRegs struct has incorrect size");
+
+} // 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 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
+namespace Pica {
+
+struct ShaderRegs {
+ BitField<0, 16, u32> bool_uniforms;
+
+ union {
+ BitField<0, 8, u32> x;
+ BitField<8, 8, u32> y;
+ BitField<16, 8, u32> z;
+ BitField<24, 8, u32> w;
+ } int_uniforms[4];
+
+ INSERT_PADDING_WORDS(0x4);
+
+ union {
+ // Number of input attributes to shader unit - 1
+ BitField<0, 4, u32> max_input_attribute_index;
+ };
+
+ // Offset to shader program entry point (in words)
+ BitField<0, 16, u32> main_offset;
+
+ /// Maps input attributes to registers. 4-bits per attribute, specifying a register index
+ u32 input_attribute_to_register_map_low;
+ u32 input_attribute_to_register_map_high;
+
+ unsigned int GetRegisterForAttribute(unsigned int attribute_index) const {
+ u64 map = ((u64)input_attribute_to_register_map_high << 32) |
+ (u64)input_attribute_to_register_map_low;
+ return (map >> (attribute_index * 4)) & 0b1111;
+ }
+
+ BitField<0, 16, u32> output_mask;
+
+ // 0x28E, CODETRANSFER_END
+ INSERT_PADDING_WORDS(0x2);
+
+ struct {
+ enum Format : u32 {
+ FLOAT24 = 0,
+ FLOAT32 = 1,
+ };
+
+ bool IsFloat32() const {
+ return format == FLOAT32;
+ }
+
+ union {
+ // Index of the next uniform to write to
+ // TODO: ctrulib uses 8 bits for this, however that seems to yield lots of invalid
+ // indices
+ // TODO: Maybe the uppermost index is for the geometry shader? Investigate!
+ BitField<0, 7, u32> index;
+
+ BitField<31, 1, Format> format;
+ };
+
+ // Writing to these registers sets the current uniform.
+ u32 set_value[8];
+
+ } uniform_setup;
+
+ INSERT_PADDING_WORDS(0x2);
+
+ struct {
+ // Offset of the next instruction to write code to.
+ // Incremented with each instruction write.
+ u32 offset;
+
+ // Writing to these registers sets the "current" word in the shader program.
+ u32 set_word[8];
+ } program;
+
+ INSERT_PADDING_WORDS(0x1);
+
+ // This register group is used to load an internal table of swizzling patterns,
+ // which are indexed by each shader instruction to specify vector component swizzling.
+ struct {
+ // Offset of the next swizzle pattern to write code to.
+ // Incremented with each instruction write.
+ u32 offset;
+
+ // Writing to these registers sets the current swizzle pattern in the table.
+ u32 set_word[8];
+ } swizzle_patterns;
+
+ INSERT_PADDING_WORDS(0x2);
+};
+
+static_assert(sizeof(ShaderRegs) == 0x30 * sizeof(u32), "ShaderRegs struct has incorrect size");
+
+} // 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 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+
+#include "common/assert.h"
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
+namespace Pica {
+
+struct TexturingRegs {
+ struct TextureConfig {
+ enum TextureType : u32 {
+ Texture2D = 0,
+ TextureCube = 1,
+ Shadow2D = 2,
+ Projection2D = 3,
+ ShadowCube = 4,
+ Disabled = 5,
+ };
+
+ enum WrapMode : u32 {
+ ClampToEdge = 0,
+ ClampToBorder = 1,
+ Repeat = 2,
+ MirroredRepeat = 3,
+ };
+
+ enum TextureFilter : u32 {
+ Nearest = 0,
+ Linear = 1,
+ };
+
+ union {
+ u32 raw;
+ BitField<0, 8, u32> r;
+ BitField<8, 8, u32> g;
+ BitField<16, 8, u32> b;
+ BitField<24, 8, u32> a;
+ } border_color;
+
+ union {
+ BitField<0, 16, u32> height;
+ BitField<16, 16, u32> width;
+ };
+
+ union {
+ BitField<1, 1, TextureFilter> mag_filter;
+ BitField<2, 1, TextureFilter> min_filter;
+ BitField<8, 2, WrapMode> wrap_t;
+ BitField<12, 2, WrapMode> wrap_s;
+ BitField<28, 2, TextureType>
+ type; ///< @note Only valid for texture 0 according to 3DBrew.
+ };
+
+ INSERT_PADDING_WORDS(0x1);
+
+ u32 address;
+
+ PAddr GetPhysicalAddress() const {
+ return address * 8;
+ }
+
+ // texture1 and texture2 store the texture format directly after the address
+ // whereas texture0 inserts some additional flags inbetween.
+ // Hence, we store the format separately so that all other parameters can be described
+ // in a single structure.
+ };
+
+ enum class TextureFormat : u32 {
+ RGBA8 = 0,
+ RGB8 = 1,
+ RGB5A1 = 2,
+ RGB565 = 3,
+ RGBA4 = 4,
+ IA8 = 5,
+ RG8 = 6, ///< @note Also called HILO8 in 3DBrew.
+ I8 = 7,
+ A8 = 8,
+ IA4 = 9,
+ I4 = 10,
+ A4 = 11,
+ ETC1 = 12, // compressed
+ ETC1A4 = 13, // compressed
+ };
+
+ static unsigned NibblesPerPixel(TextureFormat format) {
+ switch (format) {
+ case TextureFormat::RGBA8:
+ return 8;
+
+ case TextureFormat::RGB8:
+ return 6;
+
+ case TextureFormat::RGB5A1:
+ case TextureFormat::RGB565:
+ case TextureFormat::RGBA4:
+ case TextureFormat::IA8:
+ case TextureFormat::RG8:
+ return 4;
+
+ case TextureFormat::I4:
+ case TextureFormat::A4:
+ return 1;
+
+ case TextureFormat::I8:
+ case TextureFormat::A8:
+ case TextureFormat::IA4:
+
+ default: // placeholder for yet unknown formats
+ UNIMPLEMENTED();
+ return 0;
+ }
+ }
+
+ union {
+ BitField<0, 1, u32> texture0_enable;
+ BitField<1, 1, u32> texture1_enable;
+ BitField<2, 1, u32> texture2_enable;
+ };
+ TextureConfig texture0;
+ INSERT_PADDING_WORDS(0x8);
+ BitField<0, 4, TextureFormat> texture0_format;
+ BitField<0, 1, u32> fragment_lighting_enable;
+ INSERT_PADDING_WORDS(0x1);
+ TextureConfig texture1;
+ BitField<0, 4, TextureFormat> texture1_format;
+ INSERT_PADDING_WORDS(0x2);
+ TextureConfig texture2;
+ BitField<0, 4, TextureFormat> texture2_format;
+ INSERT_PADDING_WORDS(0x21);
+
+ struct FullTextureConfig {
+ const bool enabled;
+ const TextureConfig config;
+ const TextureFormat format;
+ };
+ const std::array<FullTextureConfig, 3> GetTextures() const {
+ return {{
+ {texture0_enable.ToBool(), texture0, texture0_format},
+ {texture1_enable.ToBool(), texture1, texture1_format},
+ {texture2_enable.ToBool(), texture2, texture2_format},
+ }};
+ }
+
+ // 0xc0-0xff: Texture Combiner (akin to glTexEnv)
+ struct TevStageConfig {
+ enum class Source : u32 {
+ PrimaryColor = 0x0,
+ PrimaryFragmentColor = 0x1,
+ SecondaryFragmentColor = 0x2,
+
+ Texture0 = 0x3,
+ Texture1 = 0x4,
+ Texture2 = 0x5,
+ Texture3 = 0x6,
+
+ PreviousBuffer = 0xd,
+ Constant = 0xe,
+ Previous = 0xf,
+ };
+
+ enum class ColorModifier : u32 {
+ SourceColor = 0x0,
+ OneMinusSourceColor = 0x1,
+ SourceAlpha = 0x2,
+ OneMinusSourceAlpha = 0x3,
+ SourceRed = 0x4,
+ OneMinusSourceRed = 0x5,
+
+ SourceGreen = 0x8,
+ OneMinusSourceGreen = 0x9,
+
+ SourceBlue = 0xc,
+ OneMinusSourceBlue = 0xd,
+ };
+
+ enum class AlphaModifier : u32 {
+ SourceAlpha = 0x0,
+ OneMinusSourceAlpha = 0x1,
+ SourceRed = 0x2,
+ OneMinusSourceRed = 0x3,
+ SourceGreen = 0x4,
+ OneMinusSourceGreen = 0x5,
+ SourceBlue = 0x6,
+ OneMinusSourceBlue = 0x7,
+ };
+
+ enum class Operation : u32 {
+ Replace = 0,
+ Modulate = 1,
+ Add = 2,
+ AddSigned = 3,
+ Lerp = 4,
+ Subtract = 5,
+ Dot3_RGB = 6,
+
+ MultiplyThenAdd = 8,
+ AddThenMultiply = 9,
+ };
+
+ union {
+ u32 sources_raw;
+ BitField<0, 4, Source> color_source1;
+ BitField<4, 4, Source> color_source2;
+ BitField<8, 4, Source> color_source3;
+ BitField<16, 4, Source> alpha_source1;
+ BitField<20, 4, Source> alpha_source2;
+ BitField<24, 4, Source> alpha_source3;
+ };
+
+ union {
+ u32 modifiers_raw;
+ BitField<0, 4, ColorModifier> color_modifier1;
+ BitField<4, 4, ColorModifier> color_modifier2;
+ BitField<8, 4, ColorModifier> color_modifier3;
+ BitField<12, 3, AlphaModifier> alpha_modifier1;
+ BitField<16, 3, AlphaModifier> alpha_modifier2;
+ BitField<20, 3, AlphaModifier> alpha_modifier3;
+ };
+
+ union {
+ u32 ops_raw;
+ BitField<0, 4, Operation> color_op;
+ BitField<16, 4, Operation> alpha_op;
+ };
+
+ union {
+ u32 const_color;
+ BitField<0, 8, u32> const_r;
+ BitField<8, 8, u32> const_g;
+ BitField<16, 8, u32> const_b;
+ BitField<24, 8, u32> const_a;
+ };
+
+ union {
+ u32 scales_raw;
+ BitField<0, 2, u32> color_scale;
+ BitField<16, 2, u32> alpha_scale;
+ };
+
+ inline unsigned GetColorMultiplier() const {
+ return (color_scale < 3) ? (1 << color_scale) : 1;
+ }
+
+ inline unsigned GetAlphaMultiplier() const {
+ return (alpha_scale < 3) ? (1 << alpha_scale) : 1;
+ }
+ };
+
+ TevStageConfig tev_stage0;
+ INSERT_PADDING_WORDS(0x3);
+ TevStageConfig tev_stage1;
+ INSERT_PADDING_WORDS(0x3);
+ TevStageConfig tev_stage2;
+ INSERT_PADDING_WORDS(0x3);
+ TevStageConfig tev_stage3;
+ INSERT_PADDING_WORDS(0x3);
+
+ enum class FogMode : u32 {
+ None = 0,
+ Fog = 5,
+ Gas = 7,
+ };
+
+ union {
+ BitField<0, 3, FogMode> fog_mode;
+ BitField<16, 1, u32> fog_flip;
+
+ union {
+ // Tev stages 0-3 write their output to the combiner buffer if the corresponding bit in
+ // these masks are set
+ BitField<8, 4, u32> update_mask_rgb;
+ BitField<12, 4, u32> update_mask_a;
+
+ bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const {
+ return (stage_index < 4) && (update_mask_rgb & (1 << stage_index));
+ }
+
+ bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const {
+ return (stage_index < 4) && (update_mask_a & (1 << stage_index));
+ }
+ } tev_combiner_buffer_input;
+ };
+
+ union {
+ u32 raw;
+ BitField<0, 8, u32> r;
+ BitField<8, 8, u32> g;
+ BitField<16, 8, u32> b;
+ } fog_color;
+
+ INSERT_PADDING_WORDS(0x4);
+
+ BitField<0, 16, u32> fog_lut_offset;
+
+ INSERT_PADDING_WORDS(0x1);
+
+ u32 fog_lut_data[8];
+
+ TevStageConfig tev_stage4;
+ INSERT_PADDING_WORDS(0x3);
+ TevStageConfig tev_stage5;
+
+ union {
+ u32 raw;
+ BitField<0, 8, u32> r;
+ BitField<8, 8, u32> g;
+ BitField<16, 8, u32> b;
+ BitField<24, 8, u32> a;
+ } tev_combiner_buffer_color;
+
+ INSERT_PADDING_WORDS(0x2);
+
+ const std::array<TevStageConfig, 6> GetTevStages() const {
+ return {{tev_stage0, tev_stage1, tev_stage2, tev_stage3, tev_stage4, tev_stage5}};
+ };
+};
+
+static_assert(sizeof(TexturingRegs) == 0x80 * sizeof(u32),
+ "TexturingRegs struct has incorrect size");
+
+} // 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 @@
#include "common/microprofile.h"
#include "common/vector_math.h"
#include "core/hw/gpu.h"
-#include "video_core/pica.h"
#include "video_core/pica_state.h"
+#include "video_core/regs.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/gl_shader_gen.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
@@ -26,13 +26,15 @@ MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192));
MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
-static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
- return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace &&
- stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace &&
- stage.color_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
- stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
- stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor &&
- stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha &&
+static bool IsPassThroughTevStage(const Pica::TexturingRegs::TevStageConfig& stage) {
+ using TevStageConfig = Pica::TexturingRegs::TevStageConfig;
+
+ return (stage.color_op == TevStageConfig::Operation::Replace &&
+ stage.alpha_op == TevStageConfig::Operation::Replace &&
+ stage.color_source1 == TevStageConfig::Source::Previous &&
+ stage.alpha_source1 == TevStageConfig::Source::Previous &&
+ stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor &&
+ stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha &&
stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1);
}
@@ -181,7 +183,7 @@ void RasterizerOpenGL::DrawTriangles() {
CachedSurface* depth_surface;
MathUtil::Rectangle<int> rect;
std::tie(color_surface, depth_surface, rect) =
- res_cache.GetFramebufferSurfaces(regs.framebuffer);
+ res_cache.GetFramebufferSurfaces(regs.framebuffer.framebuffer);
state.draw.draw_framebuffer = framebuffer.handle;
state.Apply();
@@ -190,20 +192,24 @@ void RasterizerOpenGL::DrawTriangles() {
color_surface != nullptr ? color_surface->texture.handle : 0, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
depth_surface != nullptr ? depth_surface->texture.handle : 0, 0);
- bool has_stencil = regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8;
+ bool has_stencil =
+ regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8;
glFramebufferTexture2D(
GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
(has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0);
// Sync the viewport
// These registers hold half-width and half-height, so must be multiplied by 2
- GLsizei viewport_width = (GLsizei)Pica::float24::FromRaw(regs.viewport_size_x).ToFloat32() * 2;
- GLsizei viewport_height = (GLsizei)Pica::float24::FromRaw(regs.viewport_size_y).ToFloat32() * 2;
+ GLsizei viewport_width =
+ (GLsizei)Pica::float24::FromRaw(regs.rasterizer.viewport_size_x).ToFloat32() * 2;
+ GLsizei viewport_height =
+ (GLsizei)Pica::float24::FromRaw(regs.rasterizer.viewport_size_y).ToFloat32() * 2;
- glViewport((GLint)(rect.left + regs.viewport_corner.x * color_surface->res_scale_width),
- (GLint)(rect.bottom + regs.viewport_corner.y * color_surface->res_scale_height),
- (GLsizei)(viewport_width * color_surface->res_scale_width),
- (GLsizei)(viewport_height * color_surface->res_scale_height));
+ glViewport(
+ (GLint)(rect.left + regs.rasterizer.viewport_corner.x * color_surface->res_scale_width),
+ (GLint)(rect.bottom + regs.rasterizer.viewport_corner.y * color_surface->res_scale_height),
+ (GLsizei)(viewport_width * color_surface->res_scale_width),
+ (GLsizei)(viewport_height * color_surface->res_scale_height));
if (uniform_block_data.data.framebuffer_scale[0] != color_surface->res_scale_width ||
uniform_block_data.data.framebuffer_scale[1] != color_surface->res_scale_height) {
@@ -215,16 +221,16 @@ void RasterizerOpenGL::DrawTriangles() {
// Scissor checks are window-, not viewport-relative, which means that if the cached texture
// sub-rect changes, the scissor bounds also need to be updated.
- GLint scissor_x1 =
- static_cast<GLint>(rect.left + regs.scissor_test.x1 * color_surface->res_scale_width);
- GLint scissor_y1 =
- static_cast<GLint>(rect.bottom + regs.scissor_test.y1 * color_surface->res_scale_height);
+ GLint scissor_x1 = static_cast<GLint>(
+ rect.left + regs.rasterizer.scissor_test.x1 * color_surface->res_scale_width);
+ GLint scissor_y1 = static_cast<GLint>(
+ rect.bottom + regs.rasterizer.scissor_test.y1 * color_surface->res_scale_height);
// x2, y2 have +1 added to cover the entire pixel area, otherwise you might get cracks when
// scaling or doing multisampling.
- GLint scissor_x2 =
- static_cast<GLint>(rect.left + (regs.scissor_test.x2 + 1) * color_surface->res_scale_width);
+ GLint scissor_x2 = static_cast<GLint>(
+ rect.left + (regs.rasterizer.scissor_test.x2 + 1) * color_surface->res_scale_width);
GLint scissor_y2 = static_cast<GLint>(
- rect.bottom + (regs.scissor_test.y2 + 1) * color_surface->res_scale_height);
+ rect.bottom + (regs.rasterizer.scissor_test.y2 + 1) * color_surface->res_scale_height);
if (uniform_block_data.data.scissor_x1 != scissor_x1 ||
uniform_block_data.data.scissor_x2 != scissor_x2 ||
@@ -239,7 +245,7 @@ void RasterizerOpenGL::DrawTriangles() {
}
// Sync and bind the texture surfaces
- const auto pica_textures = regs.GetTextures();
+ const auto pica_textures = regs.texturing.GetTextures();
for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
const auto& texture = pica_textures[texture_index];
@@ -316,69 +322,69 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
switch (id) {
// Culling
- case PICA_REG_INDEX(cull_mode):
+ case PICA_REG_INDEX(rasterizer.cull_mode):
SyncCullMode();
break;
// Depth modifiers
- case PICA_REG_INDEX(viewport_depth_range):
+ case PICA_REG_INDEX(rasterizer.viewport_depth_range):
SyncDepthScale();
break;
- case PICA_REG_INDEX(viewport_depth_near_plane):
+ case PICA_REG_INDEX(rasterizer.viewport_depth_near_plane):
SyncDepthOffset();
break;
// Depth buffering
- case PICA_REG_INDEX(depthmap_enable):
+ case PICA_REG_INDEX(rasterizer.depthmap_enable):
shader_dirty = true;
break;
// Blending
- case PICA_REG_INDEX(output_merger.alphablend_enable):
+ case PICA_REG_INDEX(framebuffer.output_merger.alphablend_enable):
SyncBlendEnabled();
break;
- case PICA_REG_INDEX(output_merger.alpha_blending):
+ case PICA_REG_INDEX(framebuffer.output_merger.alpha_blending):
SyncBlendFuncs();
break;
- case PICA_REG_INDEX(output_merger.blend_const):
+ case PICA_REG_INDEX(framebuffer.output_merger.blend_const):
SyncBlendColor();
break;
// Fog state
- case PICA_REG_INDEX(fog_color):
+ case PICA_REG_INDEX(texturing.fog_color):
SyncFogColor();
break;
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[0], 0xe8):
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[1], 0xe9):
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[2], 0xea):
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[3], 0xeb):
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[4], 0xec):
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[5], 0xed):
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[6], 0xee):
- case PICA_REG_INDEX_WORKAROUND(fog_lut_data[7], 0xef):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[0], 0xe8):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[1], 0xe9):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[2], 0xea):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[3], 0xeb):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[4], 0xec):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[5], 0xed):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[6], 0xee):
+ case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[7], 0xef):
uniform_block_data.fog_lut_dirty = true;
break;
// Alpha test
- case PICA_REG_INDEX(output_merger.alpha_test):
+ case PICA_REG_INDEX(framebuffer.output_merger.alpha_test):
SyncAlphaTest();
shader_dirty = true;
break;
// Sync GL stencil test + stencil write mask
// (Pica stencil test function register also contains a stencil write mask)
- case PICA_REG_INDEX(output_merger.stencil_test.raw_func):
+ case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_func):
SyncStencilTest();
SyncStencilWriteMask();
break;
- case PICA_REG_INDEX(output_merger.stencil_test.raw_op):
- case PICA_REG_INDEX(framebuffer.depth_format):
+ case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_op):
+ case PICA_REG_INDEX(framebuffer.framebuffer.depth_format):
SyncStencilTest();
break;
// Sync GL depth test + depth and color write mask
// (Pica depth test function register also contains a depth and color write mask)
- case PICA_REG_INDEX(output_merger.depth_test_enable):
+ case PICA_REG_INDEX(framebuffer.output_merger.depth_test_enable):
SyncDepthTest();
SyncDepthWriteMask();
SyncColorWriteMask();
@@ -386,82 +392,82 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
// Sync GL depth and stencil write mask
// (This is a dedicated combined depth / stencil write-enable register)
- case PICA_REG_INDEX(framebuffer.allow_depth_stencil_write):
+ case PICA_REG_INDEX(framebuffer.framebuffer.allow_depth_stencil_write):
SyncDepthWriteMask();
SyncStencilWriteMask();
break;
// Sync GL color write mask
// (This is a dedicated color write-enable register)
- case PICA_REG_INDEX(framebuffer.allow_color_write):
+ case PICA_REG_INDEX(framebuffer.framebuffer.allow_color_write):
SyncColorWriteMask();
break;
// Scissor test
- case PICA_REG_INDEX(scissor_test.mode):
+ case PICA_REG_INDEX(rasterizer.scissor_test.mode):
shader_dirty = true;
break;
// Logic op
- case PICA_REG_INDEX(output_merger.logic_op):
+ case PICA_REG_INDEX(framebuffer.output_merger.logic_op):
SyncLogicOp();
break;
// Texture 0 type
- case PICA_REG_INDEX(texture0.type):
+ case PICA_REG_INDEX(texturing.texture0.type):
shader_dirty = true;
break;
// TEV stages
// (This also syncs fog_mode and fog_flip which are part of tev_combiner_buffer_input)
- case PICA_REG_INDEX(tev_stage0.color_source1):
- case PICA_REG_INDEX(tev_stage0.color_modifier1):
- case PICA_REG_INDEX(tev_stage0.color_op):
- case PICA_REG_INDEX(tev_stage0.color_scale):
- case PICA_REG_INDEX(tev_stage1.color_source1):
- case PICA_REG_INDEX(tev_stage1.color_modifier1):
- case PICA_REG_INDEX(tev_stage1.color_op):
- case PICA_REG_INDEX(tev_stage1.color_scale):
- case PICA_REG_INDEX(tev_stage2.color_source1):
- case PICA_REG_INDEX(tev_stage2.color_modifier1):
- case PICA_REG_INDEX(tev_stage2.color_op):
- case PICA_REG_INDEX(tev_stage2.color_scale):
- case PICA_REG_INDEX(tev_stage3.color_source1):
- case PICA_REG_INDEX(tev_stage3.color_modifier1):
- case PICA_REG_INDEX(tev_stage3.color_op):
- case PICA_REG_INDEX(tev_stage3.color_scale):
- case PICA_REG_INDEX(tev_stage4.color_source1):
- case PICA_REG_INDEX(tev_stage4.color_modifier1):
- case PICA_REG_INDEX(tev_stage4.color_op):
- case PICA_REG_INDEX(tev_stage4.color_scale):
- case PICA_REG_INDEX(tev_stage5.color_source1):
- case PICA_REG_INDEX(tev_stage5.color_modifier1):
- case PICA_REG_INDEX(tev_stage5.color_op):
- case PICA_REG_INDEX(tev_stage5.color_scale):
- case PICA_REG_INDEX(tev_combiner_buffer_input):
+ case PICA_REG_INDEX(texturing.tev_stage0.color_source1):
+ case PICA_REG_INDEX(texturing.tev_stage0.color_modifier1):
+ case PICA_REG_INDEX(texturing.tev_stage0.color_op):
+ case PICA_REG_INDEX(texturing.tev_stage0.color_scale):
+ case PICA_REG_INDEX(texturing.tev_stage1.color_source1):
+ case PICA_REG_INDEX(texturing.tev_stage1.color_modifier1):
+ case PICA_REG_INDEX(texturing.tev_stage1.color_op):
+ case PICA_REG_INDEX(texturing.tev_stage1.color_scale):
+ case PICA_REG_INDEX(texturing.tev_stage2.color_source1):
+ case PICA_REG_INDEX(texturing.tev_stage2.color_modifier1):
+ case PICA_REG_INDEX(texturing.tev_stage2.color_op):
+ case PICA_REG_INDEX(texturing.tev_stage2.color_scale):
+ case PICA_REG_INDEX(texturing.tev_stage3.color_source1):
+ case PICA_REG_INDEX(texturing.tev_stage3.color_modifier1):
+ case PICA_REG_INDEX(texturing.tev_stage3.color_op):
+ case PICA_REG_INDEX(texturing.tev_stage3.color_scale):
+ case PICA_REG_INDEX(texturing.tev_stage4.color_source1):
+ case PICA_REG_INDEX(texturing.tev_stage4.color_modifier1):
+ case PICA_REG_INDEX(texturing.tev_stage4.color_op):
+ case PICA_REG_INDEX(texturing.tev_stage4.color_scale):
+ case PICA_REG_INDEX(texturing.tev_stage5.color_source1):
+ case PICA_REG_INDEX(texturing.tev_stage5.color_modifier1):
+ case PICA_REG_INDEX(texturing.tev_stage5.color_op):
+ case PICA_REG_INDEX(texturing.tev_stage5.color_scale):
+ case PICA_REG_INDEX(texturing.tev_combiner_buffer_input):
shader_dirty = true;
break;
- case PICA_REG_INDEX(tev_stage0.const_r):
- SyncTevConstColor(0, regs.tev_stage0);
+ case PICA_REG_INDEX(texturing.tev_stage0.const_r):
+ SyncTevConstColor(0, regs.texturing.tev_stage0);
break;
- case PICA_REG_INDEX(tev_stage1.const_r):
- SyncTevConstColor(1, regs.tev_stage1);
+ case PICA_REG_INDEX(texturing.tev_stage1.const_r):
+ SyncTevConstColor(1, regs.texturing.tev_stage1);
break;
- case PICA_REG_INDEX(tev_stage2.const_r):
- SyncTevConstColor(2, regs.tev_stage2);
+ case PICA_REG_INDEX(texturing.tev_stage2.const_r):
+ SyncTevConstColor(2, regs.texturing.tev_stage2);
break;
- case PICA_REG_INDEX(tev_stage3.const_r):
- SyncTevConstColor(3, regs.tev_stage3);
+ case PICA_REG_INDEX(texturing.tev_stage3.const_r):
+ SyncTevConstColor(3, regs.texturing.tev_stage3);
break;
- case PICA_REG_INDEX(tev_stage4.const_r):
- SyncTevConstColor(4, regs.tev_stage4);
+ case PICA_REG_INDEX(texturing.tev_stage4.const_r):
+ SyncTevConstColor(4, regs.texturing.tev_stage4);
break;
- case PICA_REG_INDEX(tev_stage5.const_r):
- SyncTevConstColor(5, regs.tev_stage5);
+ case PICA_REG_INDEX(texturing.tev_stage5.const_r):
+ SyncTevConstColor(5, regs.texturing.tev_stage5);
break;
// TEV combiner buffer color
- case PICA_REG_INDEX(tev_combiner_buffer_color):
+ case PICA_REG_INDEX(texturing.tev_combiner_buffer_color):
SyncCombinerColor();
break;
@@ -976,7 +982,9 @@ void RasterizerOpenGL::SamplerInfo::Create() {
// Other attributes have correct defaults
}
-void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Pica::Regs::TextureConfig& config) {
+void RasterizerOpenGL::SamplerInfo::SyncWithConfig(
+ const Pica::TexturingRegs::TextureConfig& config) {
+
GLuint s = sampler.handle;
if (mag_filter != config.mag_filter) {
@@ -1088,7 +1096,7 @@ void RasterizerOpenGL::SetShader() {
SyncDepthOffset();
SyncAlphaTest();
SyncCombinerColor();
- auto& tev_stages = Pica::g_state.regs.GetTevStages();
+ auto& tev_stages = Pica::g_state.regs.texturing.GetTevStages();
for (int index = 0; index < tev_stages.size(); ++index)
SyncTevConstColor(index, tev_stages[index]);
@@ -1110,30 +1118,31 @@ void RasterizerOpenGL::SetShader() {
void RasterizerOpenGL::SyncCullMode() {
const auto& regs = Pica::g_state.regs;
- switch (regs.cull_mode) {
- case Pica::Regs::CullMode::KeepAll:
+ switch (regs.rasterizer.cull_mode) {
+ case Pica::RasterizerRegs::CullMode::KeepAll:
state.cull.enabled = false;
break;
- case Pica::Regs::CullMode::KeepClockWise:
+ case Pica::RasterizerRegs::CullMode::KeepClockWise:
state.cull.enabled = true;
state.cull.front_face = GL_CW;
break;
- case Pica::Regs::CullMode::KeepCounterClockWise:
+ case Pica::RasterizerRegs::CullMode::KeepCounterClockWise:
state.cull.enabled = true;
state.cull.front_face = GL_CCW;
break;
default:
- LOG_CRITICAL(Render_OpenGL, "Unknown cull mode %d", regs.cull_mode.Value());
+ LOG_CRITICAL(Render_OpenGL, "Unknown cull mode %d", regs.rasterizer.cull_mode.Value());
UNIMPLEMENTED();
break;
}
}
void RasterizerOpenGL::SyncDepthScale() {
- float depth_scale = Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_range).ToFloat32();
+ float depth_scale =
+ Pica::float24::FromRaw(Pica::g_state.regs.rasterizer.viewport_depth_range).ToFloat32();
if (depth_scale != uniform_block_data.data.depth_scale) {
uniform_block_data.data.depth_scale = depth_scale;
uniform_block_data.dirty = true;
@@ -1142,7 +1151,7 @@ void RasterizerOpenGL::SyncDepthScale() {
void RasterizerOpenGL::SyncDepthOffset() {
float depth_offset =
- Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_near_plane).ToFloat32();
+ Pica::float24::FromRaw(Pica::g_state.regs.rasterizer.viewport_depth_near_plane).ToFloat32();
if (depth_offset != uniform_block_data.data.depth_offset) {
uniform_block_data.data.depth_offset = depth_offset;
uniform_block_data.dirty = true;
@@ -1150,25 +1159,28 @@ void RasterizerOpenGL::SyncDepthOffset() {
}
void RasterizerOpenGL::SyncBlendEnabled() {
- state.blend.enabled = (Pica::g_state.regs.output_merger.alphablend_enable == 1);
+ state.blend.enabled = (Pica::g_state.regs.framebuffer.output_merger.alphablend_enable == 1);
}
void RasterizerOpenGL::SyncBlendFuncs() {
const auto& regs = Pica::g_state.regs;
state.blend.rgb_equation =
- PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_rgb);
+ PicaToGL::BlendEquation(regs.framebuffer.output_merger.alpha_blending.blend_equation_rgb);
state.blend.a_equation =
- PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_a);
+ PicaToGL::BlendEquation(regs.framebuffer.output_merger.alpha_blending.blend_equation_a);
state.blend.src_rgb_func =
- PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb);
+ PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_source_rgb);
state.blend.dst_rgb_func =
- PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb);
- state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a);
- state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a);
+ PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_rgb);
+ state.blend.src_a_func =
+ PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_source_a);
+ state.blend.dst_a_func =
+ PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_a);
}
void RasterizerOpenGL::SyncBlendColor() {
- auto blend_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.output_merger.blend_const.raw);
+ auto blend_color =
+ PicaToGL::ColorRGBA8(Pica::g_state.regs.framebuffer.output_merger.blend_const.raw);
state.blend.color.red = blend_color[0];
state.blend.color.green = blend_color[1];
state.blend.color.blue = blend_color[2];
@@ -1178,8 +1190,8 @@ void RasterizerOpenGL::SyncBlendColor() {
void RasterizerOpenGL::SyncFogColor() {
const auto& regs = Pica::g_state.regs;
uniform_block_data.data.fog_color = {
- regs.fog_color.r.Value() / 255.0f, regs.fog_color.g.Value() / 255.0f,
- regs.fog_color.b.Value() / 255.0f,
+ regs.texturing.fog_color.r.Value() / 255.0f, regs.texturing.fog_color.g.Value() / 255.0f,
+ regs.texturing.fog_color.b.Value() / 255.0f,
};
uniform_block_data.dirty = true;
}
@@ -1200,70 +1212,78 @@ void RasterizerOpenGL::SyncFogLUT() {
void RasterizerOpenGL::SyncAlphaTest() {
const auto& regs = Pica::g_state.regs;
- if (regs.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) {
- uniform_block_data.data.alphatest_ref = regs.output_merger.alpha_test.ref;
+ if (regs.framebuffer.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) {
+ uniform_block_data.data.alphatest_ref = regs.framebuffer.output_merger.alpha_test.ref;
uniform_block_data.dirty = true;
}
}
void RasterizerOpenGL::SyncLogicOp() {
- state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op);
+ state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.framebuffer.output_merger.logic_op);
}
void RasterizerOpenGL::SyncColorWriteMask() {
const auto& regs = Pica::g_state.regs;
auto IsColorWriteEnabled = [&](u32 value) {
- return (regs.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE : GL_FALSE;
+ return (regs.framebuffer.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE
+ : GL_FALSE;
};
- state.color_mask.red_enabled = IsColorWriteEnabled(regs.output_merger.red_enable);
- state.color_mask.green_enabled = IsColorWriteEnabled(regs.output_merger.green_enable);
- state.color_mask.blue_enabled = IsColorWriteEnabled(regs.output_merger.blue_enable);
- state.color_mask.alpha_enabled = IsColorWriteEnabled(regs.output_merger.alpha_enable);
+ state.color_mask.red_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.red_enable);
+ state.color_mask.green_enabled =
+ IsColorWriteEnabled(regs.framebuffer.output_merger.green_enable);
+ state.color_mask.blue_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.blue_enable);
+ state.color_mask.alpha_enabled =
+ IsColorWriteEnabled(regs.framebuffer.output_merger.alpha_enable);
}
void RasterizerOpenGL::SyncStencilWriteMask() {
const auto& regs = Pica::g_state.regs;
- state.stencil.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0)
- ? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask)
- : 0;
+ state.stencil.write_mask =
+ (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0)
+ ? static_cast<GLuint>(regs.framebuffer.output_merger.stencil_test.write_mask)
+ : 0;
}
void RasterizerOpenGL::SyncDepthWriteMask() {
const auto& regs = Pica::g_state.regs;
- state.depth.write_mask =
- (regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable)
- ? GL_TRUE
- : GL_FALSE;
+ state.depth.write_mask = (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 &&
+ regs.framebuffer.output_merger.depth_write_enable)
+ ? GL_TRUE
+ : GL_FALSE;
}
void RasterizerOpenGL::SyncStencilTest() {
const auto& regs = Pica::g_state.regs;
- state.stencil.test_enabled = regs.output_merger.stencil_test.enable &&
- regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8;
- state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func);
- state.stencil.test_ref = regs.output_merger.stencil_test.reference_value;
- state.stencil.test_mask = regs.output_merger.stencil_test.input_mask;
+ state.stencil.test_enabled =
+ regs.framebuffer.output_merger.stencil_test.enable &&
+ regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8;
+ state.stencil.test_func =
+ PicaToGL::CompareFunc(regs.framebuffer.output_merger.stencil_test.func);
+ state.stencil.test_ref = regs.framebuffer.output_merger.stencil_test.reference_value;
+ state.stencil.test_mask = regs.framebuffer.output_merger.stencil_test.input_mask;
state.stencil.action_stencil_fail =
- PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail);
+ PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_stencil_fail);
state.stencil.action_depth_fail =
- PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail);
+ PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_depth_fail);
state.stencil.action_depth_pass =
- PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass);
+ PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_depth_pass);
}
void RasterizerOpenGL::SyncDepthTest() {
const auto& regs = Pica::g_state.regs;
- state.depth.test_enabled =
- regs.output_merger.depth_test_enable == 1 || regs.output_merger.depth_write_enable == 1;
- state.depth.test_func = regs.output_merger.depth_test_enable == 1
- ? PicaToGL::CompareFunc(regs.output_merger.depth_test_func)
- : GL_ALWAYS;
+ state.depth.test_enabled = regs.framebuffer.output_merger.depth_test_enable == 1 ||
+ regs.framebuffer.output_merger.depth_write_enable == 1;
+ state.depth.test_func =
+ regs.framebuffer.output_merger.depth_test_enable == 1
+ ? PicaToGL::CompareFunc(regs.framebuffer.output_merger.depth_test_func)
+ : GL_ALWAYS;
}
void RasterizerOpenGL::SyncCombinerColor() {
- auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw);
+ auto combiner_color =
+ PicaToGL::ColorRGBA8(Pica::g_state.regs.texturing.tev_combiner_buffer_color.raw);
if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) {
uniform_block_data.data.tev_combiner_buffer_color = combiner_color;
uniform_block_data.dirty = true;
@@ -1271,7 +1291,7 @@ void RasterizerOpenGL::SyncCombinerColor() {
}
void RasterizerOpenGL::SyncTevConstColor(int stage_index,
- const Pica::Regs::TevStageConfig& tev_stage) {
+ const Pica::TexturingRegs::TevStageConfig& tev_stage) {
auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color);
if (const_color != uniform_block_data.data.const_color[stage_index]) {
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 @@
#include "common/hash.h"
#include "common/vector_math.h"
#include "core/hw/gpu.h"
-#include "video_core/pica.h"
#include "video_core/pica_state.h"
#include "video_core/pica_types.h"
#include "video_core/rasterizer_interface.h"
+#include "video_core/regs.h"
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_state.h"
@@ -52,20 +52,20 @@ union PicaShaderConfig {
const auto& regs = Pica::g_state.regs;
- state.scissor_test_mode = regs.scissor_test.mode;
+ state.scissor_test_mode = regs.rasterizer.scissor_test.mode;
- state.depthmap_enable = regs.depthmap_enable;
+ state.depthmap_enable = regs.rasterizer.depthmap_enable;
- state.alpha_test_func = regs.output_merger.alpha_test.enable
- ? regs.output_merger.alpha_test.func.Value()
- : Pica::Regs::CompareFunc::Always;
+ state.alpha_test_func = regs.framebuffer.output_merger.alpha_test.enable
+ ? regs.framebuffer.output_merger.alpha_test.func.Value()
+ : Pica::FramebufferRegs::CompareFunc::Always;
- state.texture0_type = regs.texture0.type;
+ state.texture0_type = regs.texturing.texture0.type;
// Copy relevant tev stages fields.
// We don't sync const_color here because of the high variance, it is a
// shader uniform instead.
- const auto& tev_stages = regs.GetTevStages();
+ const auto& tev_stages = regs.texturing.GetTevStages();
DEBUG_ASSERT(state.tev_stages.size() == tev_stages.size());
for (size_t i = 0; i < tev_stages.size(); i++) {
const auto& tev_stage = tev_stages[i];
@@ -75,11 +75,12 @@ union PicaShaderConfig {
state.tev_stages[i].scales_raw = tev_stage.scales_raw;
}
- state.fog_mode = regs.fog_mode;
- state.fog_flip = regs.fog_flip != 0;
+ state.fog_mode = regs.texturing.fog_mode;
+ state.fog_flip = regs.texturing.fog_flip != 0;
- state.combiner_buffer_input = regs.tev_combiner_buffer_input.update_mask_rgb.Value() |
- regs.tev_combiner_buffer_input.update_mask_a.Value() << 4;
+ state.combiner_buffer_input =
+ regs.texturing.tev_combiner_buffer_input.update_mask_rgb.Value() |
+ regs.texturing.tev_combiner_buffer_input.update_mask_a.Value() << 4;
// Fragment lighting
@@ -159,8 +160,8 @@ union PicaShaderConfig {
u32 modifiers_raw;
u32 ops_raw;
u32 scales_raw;
- explicit operator Pica::Regs::TevStageConfig() const noexcept {
- Pica::Regs::TevStageConfig stage;
+ explicit operator Pica::TexturingRegs::TevStageConfig() const noexcept {
+ Pica::TexturingRegs::TevStageConfig stage;
stage.sources_raw = sources_raw;
stage.modifiers_raw = modifiers_raw;
stage.ops_raw = ops_raw;
@@ -171,14 +172,14 @@ union PicaShaderConfig {
};
struct State {
- Pica::Regs::CompareFunc alpha_test_func;
- Pica::Regs::ScissorMode scissor_test_mode;
- Pica::Regs::TextureConfig::TextureType texture0_type;
+ Pica::FramebufferRegs::CompareFunc alpha_test_func;
+ Pica::RasterizerRegs::ScissorMode scissor_test_mode;
+ Pica::TexturingRegs::TextureConfig::TextureType texture0_type;
std::array<TevStageConfigRaw, 6> tev_stages;
u8 combiner_buffer_input;
- Pica::Regs::DepthBuffering depthmap_enable;
- Pica::Regs::FogMode fog_mode;
+ Pica::RasterizerRegs::DepthBuffering depthmap_enable;
+ Pica::TexturingRegs::FogMode fog_mode;
bool fog_flip;
struct {
@@ -191,18 +192,18 @@ union PicaShaderConfig {
bool enable;
unsigned src_num;
- Pica::Regs::LightingBumpMode bump_mode;
+ Pica::LightingRegs::LightingBumpMode bump_mode;
unsigned bump_selector;
bool bump_renorm;
bool clamp_highlights;
- Pica::Regs::LightingConfig config;
- Pica::Regs::LightingFresnelSelector fresnel_selector;
+ Pica::LightingRegs::LightingConfig config;
+ Pica::LightingRegs::LightingFresnelSelector fresnel_selector;
struct {
bool enable;
bool abs_input;
- Pica::Regs::LightingLutInput type;
+ Pica::LightingRegs::LightingLutInput type;
float scale;
} lut_d0, lut_d1, lut_fr, lut_rr, lut_rg, lut_rb;
} lighting;
@@ -251,7 +252,7 @@ public:
private:
struct SamplerInfo {
- using TextureConfig = Pica::Regs::TextureConfig;
+ using TextureConfig = Pica::TexturingRegs::TextureConfig;
OGLSampler sampler;
@@ -398,7 +399,7 @@ private:
void SyncCombinerColor();
/// Syncs the TEV constant color to match the PICA register
- void SyncTevConstColor(int tev_index, const Pica::Regs::TevStageConfig& tev_stage);
+ void SyncTevConstColor(int tev_index, const Pica::TexturingRegs::TevStageConfig& tev_stage);
/// Syncs the lighting global ambient color to match the PICA register
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
Pica::Texture::TextureInfo tex_info;
tex_info.width = params.width;
tex_info.height = params.height;
- tex_info.format = (Pica::Regs::TextureFormat)params.pixel_format;
+ tex_info.format = (Pica::TexturingRegs::TextureFormat)params.pixel_format;
tex_info.SetDefaultStride();
tex_info.physical_address = params.addr;
@@ -510,7 +510,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params
}
CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(
- const Pica::Regs::FullTextureConfig& config) {
+ const Pica::TexturingRegs::FullTextureConfig& config) {
Pica::Texture::TextureInfo info =
Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format);
@@ -525,7 +525,9 @@ CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(
}
std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>>
-RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config) {
+RasterizerCacheOpenGL::GetFramebufferSurfaces(
+ const Pica::FramebufferRegs::FramebufferConfig& config) {
+
const auto& regs = Pica::g_state.regs;
// 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
config.GetColorBufferPhysicalAddress(),
fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())),
config.GetDepthBufferPhysicalAddress(),
- fb_area * Pica::Regs::BytesPerDepthPixel(config.depth_format));
+ fb_area * Pica::FramebufferRegs::BytesPerDepthPixel(config.depth_format));
bool using_color_fb = config.GetColorBufferPhysicalAddress() != 0;
- bool using_depth_fb = config.GetDepthBufferPhysicalAddress() != 0 &&
- (regs.output_merger.depth_test_enable ||
- regs.output_merger.depth_write_enable || !framebuffers_overlap);
+ bool using_depth_fb =
+ config.GetDepthBufferPhysicalAddress() != 0 &&
+ (regs.framebuffer.output_merger.depth_test_enable ||
+ regs.framebuffer.output_merger.depth_write_enable || !framebuffers_overlap);
if (framebuffers_overlap && using_color_fb && using_depth_fb) {
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 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hw/gpu.h"
-#include "video_core/pica.h"
+#include "video_core/regs.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
namespace MathUtil {
@@ -96,15 +96,15 @@ struct CachedSurface {
return bpp_table[(unsigned int)format];
}
- static PixelFormat PixelFormatFromTextureFormat(Pica::Regs::TextureFormat format) {
+ static PixelFormat PixelFormatFromTextureFormat(Pica::TexturingRegs::TextureFormat format) {
return ((unsigned int)format < 14) ? (PixelFormat)format : PixelFormat::Invalid;
}
- static PixelFormat PixelFormatFromColorFormat(Pica::Regs::ColorFormat format) {
+ static PixelFormat PixelFormatFromColorFormat(Pica::FramebufferRegs::ColorFormat format) {
return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid;
}
- static PixelFormat PixelFormatFromDepthFormat(Pica::Regs::DepthFormat format) {
+ static PixelFormat PixelFormatFromDepthFormat(Pica::FramebufferRegs::DepthFormat format) {
return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14)
: PixelFormat::Invalid;
}
@@ -212,12 +212,12 @@ public:
bool load_if_create, MathUtil::Rectangle<int>& out_rect);
/// Gets a surface based on the texture configuration
- CachedSurface* GetTextureSurface(const Pica::Regs::FullTextureConfig& config);
+ CachedSurface* GetTextureSurface(const Pica::TexturingRegs::FullTextureConfig& config);
/// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer
/// configuration
std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> GetFramebufferSurfaces(
- const Pica::Regs::FramebufferConfig& config);
+ const Pica::FramebufferRegs::FramebufferConfig& config);
/// Attempt to get a surface that exactly matches the fill region and format
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 @@
#include "common/assert.h"
#include "common/bit_field.h"
#include "common/logging/log.h"
-#include "video_core/pica.h"
+#include "video_core/regs.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/gl_shader_gen.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
using Pica::Regs;
-using TevStageConfig = Regs::TevStageConfig;
+using Pica::RasterizerRegs;
+using Pica::LightingRegs;
+using TevStageConfig = Pica::TexturingRegs::TevStageConfig;
namespace GLShader {
@@ -46,10 +48,10 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config,
case Source::Texture0:
// Only unit 0 respects the texturing type (according to 3DBrew)
switch (state.texture0_type) {
- case Pica::Regs::TextureConfig::Texture2D:
+ case Pica::TexturingRegs::TextureConfig::Texture2D:
out += "texture(tex[0], texcoord[0])";
break;
- case Pica::Regs::TextureConfig::Projection2D:
+ case Pica::TexturingRegs::TextureConfig::Projection2D:
out += "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))";
break;
default:
@@ -276,8 +278,8 @@ static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation oper
}
/// Writes the if-statement condition used to evaluate alpha testing
-static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) {
- using CompareFunc = Regs::CompareFunc;
+static void AppendAlphaTestCondition(std::string& out, Pica::FramebufferRegs::CompareFunc func) {
+ using CompareFunc = Pica::FramebufferRegs::CompareFunc;
switch (func) {
case CompareFunc::Never:
out += "true";
@@ -307,7 +309,7 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) {
/// Writes the code to emulate the specified TEV stage
static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) {
const auto stage =
- static_cast<const Pica::Regs::TevStageConfig>(config.state.tev_stages[index]);
+ static_cast<const Pica::TexturingRegs::TevStageConfig>(config.state.tev_stages[index]);
if (!IsPassThroughTevStage(stage)) {
std::string index_name = std::to_string(index);
@@ -364,7 +366,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
"vec3 refl_value = vec3(0.0);\n";
// Compute fragment normals
- if (lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) {
+ if (lighting.bump_mode == LightingRegs::LightingBumpMode::NormalMap) {
// Bump mapping is enabled using a normal map, read perturbation vector from the selected
// texture
std::string bump_selector = std::to_string(lighting.bump_selector);
@@ -378,7 +380,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
"(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))";
out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n";
}
- } else if (lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) {
+ } else if (lighting.bump_mode == LightingRegs::LightingBumpMode::TangentMap) {
// Bump mapping is enabled using a tangent map
LOG_CRITICAL(HW_GPU, "unimplemented bump mapping mode (tangent mapping)");
UNIMPLEMENTED();
@@ -392,23 +394,24 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n";
// Gets the index into the specified lookup table for specular lighting
- auto GetLutIndex = [&lighting](unsigned light_num, Regs::LightingLutInput input, bool abs) {
+ auto GetLutIndex = [&lighting](unsigned light_num, LightingRegs::LightingLutInput input,
+ bool abs) {
const std::string half_angle = "normalize(normalize(view) + light_vector)";
std::string index;
switch (input) {
- case Regs::LightingLutInput::NH:
+ case LightingRegs::LightingLutInput::NH:
index = "dot(normal, " + half_angle + ")";
break;
- case Regs::LightingLutInput::VH:
+ case LightingRegs::LightingLutInput::VH:
index = std::string("dot(normalize(view), " + half_angle + ")");
break;
- case Regs::LightingLutInput::NV:
+ case LightingRegs::LightingLutInput::NV:
index = std::string("dot(normal, normalize(view))");
break;
- case Regs::LightingLutInput::LN:
+ case LightingRegs::LightingLutInput::LN:
index = std::string("dot(light_vector, normal)");
break;
@@ -432,7 +435,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
};
// Gets the lighting lookup table value given the specified sampler and index
- auto GetLutValue = [](Regs::LightingSampler sampler, std::string lut_index) {
+ auto GetLutValue = [](LightingRegs::LightingSampler sampler, std::string lut_index) {
return std::string("texture(lut[" + std::to_string((unsigned)sampler / 4) + "], " +
lut_index + ")[" + std::to_string((unsigned)sampler & 3) + "]");
};
@@ -461,8 +464,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
light_src + ".position) + " + light_src + ".dist_atten_bias)";
index = "(OFFSET_256 + SCALE_256 * clamp(" + index + ", 0.0, 1.0))";
const unsigned lut_num =
- ((unsigned)Regs::LightingSampler::DistanceAttenuation + light_config.num);
- dist_atten = GetLutValue((Regs::LightingSampler)lut_num, index);
+ ((unsigned)LightingRegs::LightingSampler::DistanceAttenuation + light_config.num);
+ dist_atten = GetLutValue((LightingRegs::LightingSampler)lut_num, index);
}
// If enabled, clamp specular component if lighting result is negative
@@ -472,24 +475,24 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
// Specular 0 component
std::string d0_lut_value = "1.0";
if (lighting.lut_d0.enable &&
- Pica::Regs::IsLightingSamplerSupported(lighting.config,
- Pica::Regs::LightingSampler::Distribution0)) {
+ LightingRegs::IsLightingSamplerSupported(
+ lighting.config, LightingRegs::LightingSampler::Distribution0)) {
// Lookup specular "distribution 0" LUT value
std::string index =
GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input);
d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " +
- GetLutValue(Regs::LightingSampler::Distribution0, index) + ")";
+ GetLutValue(LightingRegs::LightingSampler::Distribution0, index) + ")";
}
std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)";
// If enabled, lookup ReflectRed value, otherwise, 1.0 is used
if (lighting.lut_rr.enable &&
- Pica::Regs::IsLightingSamplerSupported(lighting.config,
- Pica::Regs::LightingSampler::ReflectRed)) {
+ LightingRegs::IsLightingSamplerSupported(lighting.config,
+ LightingRegs::LightingSampler::ReflectRed)) {
std::string index =
GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input);
std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " +
- GetLutValue(Regs::LightingSampler::ReflectRed, index) + ")";
+ GetLutValue(LightingRegs::LightingSampler::ReflectRed, index) + ")";
out += "refl_value.r = " + value + ";\n";
} else {
out += "refl_value.r = 1.0;\n";
@@ -497,12 +500,13 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
// If enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used
if (lighting.lut_rg.enable &&
- Pica::Regs::IsLightingSamplerSupported(lighting.config,
- Pica::Regs::LightingSampler::ReflectGreen)) {
+ LightingRegs::IsLightingSamplerSupported(lighting.config,
+ LightingRegs::LightingSampler::ReflectGreen)) {
std::string index =
GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input);
std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " +
- GetLutValue(Regs::LightingSampler::ReflectGreen, index) + ")";
+ GetLutValue(LightingRegs::LightingSampler::ReflectGreen, index) +
+ ")";
out += "refl_value.g = " + value + ";\n";
} else {
out += "refl_value.g = refl_value.r;\n";
@@ -510,12 +514,13 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
// If enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used
if (lighting.lut_rb.enable &&
- Pica::Regs::IsLightingSamplerSupported(lighting.config,
- Pica::Regs::LightingSampler::ReflectBlue)) {
+ LightingRegs::IsLightingSamplerSupported(lighting.config,
+ LightingRegs::LightingSampler::ReflectBlue)) {
std::string index =
GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input);
std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " +
- GetLutValue(Regs::LightingSampler::ReflectBlue, index) + ")";
+ GetLutValue(LightingRegs::LightingSampler::ReflectBlue, index) +
+ ")";
out += "refl_value.b = " + value + ";\n";
} else {
out += "refl_value.b = refl_value.r;\n";
@@ -524,35 +529,39 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
// Specular 1 component
std::string d1_lut_value = "1.0";
if (lighting.lut_d1.enable &&
- Pica::Regs::IsLightingSamplerSupported(lighting.config,
- Pica::Regs::LightingSampler::Distribution1)) {
+ LightingRegs::IsLightingSamplerSupported(
+ lighting.config, LightingRegs::LightingSampler::Distribution1)) {
// Lookup specular "distribution 1" LUT value
std::string index =
GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input);
d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " +
- GetLutValue(Regs::LightingSampler::Distribution1, index) + ")";
+ GetLutValue(LightingRegs::LightingSampler::Distribution1, index) + ")";
}
std::string specular_1 =
"(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)";
// Fresnel
- if (lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported(
- lighting.config, Pica::Regs::LightingSampler::Fresnel)) {
+ if (lighting.lut_fr.enable &&
+ LightingRegs::IsLightingSamplerSupported(lighting.config,
+ LightingRegs::LightingSampler::Fresnel)) {
// Lookup fresnel LUT value
std::string index =
GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input);
std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " +
- GetLutValue(Regs::LightingSampler::Fresnel, index) + ")";
+ GetLutValue(LightingRegs::LightingSampler::Fresnel, index) + ")";
// Enabled for difffuse lighting alpha component
- if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha ||
- lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
+ if (lighting.fresnel_selector == LightingRegs::LightingFresnelSelector::PrimaryAlpha ||
+ lighting.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) {
out += "diffuse_sum.a *= " + value + ";\n";
+ }
// Enabled for the specular lighting alpha component
- if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::SecondaryAlpha ||
- lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
+ if (lighting.fresnel_selector ==
+ LightingRegs::LightingFresnelSelector::SecondaryAlpha ||
+ lighting.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) {
out += "specular_sum.a *= " + value + ";\n";
+ }
}
// Compute primary fragment color (diffuse lighting) function
@@ -633,16 +642,16 @@ vec4 secondary_fragment_color = vec4(0.0);
)";
// Do not do any sort of processing if it's obvious we're not going to pass the alpha test
- if (state.alpha_test_func == Regs::CompareFunc::Never) {
+ if (state.alpha_test_func == Pica::FramebufferRegs::CompareFunc::Never) {
out += "discard; }";
return out;
}
// Append the scissor test
- if (state.scissor_test_mode != Regs::ScissorMode::Disabled) {
+ if (state.scissor_test_mode != RasterizerRegs::ScissorMode::Disabled) {
out += "if (";
// Negate the condition if we have to keep only the pixels outside the scissor box
- if (state.scissor_test_mode == Regs::ScissorMode::Include)
+ if (state.scissor_test_mode == RasterizerRegs::ScissorMode::Include)
out += "!";
out += "(gl_FragCoord.x >= scissor_x1 && "
"gl_FragCoord.y >= scissor_y1 && "
@@ -652,7 +661,7 @@ vec4 secondary_fragment_color = vec4(0.0);
out += "float z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n";
out += "float depth = z_over_w * depth_scale + depth_offset;\n";
- if (state.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) {
+ if (state.depthmap_enable == Pica::RasterizerRegs::DepthBuffering::WBuffering) {
out += "depth /= gl_FragCoord.w;\n";
}
@@ -666,14 +675,14 @@ vec4 secondary_fragment_color = vec4(0.0);
for (size_t index = 0; index < state.tev_stages.size(); ++index)
WriteTevStage(out, config, (unsigned)index);
- if (state.alpha_test_func != Regs::CompareFunc::Always) {
+ if (state.alpha_test_func != Pica::FramebufferRegs::CompareFunc::Always) {
out += "if (";
AppendAlphaTestCondition(out, state.alpha_test_func);
out += ") discard;\n";
}
// Append fog combiner
- if (state.fog_mode == Regs::FogMode::Fog) {
+ if (state.fog_mode == Pica::TexturingRegs::FogMode::Fog) {
// Get index into fog LUT
if (state.fog_flip) {
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 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/logging/log.h"
-#include "video_core/pica.h"
+#include "video_core/regs.h"
using GLvec2 = std::array<GLfloat, 2>;
using GLvec3 = std::array<GLfloat, 3>;
@@ -20,7 +20,7 @@ using GLvec4 = std::array<GLfloat, 4>;
namespace PicaToGL {
-inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) {
+inline GLenum TextureFilterMode(Pica::TexturingRegs::TextureConfig::TextureFilter mode) {
static const GLenum filter_mode_table[] = {
GL_NEAREST, // TextureFilter::Nearest
GL_LINEAR, // TextureFilter::Linear
@@ -47,7 +47,7 @@ inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) {
return gl_mode;
}
-inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) {
+inline GLenum WrapMode(Pica::TexturingRegs::TextureConfig::WrapMode mode) {
static const GLenum wrap_mode_table[] = {
GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge
GL_CLAMP_TO_BORDER, // WrapMode::ClampToBorder
@@ -76,7 +76,7 @@ inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) {
return gl_mode;
}
-inline GLenum BlendEquation(Pica::Regs::BlendEquation equation) {
+inline GLenum BlendEquation(Pica::FramebufferRegs::BlendEquation equation) {
static const GLenum blend_equation_table[] = {
GL_FUNC_ADD, // BlendEquation::Add
GL_FUNC_SUBTRACT, // BlendEquation::Subtract
@@ -96,7 +96,7 @@ inline GLenum BlendEquation(Pica::Regs::BlendEquation equation) {
return blend_equation_table[(unsigned)equation];
}
-inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) {
+inline GLenum BlendFunc(Pica::FramebufferRegs::BlendFactor factor) {
static const GLenum blend_func_table[] = {
GL_ZERO, // BlendFactor::Zero
GL_ONE, // BlendFactor::One
@@ -126,7 +126,7 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) {
return blend_func_table[(unsigned)factor];
}
-inline GLenum LogicOp(Pica::Regs::LogicOp op) {
+inline GLenum LogicOp(Pica::FramebufferRegs::LogicOp op) {
static const GLenum logic_op_table[] = {
GL_CLEAR, // Clear
GL_AND, // And
@@ -157,7 +157,7 @@ inline GLenum LogicOp(Pica::Regs::LogicOp op) {
return logic_op_table[(unsigned)op];
}
-inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
+inline GLenum CompareFunc(Pica::FramebufferRegs::CompareFunc func) {
static const GLenum compare_func_table[] = {
GL_NEVER, // CompareFunc::Never
GL_ALWAYS, // CompareFunc::Always
@@ -180,7 +180,7 @@ inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
return compare_func_table[(unsigned)func];
}
-inline GLenum StencilOp(Pica::Regs::StencilAction action) {
+inline GLenum StencilOp(Pica::FramebufferRegs::StencilAction action) {
static const GLenum stencil_op_table[] = {
GL_KEEP, // StencilAction::Keep
GL_ZERO, // StencilAction::Zero
@@ -210,7 +210,7 @@ inline GLvec4 ColorRGBA8(const u32 color) {
}};
}
-inline std::array<GLfloat, 3> LightColor(const Pica::Regs::LightColor& color) {
+inline std::array<GLfloat, 3> LightColor(const Pica::LightingRegs::LightColor& color) {
return {{
color.r / 255.0f, color.g / 255.0f, color.b / 255.0f,
}};
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 @@
#include "common/bit_set.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
-#include "video_core/pica.h"
#include "video_core/pica_state.h"
+#include "video_core/regs.h"
#include "video_core/shader/shader.h"
#include "video_core/shader/shader_interpreter.h"
#ifdef ARCHITECTURE_x86_64
@@ -20,7 +20,7 @@ namespace Pica {
namespace Shader {
-OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer& input) {
+OutputVertex OutputVertex::FromAttributeBuffer(const RasterizerRegs& regs, AttributeBuffer& input) {
// Setup output data
union {
OutputVertex ret{};
@@ -33,16 +33,16 @@ OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer
for (unsigned int i = 0; i < num_attributes; ++i) {
const auto& output_register_map = regs.vs_output_attributes[i];
- Regs::VSOutputAttributes::Semantic semantics[4] = {
+ RasterizerRegs::VSOutputAttributes::Semantic semantics[4] = {
output_register_map.map_x, output_register_map.map_y, output_register_map.map_z,
output_register_map.map_w};
for (unsigned comp = 0; comp < 4; ++comp) {
- Regs::VSOutputAttributes::Semantic semantic = semantics[comp];
+ RasterizerRegs::VSOutputAttributes::Semantic semantic = semantics[comp];
float24* out = &vertex_slots[semantic];
if (semantic < vertex_slots.size()) {
*out = input.attr[i][comp];
- } else if (semantic != Regs::VSOutputAttributes::INVALID) {
+ } else if (semantic != RasterizerRegs::VSOutputAttributes::INVALID) {
LOG_ERROR(HW_GPU, "Invalid/unknown semantic id: %u", (unsigned int)semantic);
}
}
@@ -66,7 +66,7 @@ OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer
return ret;
}
-void UnitState::LoadInput(const Regs::ShaderConfig& config, const AttributeBuffer& input) {
+void UnitState::LoadInput(const ShaderRegs& config, const AttributeBuffer& input) {
const unsigned max_attribute = config.max_input_attribute_index;
for (unsigned attr = 0; attr <= max_attribute; ++attr) {
@@ -75,7 +75,7 @@ void UnitState::LoadInput(const Regs::ShaderConfig& config, const AttributeBuffe
}
}
-void UnitState::WriteOutput(const Regs::ShaderConfig& config, AttributeBuffer& output) {
+void UnitState::WriteOutput(const ShaderRegs& config, AttributeBuffer& output) {
unsigned int output_i = 0;
for (unsigned int reg : Common::BitSet<u32>(config.output_mask)) {
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 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/vector_math.h"
-#include "video_core/pica.h"
#include "video_core/pica_types.h"
+#include "video_core/regs.h"
using nihstro::RegisterType;
using nihstro::SourceRegister;
@@ -39,19 +39,19 @@ struct OutputVertex {
INSERT_PADDING_WORDS(1);
Math::Vec2<float24> tc2;
- static OutputVertex FromAttributeBuffer(const Regs& regs, AttributeBuffer& output);
+ static OutputVertex FromAttributeBuffer(const RasterizerRegs& regs, AttributeBuffer& output);
};
#define ASSERT_POS(var, pos) \
static_assert(offsetof(OutputVertex, var) == pos * sizeof(float24), "Semantic at wrong " \
"offset.")
-ASSERT_POS(pos, Regs::VSOutputAttributes::POSITION_X);
-ASSERT_POS(quat, Regs::VSOutputAttributes::QUATERNION_X);
-ASSERT_POS(color, Regs::VSOutputAttributes::COLOR_R);
-ASSERT_POS(tc0, Regs::VSOutputAttributes::TEXCOORD0_U);
-ASSERT_POS(tc1, Regs::VSOutputAttributes::TEXCOORD1_U);
-ASSERT_POS(tc0_w, Regs::VSOutputAttributes::TEXCOORD0_W);
-ASSERT_POS(view, Regs::VSOutputAttributes::VIEW_X);
-ASSERT_POS(tc2, Regs::VSOutputAttributes::TEXCOORD2_U);
+ASSERT_POS(pos, RasterizerRegs::VSOutputAttributes::POSITION_X);
+ASSERT_POS(quat, RasterizerRegs::VSOutputAttributes::QUATERNION_X);
+ASSERT_POS(color, RasterizerRegs::VSOutputAttributes::COLOR_R);
+ASSERT_POS(tc0, RasterizerRegs::VSOutputAttributes::TEXCOORD0_U);
+ASSERT_POS(tc1, RasterizerRegs::VSOutputAttributes::TEXCOORD1_U);
+ASSERT_POS(tc0_w, RasterizerRegs::VSOutputAttributes::TEXCOORD0_W);
+ASSERT_POS(view, RasterizerRegs::VSOutputAttributes::VIEW_X);
+ASSERT_POS(tc2, RasterizerRegs::VSOutputAttributes::TEXCOORD2_U);
#undef ASSERT_POS
static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size");
@@ -116,9 +116,9 @@ struct UnitState {
* @param config Shader configuration registers corresponding to the unit.
* @param input Attribute buffer to load into the input registers.
*/
- void LoadInput(const Regs::ShaderConfig& config, const AttributeBuffer& input);
+ void LoadInput(const ShaderRegs& config, const AttributeBuffer& input);
- void WriteOutput(const Regs::ShaderConfig& config, AttributeBuffer& output);
+ void WriteOutput(const ShaderRegs& config, AttributeBuffer& output);
};
struct 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 {
DebugData<true> InterpreterEngine::ProduceDebugInfo(const ShaderSetup& setup,
const AttributeBuffer& input,
- const Regs::ShaderConfig& config) const {
+ const ShaderRegs& config) const {
UnitState state;
DebugData<true> debug_data;
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:
* @return Debug information for this shader with regards to the given vertex
*/
DebugData<true> ProduceDebugInfo(const ShaderSetup& setup, const AttributeBuffer& input,
- const Regs::ShaderConfig& config) const;
+ const ShaderRegs& config) const;
};
} // 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 @@
#include "common/math_util.h"
#include "common/swap.h"
#include "common/vector_math.h"
-#include "video_core/pica.h"
+#include "video_core/regs_texturing.h"
#include "video_core/texture/etc1.h"
#include "video_core/texture/texture_decode.h"
#include "video_core/utils.h"
-using TextureFormat = Pica::Regs::TextureFormat;
+using TextureFormat = Pica::TexturingRegs::TextureFormat;
namespace Pica {
namespace Texture {
@@ -82,32 +82,32 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
using VideoCore::MortonInterleave;
switch (info.format) {
- case Regs::TextureFormat::RGBA8: {
+ case TextureFormat::RGBA8: {
auto res = Color::DecodeRGBA8(source + MortonInterleave(x, y) * 4);
return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
}
- case Regs::TextureFormat::RGB8: {
+ case TextureFormat::RGB8: {
auto res = Color::DecodeRGB8(source + MortonInterleave(x, y) * 3);
return {res.r(), res.g(), res.b(), 255};
}
- case Regs::TextureFormat::RGB5A1: {
+ case TextureFormat::RGB5A1: {
auto res = Color::DecodeRGB5A1(source + MortonInterleave(x, y) * 2);
return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
}
- case Regs::TextureFormat::RGB565: {
+ case TextureFormat::RGB565: {
auto res = Color::DecodeRGB565(source + MortonInterleave(x, y) * 2);
return {res.r(), res.g(), res.b(), 255};
}
- case Regs::TextureFormat::RGBA4: {
+ case TextureFormat::RGBA4: {
auto res = Color::DecodeRGBA4(source + MortonInterleave(x, y) * 2);
return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
}
- case Regs::TextureFormat::IA8: {
+ case TextureFormat::IA8: {
const u8* source_ptr = source + MortonInterleave(x, y) * 2;
if (disable_alpha) {
@@ -118,17 +118,17 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
}
}
- case Regs::TextureFormat::RG8: {
+ case TextureFormat::RG8: {
auto res = Color::DecodeRG8(source + MortonInterleave(x, y) * 2);
return {res.r(), res.g(), 0, 255};
}
- case Regs::TextureFormat::I8: {
+ case TextureFormat::I8: {
const u8* source_ptr = source + MortonInterleave(x, y);
return {*source_ptr, *source_ptr, *source_ptr, 255};
}
- case Regs::TextureFormat::A8: {
+ case TextureFormat::A8: {
const u8* source_ptr = source + MortonInterleave(x, y);
if (disable_alpha) {
@@ -138,7 +138,7 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
}
}
- case Regs::TextureFormat::IA4: {
+ case TextureFormat::IA4: {
const u8* source_ptr = source + MortonInterleave(x, y);
u8 i = Color::Convert4To8(((*source_ptr) & 0xF0) >> 4);
@@ -152,7 +152,7 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
}
}
- case Regs::TextureFormat::I4: {
+ case TextureFormat::I4: {
u32 morton_offset = MortonInterleave(x, y);
const u8* source_ptr = source + morton_offset / 2;
@@ -162,7 +162,7 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
return {i, i, i, 255};
}
- case Regs::TextureFormat::A4: {
+ case TextureFormat::A4: {
u32 morton_offset = MortonInterleave(x, y);
const u8* source_ptr = source + morton_offset / 2;
@@ -176,9 +176,9 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
}
}
- case Regs::TextureFormat::ETC1:
- case Regs::TextureFormat::ETC1A4: {
- bool has_alpha = (info.format == Regs::TextureFormat::ETC1A4);
+ case TextureFormat::ETC1:
+ case TextureFormat::ETC1A4: {
+ bool has_alpha = (info.format == TextureFormat::ETC1A4);
size_t subtile_size = has_alpha ? 16 : 8;
// 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
}
}
-TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config,
- const Regs::TextureFormat& format) {
+TextureInfo TextureInfo::FromPicaRegister(const TexturingRegs::TextureConfig& config,
+ const TexturingRegs::TextureFormat& format) {
TextureInfo info;
info.physical_address = config.GetPhysicalAddress();
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 @@
#include "common/common_types.h"
#include "common/vector_math.h"
-#include "video_core/pica.h"
+#include "video_core/regs_texturing.h"
namespace Pica {
namespace Texture {
/// Returns the byte size of a 8*8 tile of the specified texture format.
-size_t CalculateTileSize(Pica::Regs::TextureFormat format);
+size_t CalculateTileSize(TexturingRegs::TextureFormat format);
struct TextureInfo {
PAddr physical_address;
unsigned int width;
unsigned int height;
ptrdiff_t stride;
- Pica::Regs::TextureFormat format;
+ TexturingRegs::TextureFormat format;
- static TextureInfo FromPicaRegister(const Pica::Regs::TextureConfig& config,
- const Pica::Regs::TextureFormat& format);
+ static TextureInfo FromPicaRegister(const TexturingRegs::TextureConfig& config,
+ const TexturingRegs::TextureFormat& format);
/// Calculates stride from format and width, assuming that the entire texture is contiguous.
void SetDefaultStride() {
- stride = Pica::Texture::CalculateTileSize(format) * (width / 8);
+ stride = CalculateTileSize(format) * (width / 8);
}
};
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 @@
#include "common/vector_math.h"
#include "core/memory.h"
#include "video_core/debug_utils/debug_utils.h"
-#include "video_core/pica.h"
#include "video_core/pica_state.h"
#include "video_core/pica_types.h"
+#include "video_core/regs_pipeline.h"
#include "video_core/shader/shader.h"
#include "video_core/vertex_loader.h"
namespace Pica {
-void VertexLoader::Setup(const Pica::Regs& regs) {
+void VertexLoader::Setup(const PipelineRegs& regs) {
ASSERT_MSG(!is_setup, "VertexLoader is not intended to be setup more than once.");
const auto& attribute_config = regs.vertex_attributes;
@@ -85,15 +85,16 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex,
memory_accesses.AddAccess(
source_addr,
vertex_attribute_elements[i] *
- ((vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT)
+ ((vertex_attribute_formats[i] == PipelineRegs::VertexAttributeFormat::FLOAT)
? 4
- : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT)
+ : (vertex_attribute_formats[i] ==
+ PipelineRegs::VertexAttributeFormat::SHORT)
? 2
: 1));
}
switch (vertex_attribute_formats[i]) {
- case Regs::VertexAttributeFormat::BYTE: {
+ case PipelineRegs::VertexAttributeFormat::BYTE: {
const s8* srcdata =
reinterpret_cast<const s8*>(Memory::GetPhysicalPointer(source_addr));
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,
}
break;
}
- case Regs::VertexAttributeFormat::UBYTE: {
+ case PipelineRegs::VertexAttributeFormat::UBYTE: {
const u8* srcdata =
reinterpret_cast<const u8*>(Memory::GetPhysicalPointer(source_addr));
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,
}
break;
}
- case Regs::VertexAttributeFormat::SHORT: {
+ case PipelineRegs::VertexAttributeFormat::SHORT: {
const s16* srcdata =
reinterpret_cast<const s16*>(Memory::GetPhysicalPointer(source_addr));
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,
}
break;
}
- case Regs::VertexAttributeFormat::FLOAT: {
+ case PipelineRegs::VertexAttributeFormat::FLOAT: {
const float* srcdata =
reinterpret_cast<const float*>(Memory::GetPhysicalPointer(source_addr));
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 @@
#include <array>
#include "common/common_types.h"
-#include "video_core/pica.h"
+#include "video_core/regs_pipeline.h"
namespace Pica {
@@ -17,11 +17,11 @@ struct AttributeBuffer;
class VertexLoader {
public:
VertexLoader() = default;
- explicit VertexLoader(const Pica::Regs& regs) {
+ explicit VertexLoader(const PipelineRegs& regs) {
Setup(regs);
}
- void Setup(const Pica::Regs& regs);
+ void Setup(const PipelineRegs& regs);
void LoadVertex(u32 base_address, int index, int vertex, Shader::AttributeBuffer& input,
DebugUtils::MemoryAccessTracker& memory_accesses);
@@ -32,7 +32,7 @@ public:
private:
std::array<u32, 16> vertex_attribute_sources;
std::array<u32, 16> vertex_attribute_strides{};
- std::array<Regs::VertexAttributeFormat, 16> vertex_attribute_formats;
+ std::array<PipelineRegs::VertexAttributeFormat, 16> vertex_attribute_formats;
std::array<u32, 16> vertex_attribute_elements{};
std::array<bool, 16> vertex_attribute_is_default;
int num_total_attributes = 0;