forked from suyu/suyu
Merge pull request #2482 from yuriks/pica-refactor
Split up monolithic Regs struct
This commit is contained in:
commit
2889372e47
37 changed files with 2635 additions and 2427 deletions
|
@ -18,8 +18,8 @@
|
||||||
#include "citra_qt/util/util.h"
|
#include "citra_qt/util/util.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
#include "video_core/debug_utils/debug_utils.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
|
#include "video_core/regs.h"
|
||||||
#include "video_core/texture/texture_decode.h"
|
#include "video_core/texture/texture_decode.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -123,15 +123,16 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&
|
||||||
void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
|
void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
|
||||||
const unsigned int command_id =
|
const unsigned int command_id =
|
||||||
list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt();
|
list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt();
|
||||||
if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) ||
|
if (COMMAND_IN_RANGE(command_id, texturing.texture0) ||
|
||||||
COMMAND_IN_RANGE(command_id, texture2)) {
|
COMMAND_IN_RANGE(command_id, texturing.texture1) ||
|
||||||
|
COMMAND_IN_RANGE(command_id, texturing.texture2)) {
|
||||||
|
|
||||||
unsigned texture_index;
|
unsigned texture_index;
|
||||||
if (COMMAND_IN_RANGE(command_id, texture0)) {
|
if (COMMAND_IN_RANGE(command_id, texturing.texture0)) {
|
||||||
texture_index = 0;
|
texture_index = 0;
|
||||||
} else if (COMMAND_IN_RANGE(command_id, texture1)) {
|
} else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) {
|
||||||
texture_index = 1;
|
texture_index = 1;
|
||||||
} else if (COMMAND_IN_RANGE(command_id, texture2)) {
|
} else if (COMMAND_IN_RANGE(command_id, texturing.texture2)) {
|
||||||
texture_index = 2;
|
texture_index = 2;
|
||||||
} else {
|
} else {
|
||||||
UNREACHABLE_MSG("Unknown texture command");
|
UNREACHABLE_MSG("Unknown texture command");
|
||||||
|
@ -146,19 +147,20 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
|
||||||
|
|
||||||
const unsigned int command_id =
|
const unsigned int command_id =
|
||||||
list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt();
|
list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toUInt();
|
||||||
if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) ||
|
if (COMMAND_IN_RANGE(command_id, texturing.texture0) ||
|
||||||
COMMAND_IN_RANGE(command_id, texture2)) {
|
COMMAND_IN_RANGE(command_id, texturing.texture1) ||
|
||||||
|
COMMAND_IN_RANGE(command_id, texturing.texture2)) {
|
||||||
|
|
||||||
unsigned texture_index;
|
unsigned texture_index;
|
||||||
if (COMMAND_IN_RANGE(command_id, texture0)) {
|
if (COMMAND_IN_RANGE(command_id, texturing.texture0)) {
|
||||||
texture_index = 0;
|
texture_index = 0;
|
||||||
} else if (COMMAND_IN_RANGE(command_id, texture1)) {
|
} else if (COMMAND_IN_RANGE(command_id, texturing.texture1)) {
|
||||||
texture_index = 1;
|
texture_index = 1;
|
||||||
} else {
|
} else {
|
||||||
texture_index = 2;
|
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 config = texture.config;
|
||||||
const auto format = texture.format;
|
const auto format = texture.format;
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
#include "common/color.h"
|
#include "common/color.h"
|
||||||
#include "core/hw/gpu.h"
|
#include "core/hw/gpu.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
|
#include "video_core/regs.h"
|
||||||
#include "video_core/texture/texture_decode.h"
|
#include "video_core/texture/texture_decode.h"
|
||||||
#include "video_core/utils.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
|
// TODO: Store a reference to the registers in the debug context instead of accessing them
|
||||||
// directly...
|
// directly...
|
||||||
|
|
||||||
const auto& framebuffer = Pica::g_state.regs.framebuffer;
|
const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer;
|
||||||
|
|
||||||
surface_address = framebuffer.GetColorBufferPhysicalAddress();
|
surface_address = framebuffer.GetColorBufferPhysicalAddress();
|
||||||
surface_width = framebuffer.GetWidth();
|
surface_width = framebuffer.GetWidth();
|
||||||
surface_height = framebuffer.GetHeight();
|
surface_height = framebuffer.GetHeight();
|
||||||
|
|
||||||
switch (framebuffer.color_format) {
|
switch (framebuffer.color_format) {
|
||||||
case Pica::Regs::ColorFormat::RGBA8:
|
case Pica::FramebufferRegs::ColorFormat::RGBA8:
|
||||||
surface_format = Format::RGBA8;
|
surface_format = Format::RGBA8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Pica::Regs::ColorFormat::RGB8:
|
case Pica::FramebufferRegs::ColorFormat::RGB8:
|
||||||
surface_format = Format::RGB8;
|
surface_format = Format::RGB8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Pica::Regs::ColorFormat::RGB5A1:
|
case Pica::FramebufferRegs::ColorFormat::RGB5A1:
|
||||||
surface_format = Format::RGB5A1;
|
surface_format = Format::RGB5A1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Pica::Regs::ColorFormat::RGB565:
|
case Pica::FramebufferRegs::ColorFormat::RGB565:
|
||||||
surface_format = Format::RGB565;
|
surface_format = Format::RGB565;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Pica::Regs::ColorFormat::RGBA4:
|
case Pica::FramebufferRegs::ColorFormat::RGBA4:
|
||||||
surface_format = Format::RGBA4;
|
surface_format = Format::RGBA4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -450,22 +450,22 @@ void GraphicsSurfaceWidget::OnUpdate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
case Source::DepthBuffer: {
|
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_address = framebuffer.GetDepthBufferPhysicalAddress();
|
||||||
surface_width = framebuffer.GetWidth();
|
surface_width = framebuffer.GetWidth();
|
||||||
surface_height = framebuffer.GetHeight();
|
surface_height = framebuffer.GetHeight();
|
||||||
|
|
||||||
switch (framebuffer.depth_format) {
|
switch (framebuffer.depth_format) {
|
||||||
case Pica::Regs::DepthFormat::D16:
|
case Pica::FramebufferRegs::DepthFormat::D16:
|
||||||
surface_format = Format::D16;
|
surface_format = Format::D16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Pica::Regs::DepthFormat::D24:
|
case Pica::FramebufferRegs::DepthFormat::D24:
|
||||||
surface_format = Format::D24;
|
surface_format = Format::D24;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Pica::Regs::DepthFormat::D24S8:
|
case Pica::FramebufferRegs::DepthFormat::D24S8:
|
||||||
surface_format = Format::D24X8;
|
surface_format = Format::D24X8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -478,14 +478,14 @@ void GraphicsSurfaceWidget::OnUpdate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
case Source::StencilBuffer: {
|
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_address = framebuffer.GetDepthBufferPhysicalAddress();
|
||||||
surface_width = framebuffer.GetWidth();
|
surface_width = framebuffer.GetWidth();
|
||||||
surface_height = framebuffer.GetHeight();
|
surface_height = framebuffer.GetHeight();
|
||||||
|
|
||||||
switch (framebuffer.depth_format) {
|
switch (framebuffer.depth_format) {
|
||||||
case Pica::Regs::DepthFormat::D24S8:
|
case Pica::FramebufferRegs::DepthFormat::D24S8:
|
||||||
surface_format = Format::X24S8;
|
surface_format = Format::X24S8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -512,7 +512,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
|
||||||
break;
|
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);
|
auto info = Pica::Texture::TextureInfo::FromPicaRegister(texture.config, texture.format);
|
||||||
|
|
||||||
surface_address = info.physical_address;
|
surface_address = info.physical_address;
|
||||||
|
@ -574,7 +574,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
|
||||||
info.physical_address = surface_address;
|
info.physical_address = surface_address;
|
||||||
info.width = surface_width;
|
info.width = surface_width;
|
||||||
info.height = surface_height;
|
info.height = surface_height;
|
||||||
info.format = static_cast<Pica::Regs::TextureFormat>(surface_format);
|
info.format = static_cast<Pica::TexturingRegs::TextureFormat>(surface_format);
|
||||||
info.SetDefaultStride();
|
info.SetDefaultStride();
|
||||||
|
|
||||||
for (unsigned int y = 0; y < surface_height; ++y) {
|
for (unsigned int y = 0; y < surface_height; ++y) {
|
||||||
|
@ -689,7 +689,8 @@ void GraphicsSurfaceWidget::SaveSurface() {
|
||||||
|
|
||||||
unsigned int GraphicsSurfaceWidget::NibblesPerPixel(GraphicsSurfaceWidget::Format format) {
|
unsigned int GraphicsSurfaceWidget::NibblesPerPixel(GraphicsSurfaceWidget::Format format) {
|
||||||
if (format <= Format::MaxTextureFormat) {
|
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) {
|
switch (format) {
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include "core/hw/lcd.h"
|
#include "core/hw/lcd.h"
|
||||||
#include "core/tracer/recorder.h"
|
#include "core/tracer/recorder.h"
|
||||||
#include "nihstro/float24.h"
|
#include "nihstro/float24.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
|
|
||||||
GraphicsTracingWidget::GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context,
|
GraphicsTracingWidget::GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context,
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include <QTreeView>
|
#include <QTreeView>
|
||||||
#include "citra_qt/debugger/graphics/graphics_vertex_shader.h"
|
#include "citra_qt/debugger/graphics/graphics_vertex_shader.h"
|
||||||
#include "citra_qt/util/util.h"
|
#include "citra_qt/util/util.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
#include "video_core/shader/debug_data.h"
|
#include "video_core/shader/debug_data.h"
|
||||||
#include "video_core/shader/shader.h"
|
#include "video_core/shader/shader.h"
|
||||||
|
@ -359,7 +358,7 @@ void GraphicsVertexShaderWidget::DumpShader() {
|
||||||
auto& config = Pica::g_state.regs.vs;
|
auto& config = Pica::g_state.regs.vs;
|
||||||
|
|
||||||
Pica::DebugUtils::DumpShader(filename.toStdString(), config, setup,
|
Pica::DebugUtils::DumpShader(filename.toStdString(), config, setup,
|
||||||
Pica::g_state.regs.vs_output_attributes);
|
Pica::g_state.regs.rasterizer.vs_output_attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(
|
GraphicsVertexShaderWidget::GraphicsVertexShaderWidget(
|
||||||
|
|
|
@ -5,6 +5,7 @@ set(SRCS
|
||||||
pica.cpp
|
pica.cpp
|
||||||
primitive_assembly.cpp
|
primitive_assembly.cpp
|
||||||
rasterizer.cpp
|
rasterizer.cpp
|
||||||
|
regs.cpp
|
||||||
renderer_base.cpp
|
renderer_base.cpp
|
||||||
renderer_opengl/gl_rasterizer.cpp
|
renderer_opengl/gl_rasterizer.cpp
|
||||||
renderer_opengl/gl_rasterizer_cache.cpp
|
renderer_opengl/gl_rasterizer_cache.cpp
|
||||||
|
@ -32,6 +33,13 @@ set(HEADERS
|
||||||
primitive_assembly.h
|
primitive_assembly.h
|
||||||
rasterizer.h
|
rasterizer.h
|
||||||
rasterizer_interface.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_base.h
|
||||||
renderer_opengl/gl_rasterizer.h
|
renderer_opengl/gl_rasterizer.h
|
||||||
renderer_opengl/gl_rasterizer_cache.h
|
renderer_opengl/gl_rasterizer_cache.h
|
||||||
|
|
|
@ -12,10 +12,10 @@
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "video_core/clipper.h"
|
#include "video_core/clipper.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
#include "video_core/pica_types.h"
|
#include "video_core/pica_types.h"
|
||||||
#include "video_core/rasterizer.h"
|
#include "video_core/rasterizer.h"
|
||||||
|
#include "video_core/regs.h"
|
||||||
#include "video_core/shader/shader.h"
|
#include "video_core/shader/shader.h"
|
||||||
|
|
||||||
using Pica::Rasterizer::Vertex;
|
using Pica::Rasterizer::Vertex;
|
||||||
|
@ -64,10 +64,10 @@ static void InitScreenCoordinates(Vertex& vtx) {
|
||||||
} viewport;
|
} viewport;
|
||||||
|
|
||||||
const auto& regs = g_state.regs;
|
const auto& regs = g_state.regs;
|
||||||
viewport.halfsize_x = float24::FromRaw(regs.viewport_size_x);
|
viewport.halfsize_x = float24::FromRaw(regs.rasterizer.viewport_size_x);
|
||||||
viewport.halfsize_y = float24::FromRaw(regs.viewport_size_y);
|
viewport.halfsize_y = float24::FromRaw(regs.rasterizer.viewport_size_y);
|
||||||
viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.viewport_corner.x));
|
viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.rasterizer.viewport_corner.x));
|
||||||
viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.viewport_corner.y));
|
viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.rasterizer.viewport_corner.y));
|
||||||
|
|
||||||
float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w;
|
float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w;
|
||||||
vtx.color *= inv_w;
|
vtx.color *= inv_w;
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
#include "core/tracer/recorder.h"
|
#include "core/tracer/recorder.h"
|
||||||
#include "video_core/command_processor.h"
|
#include "video_core/command_processor.h"
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
#include "video_core/debug_utils/debug_utils.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
#include "video_core/pica_types.h"
|
#include "video_core/pica_types.h"
|
||||||
#include "video_core/primitive_assembly.h"
|
#include "video_core/primitive_assembly.h"
|
||||||
#include "video_core/rasterizer_interface.h"
|
#include "video_core/rasterizer_interface.h"
|
||||||
|
#include "video_core/regs.h"
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
#include "video_core/shader/shader.h"
|
#include "video_core/shader/shader.h"
|
||||||
#include "video_core/vertex_loader.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);
|
Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PICA_REG_INDEX_WORKAROUND(triangle_topology, 0x25E):
|
case PICA_REG_INDEX(pipeline.triangle_topology):
|
||||||
g_state.primitive_assembler.Reconfigure(regs.triangle_topology);
|
g_state.primitive_assembler.Reconfigure(regs.pipeline.triangle_topology);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PICA_REG_INDEX_WORKAROUND(restart_primitive, 0x25F):
|
case PICA_REG_INDEX(pipeline.restart_primitive):
|
||||||
g_state.primitive_assembler.Reset();
|
g_state.primitive_assembler.Reset();
|
||||||
break;
|
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;
|
g_state.immediate.current_attribute = 0;
|
||||||
default_attr_counter = 0;
|
default_attr_counter = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Load default vertex input attributes
|
// Load default vertex input attributes
|
||||||
case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233):
|
case PICA_REG_INDEX_WORKAROUND(pipeline.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(pipeline.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[2], 0x235): {
|
||||||
// TODO: Does actual hardware indeed keep an intermediate buffer or does
|
// TODO: Does actual hardware indeed keep an intermediate buffer or does
|
||||||
// it directly write the values?
|
// it directly write the values?
|
||||||
default_attr_write_buffer[default_attr_counter++] = value;
|
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) {
|
if (default_attr_counter >= 3) {
|
||||||
default_attr_counter = 0;
|
default_attr_counter = 0;
|
||||||
|
|
||||||
auto& setup = regs.vs_default_attributes_setup;
|
auto& setup = regs.pipeline.vs_default_attributes_setup;
|
||||||
|
|
||||||
if (setup.index >= 16) {
|
if (setup.index >= 16) {
|
||||||
LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index);
|
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;
|
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;
|
immediate_attribute_id += 1;
|
||||||
} else {
|
} else {
|
||||||
MICROPROFILE_SCOPE(GPU_Drawing);
|
MICROPROFILE_SCOPE(GPU_Drawing);
|
||||||
|
@ -165,15 +165,16 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
|
||||||
};
|
};
|
||||||
|
|
||||||
g_state.primitive_assembler.SubmitVertex(
|
g_state.primitive_assembler.SubmitVertex(
|
||||||
Shader::OutputVertex::FromAttributeBuffer(regs, output), AddTriangle);
|
Shader::OutputVertex::FromAttributeBuffer(regs.rasterizer, output),
|
||||||
|
AddTriangle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PICA_REG_INDEX(gpu_mode):
|
case PICA_REG_INDEX(pipeline.gpu_mode):
|
||||||
if (regs.gpu_mode == Regs::GPUMode::Configuring) {
|
if (regs.pipeline.gpu_mode == PipelineRegs::GPUMode::Configuring) {
|
||||||
MICROPROFILE_SCOPE(GPU_Drawing);
|
MICROPROFILE_SCOPE(GPU_Drawing);
|
||||||
|
|
||||||
// Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring
|
// 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;
|
break;
|
||||||
|
|
||||||
case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c):
|
case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[0], 0x23c):
|
||||||
case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): {
|
case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[1], 0x23d): {
|
||||||
unsigned index = static_cast<unsigned>(id - PICA_REG_INDEX(command_buffer.trigger[0]));
|
unsigned index =
|
||||||
u32* head_ptr =
|
static_cast<unsigned>(id - PICA_REG_INDEX(pipeline.command_buffer.trigger[0]));
|
||||||
(u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index));
|
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.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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It seems like these trigger vertex rendering
|
// It seems like these trigger vertex rendering
|
||||||
case PICA_REG_INDEX(trigger_draw):
|
case PICA_REG_INDEX(pipeline.trigger_draw):
|
||||||
case PICA_REG_INDEX(trigger_draw_indexed): {
|
case PICA_REG_INDEX(pipeline.trigger_draw_indexed): {
|
||||||
MICROPROFILE_SCOPE(GPU_Drawing);
|
MICROPROFILE_SCOPE(GPU_Drawing);
|
||||||
|
|
||||||
#if PICA_LOG_TEV
|
#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
|
// Processes information about internal vertex attributes to figure out how a vertex is
|
||||||
// loaded.
|
// loaded.
|
||||||
// Later, these can be compiled and cached.
|
// Later, these can be compiled and cached.
|
||||||
const u32 base_address = regs.vertex_attributes.GetPhysicalBaseAddress();
|
const u32 base_address = regs.pipeline.vertex_attributes.GetPhysicalBaseAddress();
|
||||||
VertexLoader loader(regs);
|
VertexLoader loader(regs.pipeline);
|
||||||
|
|
||||||
// Load vertices
|
// 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 u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset);
|
||||||
const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8);
|
const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8);
|
||||||
bool index_u16 = index_info.format != 0;
|
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) {
|
if (g_debug_context && g_debug_context->recorder) {
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
const auto texture = regs.GetTextures()[i];
|
const auto texture = regs.texturing.GetTextures()[i];
|
||||||
if (!texture.enabled)
|
if (!texture.enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
|
u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
|
||||||
g_debug_context->recorder->MemoryAccessed(
|
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.width / 2 * texture.config.height,
|
||||||
texture.config.GetPhysicalAddress());
|
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);
|
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
|
// Indexed rendering doesn't use the start offset
|
||||||
unsigned int vertex =
|
unsigned int vertex =
|
||||||
is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index])
|
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
|
// -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.
|
// 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);
|
shader_unit.WriteOutput(regs.vs, output);
|
||||||
|
|
||||||
// Retrieve vertex from register data
|
// Retrieve vertex from register data
|
||||||
output_vertex = Shader::OutputVertex::FromAttributeBuffer(regs, output);
|
output_vertex = Shader::OutputVertex::FromAttributeBuffer(regs.rasterizer, output);
|
||||||
|
|
||||||
if (is_indexed) {
|
if (is_indexed) {
|
||||||
vertex_cache[vertex_cache_pos] = output_vertex;
|
vertex_cache[vertex_cache_pos] = output_vertex;
|
||||||
|
@ -437,16 +439,16 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[0], 0xe8):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[0], 0xe8):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[1], 0xe9):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[1], 0xe9):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[2], 0xea):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[2], 0xea):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[3], 0xeb):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[3], 0xeb):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[4], 0xec):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[4], 0xec):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[5], 0xed):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[5], 0xed):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[6], 0xee):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[6], 0xee):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[7], 0xef): {
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[7], 0xef): {
|
||||||
g_state.fog.lut[regs.fog_lut_offset % 128].raw = value;
|
g_state.fog.lut[regs.texturing.fog_lut_offset % 128].raw = value;
|
||||||
regs.fog_lut_offset.Assign(regs.fog_lut_offset + 1);
|
regs.texturing.fog_lut_offset.Assign(regs.texturing.fog_lut_offset + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,10 @@
|
||||||
#include "common/math_util.h"
|
#include "common/math_util.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
#include "video_core/debug_utils/debug_utils.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
#include "video_core/pica_types.h"
|
#include "video_core/pica_types.h"
|
||||||
#include "video_core/rasterizer_interface.h"
|
#include "video_core/rasterizer_interface.h"
|
||||||
|
#include "video_core/regs.h"
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
#include "video_core/shader/shader.h"
|
#include "video_core/shader/shader.h"
|
||||||
#include "video_core/texture/texture_decode.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 {
|
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 Shader::ShaderSetup& setup,
|
||||||
const Regs::VSOutputAttributes* output_attributes) {
|
const RasterizerRegs::VSOutputAttributes* output_attributes) {
|
||||||
struct StuffToWrite {
|
struct StuffToWrite {
|
||||||
const u8* pointer;
|
const u8* pointer;
|
||||||
u32 size;
|
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.
|
// This is put into a try-catch block to make sure we notice unknown configurations.
|
||||||
std::vector<OutputRegisterInfo> output_info_table;
|
std::vector<OutputRegisterInfo> output_info_table;
|
||||||
for (unsigned i = 0; i < 7; ++i) {
|
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!
|
// 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.
|
// 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
|
#endif
|
||||||
|
|
||||||
void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
|
void DumpTexture(const TexturingRegs::TextureConfig& texture_config, u8* data) {
|
||||||
#ifndef HAVE_PNG
|
#ifndef HAVE_PNG
|
||||||
return;
|
return;
|
||||||
#else
|
#else
|
||||||
|
@ -396,7 +396,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
|
||||||
info.width = texture_config.width;
|
info.width = texture_config.width;
|
||||||
info.height = texture_config.height;
|
info.height = texture_config.height;
|
||||||
info.stride = row_stride;
|
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);
|
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] = texture_color.r();
|
||||||
buf[3 * x + y * row_stride + 1] = texture_color.g();
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetTevStageConfigSourceString(const Pica::Regs::TevStageConfig::Source& source) {
|
static std::string GetTevStageConfigSourceString(
|
||||||
using Source = Pica::Regs::TevStageConfig::Source;
|
const TexturingRegs::TevStageConfig::Source& source) {
|
||||||
|
|
||||||
|
using Source = TexturingRegs::TevStageConfig::Source;
|
||||||
static const std::map<Source, std::string> source_map = {
|
static const std::map<Source, std::string> source_map = {
|
||||||
{Source::PrimaryColor, "PrimaryColor"},
|
{Source::PrimaryColor, "PrimaryColor"},
|
||||||
{Source::PrimaryFragmentColor, "PrimaryFragmentColor"},
|
{Source::PrimaryFragmentColor, "PrimaryFragmentColor"},
|
||||||
|
@ -457,9 +459,10 @@ static std::string GetTevStageConfigSourceString(const Pica::Regs::TevStageConfi
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetTevStageConfigColorSourceString(
|
static std::string GetTevStageConfigColorSourceString(
|
||||||
const Pica::Regs::TevStageConfig::Source& source,
|
const TexturingRegs::TevStageConfig::Source& source,
|
||||||
const Pica::Regs::TevStageConfig::ColorModifier modifier) {
|
const TexturingRegs::TevStageConfig::ColorModifier modifier) {
|
||||||
using ColorModifier = Pica::Regs::TevStageConfig::ColorModifier;
|
|
||||||
|
using ColorModifier = TexturingRegs::TevStageConfig::ColorModifier;
|
||||||
static const std::map<ColorModifier, std::string> color_modifier_map = {
|
static const std::map<ColorModifier, std::string> color_modifier_map = {
|
||||||
{ColorModifier::SourceColor, "%source.rgb"},
|
{ColorModifier::SourceColor, "%source.rgb"},
|
||||||
{ColorModifier::OneMinusSourceColor, "(1.0 - %source.rgb)"},
|
{ColorModifier::OneMinusSourceColor, "(1.0 - %source.rgb)"},
|
||||||
|
@ -483,9 +486,10 @@ static std::string GetTevStageConfigColorSourceString(
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetTevStageConfigAlphaSourceString(
|
static std::string GetTevStageConfigAlphaSourceString(
|
||||||
const Pica::Regs::TevStageConfig::Source& source,
|
const TexturingRegs::TevStageConfig::Source& source,
|
||||||
const Pica::Regs::TevStageConfig::AlphaModifier modifier) {
|
const TexturingRegs::TevStageConfig::AlphaModifier modifier) {
|
||||||
using AlphaModifier = Pica::Regs::TevStageConfig::AlphaModifier;
|
|
||||||
|
using AlphaModifier = TexturingRegs::TevStageConfig::AlphaModifier;
|
||||||
static const std::map<AlphaModifier, std::string> alpha_modifier_map = {
|
static const std::map<AlphaModifier, std::string> alpha_modifier_map = {
|
||||||
{AlphaModifier::SourceAlpha, "%source.a"},
|
{AlphaModifier::SourceAlpha, "%source.a"},
|
||||||
{AlphaModifier::OneMinusSourceAlpha, "(1.0 - %source.a)"},
|
{AlphaModifier::OneMinusSourceAlpha, "(1.0 - %source.a)"},
|
||||||
|
@ -507,8 +511,9 @@ static std::string GetTevStageConfigAlphaSourceString(
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetTevStageConfigOperationString(
|
static std::string GetTevStageConfigOperationString(
|
||||||
const Pica::Regs::TevStageConfig::Operation& operation) {
|
const TexturingRegs::TevStageConfig::Operation& operation) {
|
||||||
using Operation = Pica::Regs::TevStageConfig::Operation;
|
|
||||||
|
using Operation = TexturingRegs::TevStageConfig::Operation;
|
||||||
static const std::map<Operation, std::string> combiner_map = {
|
static const std::map<Operation, std::string> combiner_map = {
|
||||||
{Operation::Replace, "%source1"},
|
{Operation::Replace, "%source1"},
|
||||||
{Operation::Modulate, "(%source1 * %source2)"},
|
{Operation::Modulate, "(%source1 * %source2)"},
|
||||||
|
@ -528,7 +533,7 @@ static std::string GetTevStageConfigOperationString(
|
||||||
return op_it->second;
|
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);
|
auto op_str = GetTevStageConfigOperationString(tev_stage.color_op);
|
||||||
op_str = ReplacePattern(
|
op_str = ReplacePattern(
|
||||||
op_str, "%source1",
|
op_str, "%source1",
|
||||||
|
@ -541,7 +546,7 @@ std::string GetTevStageConfigColorCombinerString(const Pica::Regs::TevStageConfi
|
||||||
GetTevStageConfigColorSourceString(tev_stage.color_source3, tev_stage.color_modifier3));
|
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);
|
auto op_str = GetTevStageConfigOperationString(tev_stage.alpha_op);
|
||||||
op_str = ReplacePattern(
|
op_str = ReplacePattern(
|
||||||
op_str, "%source1",
|
op_str, "%source1",
|
||||||
|
@ -554,7 +559,7 @@ std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfi
|
||||||
GetTevStageConfigAlphaSourceString(tev_stage.alpha_source3, tev_stage.alpha_modifier3));
|
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";
|
std::string stage_info = "Tev setup:\n";
|
||||||
for (size_t index = 0; index < stages.size(); ++index) {
|
for (size_t index = 0; index < stages.size(); ++index) {
|
||||||
const auto& tev_stage = stages[index];
|
const auto& tev_stage = stages[index];
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "video_core/pica.h"
|
#include "video_core/regs.h"
|
||||||
|
|
||||||
namespace CiTrace {
|
namespace CiTrace {
|
||||||
class Recorder;
|
class Recorder;
|
||||||
|
@ -182,9 +182,9 @@ namespace DebugUtils {
|
||||||
#define PICA_DUMP_TEXTURES 0
|
#define PICA_DUMP_TEXTURES 0
|
||||||
#define PICA_LOG_TEV 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 Shader::ShaderSetup& setup,
|
||||||
const Regs::VSOutputAttributes* output_attributes);
|
const RasterizerRegs::VSOutputAttributes* output_attributes);
|
||||||
|
|
||||||
// Utility class to log Pica commands.
|
// Utility class to log Pica commands.
|
||||||
struct PicaTrace {
|
struct PicaTrace {
|
||||||
|
@ -205,13 +205,13 @@ inline bool IsPicaTracing() {
|
||||||
void OnPicaRegWrite(PicaTrace::Write write);
|
void OnPicaRegWrite(PicaTrace::Write write);
|
||||||
std::unique_ptr<PicaTrace> FinishPicaTracing();
|
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 GetTevStageConfigColorCombinerString(const TexturingRegs::TevStageConfig& tev_stage);
|
||||||
std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfig& tev_stage);
|
std::string GetTevStageConfigAlphaCombinerString(const TexturingRegs::TevStageConfig& tev_stage);
|
||||||
|
|
||||||
/// Dumps the Tev stage config to log at trace level
|
/// 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.
|
* Used in the vertex loader to merge access records. TODO: Investigate if actually useful.
|
||||||
|
|
|
@ -3,497 +3,14 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iterator>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <utility>
|
|
||||||
#include "video_core/pica.h"
|
#include "video_core/pica.h"
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
#include "video_core/primitive_assembly.h"
|
#include "video_core/regs.h"
|
||||||
#include "video_core/shader/shader.h"
|
|
||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
|
|
||||||
State g_state;
|
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() {
|
void Init() {
|
||||||
g_state.Reset();
|
g_state.Reset();
|
||||||
}
|
}
|
||||||
|
@ -513,6 +30,6 @@ void State::Reset() {
|
||||||
Zero(gs);
|
Zero(gs);
|
||||||
Zero(cmd_list);
|
Zero(cmd_list);
|
||||||
Zero(immediate);
|
Zero(immediate);
|
||||||
primitive_assembler.Reconfigure(Regs::TriangleTopology::List);
|
primitive_assembler.Reconfigure(PipelineRegs::TriangleTopology::List);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,8 +7,8 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/primitive_assembly.h"
|
#include "video_core/primitive_assembly.h"
|
||||||
|
#include "video_core/regs.h"
|
||||||
#include "video_core/shader/shader.h"
|
#include "video_core/shader/shader.h"
|
||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/primitive_assembly.h"
|
#include "video_core/primitive_assembly.h"
|
||||||
|
#include "video_core/regs_pipeline.h"
|
||||||
#include "video_core/shader/shader.h"
|
#include "video_core/shader/shader.h"
|
||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
|
|
||||||
template <typename VertexType>
|
template <typename VertexType>
|
||||||
PrimitiveAssembler<VertexType>::PrimitiveAssembler(Regs::TriangleTopology topology)
|
PrimitiveAssembler<VertexType>::PrimitiveAssembler(PipelineRegs::TriangleTopology topology)
|
||||||
: topology(topology), buffer_index(0) {}
|
: topology(topology), buffer_index(0) {}
|
||||||
|
|
||||||
template <typename VertexType>
|
template <typename VertexType>
|
||||||
|
@ -18,8 +18,8 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx,
|
||||||
TriangleHandler triangle_handler) {
|
TriangleHandler triangle_handler) {
|
||||||
switch (topology) {
|
switch (topology) {
|
||||||
// TODO: Figure out what's different with TriangleTopology::Shader.
|
// TODO: Figure out what's different with TriangleTopology::Shader.
|
||||||
case Regs::TriangleTopology::List:
|
case PipelineRegs::TriangleTopology::List:
|
||||||
case Regs::TriangleTopology::Shader:
|
case PipelineRegs::TriangleTopology::Shader:
|
||||||
if (buffer_index < 2) {
|
if (buffer_index < 2) {
|
||||||
buffer[buffer_index++] = vtx;
|
buffer[buffer_index++] = vtx;
|
||||||
} else {
|
} else {
|
||||||
|
@ -29,8 +29,8 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::TriangleTopology::Strip:
|
case PipelineRegs::TriangleTopology::Strip:
|
||||||
case Regs::TriangleTopology::Fan:
|
case PipelineRegs::TriangleTopology::Fan:
|
||||||
if (strip_ready)
|
if (strip_ready)
|
||||||
triangle_handler(buffer[0], buffer[1], vtx);
|
triangle_handler(buffer[0], buffer[1], vtx);
|
||||||
|
|
||||||
|
@ -38,9 +38,9 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(const VertexType& vtx,
|
||||||
|
|
||||||
strip_ready |= (buffer_index == 1);
|
strip_ready |= (buffer_index == 1);
|
||||||
|
|
||||||
if (topology == Regs::TriangleTopology::Strip)
|
if (topology == PipelineRegs::TriangleTopology::Strip)
|
||||||
buffer_index = !buffer_index;
|
buffer_index = !buffer_index;
|
||||||
else if (topology == Regs::TriangleTopology::Fan)
|
else if (topology == PipelineRegs::TriangleTopology::Fan)
|
||||||
buffer_index = 1;
|
buffer_index = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ void PrimitiveAssembler<VertexType>::Reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename VertexType>
|
template <typename VertexType>
|
||||||
void PrimitiveAssembler<VertexType>::Reconfigure(Regs::TriangleTopology topology) {
|
void PrimitiveAssembler<VertexType>::Reconfigure(PipelineRegs::TriangleTopology topology) {
|
||||||
Reset();
|
Reset();
|
||||||
this->topology = topology;
|
this->topology = topology;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include "video_core/pica.h"
|
#include "video_core/regs_pipeline.h"
|
||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
|
|
||||||
|
@ -18,7 +18,8 @@ struct PrimitiveAssembler {
|
||||||
using TriangleHandler =
|
using TriangleHandler =
|
||||||
std::function<void(const VertexType& v0, const VertexType& v1, const VertexType& v2)>;
|
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
|
* 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.
|
* Reconfigures the PrimitiveAssembler to use a different triangle topology.
|
||||||
*/
|
*/
|
||||||
void Reconfigure(Regs::TriangleTopology topology);
|
void Reconfigure(PipelineRegs::TriangleTopology topology);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Regs::TriangleTopology topology;
|
PipelineRegs::TriangleTopology topology;
|
||||||
|
|
||||||
int buffer_index;
|
int buffer_index;
|
||||||
VertexType buffer[2];
|
VertexType buffer[2];
|
||||||
|
|
|
@ -16,10 +16,10 @@
|
||||||
#include "core/hw/gpu.h"
|
#include "core/hw/gpu.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
#include "video_core/debug_utils/debug_utils.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
#include "video_core/pica_types.h"
|
#include "video_core/pica_types.h"
|
||||||
#include "video_core/rasterizer.h"
|
#include "video_core/rasterizer.h"
|
||||||
|
#include "video_core/regs.h"
|
||||||
#include "video_core/shader/shader.h"
|
#include "video_core/shader/shader.h"
|
||||||
#include "video_core/texture/texture_decode.h"
|
#include "video_core/texture/texture_decode.h"
|
||||||
#include "video_core/utils.h"
|
#include "video_core/utils.h"
|
||||||
|
@ -29,7 +29,7 @@ namespace Pica {
|
||||||
namespace Rasterizer {
|
namespace Rasterizer {
|
||||||
|
|
||||||
static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
|
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();
|
const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
|
||||||
|
|
||||||
// Similarly to textures, the render framebuffer is laid out from bottom to top, too.
|
// 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;
|
u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset;
|
||||||
|
|
||||||
switch (framebuffer.color_format) {
|
switch (framebuffer.color_format) {
|
||||||
case Regs::ColorFormat::RGBA8:
|
case FramebufferRegs::ColorFormat::RGBA8:
|
||||||
Color::EncodeRGBA8(color, dst_pixel);
|
Color::EncodeRGBA8(color, dst_pixel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::ColorFormat::RGB8:
|
case FramebufferRegs::ColorFormat::RGB8:
|
||||||
Color::EncodeRGB8(color, dst_pixel);
|
Color::EncodeRGB8(color, dst_pixel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::ColorFormat::RGB5A1:
|
case FramebufferRegs::ColorFormat::RGB5A1:
|
||||||
Color::EncodeRGB5A1(color, dst_pixel);
|
Color::EncodeRGB5A1(color, dst_pixel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::ColorFormat::RGB565:
|
case FramebufferRegs::ColorFormat::RGB565:
|
||||||
Color::EncodeRGB565(color, dst_pixel);
|
Color::EncodeRGB565(color, dst_pixel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::ColorFormat::RGBA4:
|
case FramebufferRegs::ColorFormat::RGBA4:
|
||||||
Color::EncodeRGBA4(color, dst_pixel);
|
Color::EncodeRGBA4(color, dst_pixel);
|
||||||
break;
|
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) {
|
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();
|
const PAddr addr = framebuffer.GetColorBufferPhysicalAddress();
|
||||||
|
|
||||||
y = framebuffer.height - y;
|
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;
|
u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset;
|
||||||
|
|
||||||
switch (framebuffer.color_format) {
|
switch (framebuffer.color_format) {
|
||||||
case Regs::ColorFormat::RGBA8:
|
case FramebufferRegs::ColorFormat::RGBA8:
|
||||||
return Color::DecodeRGBA8(src_pixel);
|
return Color::DecodeRGBA8(src_pixel);
|
||||||
|
|
||||||
case Regs::ColorFormat::RGB8:
|
case FramebufferRegs::ColorFormat::RGB8:
|
||||||
return Color::DecodeRGB8(src_pixel);
|
return Color::DecodeRGB8(src_pixel);
|
||||||
|
|
||||||
case Regs::ColorFormat::RGB5A1:
|
case FramebufferRegs::ColorFormat::RGB5A1:
|
||||||
return Color::DecodeRGB5A1(src_pixel);
|
return Color::DecodeRGB5A1(src_pixel);
|
||||||
|
|
||||||
case Regs::ColorFormat::RGB565:
|
case FramebufferRegs::ColorFormat::RGB565:
|
||||||
return Color::DecodeRGB565(src_pixel);
|
return Color::DecodeRGB565(src_pixel);
|
||||||
|
|
||||||
case Regs::ColorFormat::RGBA4:
|
case FramebufferRegs::ColorFormat::RGBA4:
|
||||||
return Color::DecodeRGBA4(src_pixel);
|
return Color::DecodeRGBA4(src_pixel);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -110,25 +110,25 @@ static const Math::Vec4<u8> GetPixel(int x, int y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 GetDepth(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();
|
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
|
||||||
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
|
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
|
||||||
|
|
||||||
y = framebuffer.height - y;
|
y = framebuffer.height - y;
|
||||||
|
|
||||||
const u32 coarse_y = y & ~7;
|
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 stride = framebuffer.width * bytes_per_pixel;
|
||||||
|
|
||||||
u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
|
u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
|
||||||
u8* src_pixel = depth_buffer + src_offset;
|
u8* src_pixel = depth_buffer + src_offset;
|
||||||
|
|
||||||
switch (framebuffer.depth_format) {
|
switch (framebuffer.depth_format) {
|
||||||
case Regs::DepthFormat::D16:
|
case FramebufferRegs::DepthFormat::D16:
|
||||||
return Color::DecodeD16(src_pixel);
|
return Color::DecodeD16(src_pixel);
|
||||||
case Regs::DepthFormat::D24:
|
case FramebufferRegs::DepthFormat::D24:
|
||||||
return Color::DecodeD24(src_pixel);
|
return Color::DecodeD24(src_pixel);
|
||||||
case Regs::DepthFormat::D24S8:
|
case FramebufferRegs::DepthFormat::D24S8:
|
||||||
return Color::DecodeD24S8(src_pixel).x;
|
return Color::DecodeD24S8(src_pixel).x;
|
||||||
default:
|
default:
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
|
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) {
|
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();
|
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
|
||||||
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
|
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
|
||||||
|
|
||||||
y = framebuffer.height - y;
|
y = framebuffer.height - y;
|
||||||
|
|
||||||
const u32 coarse_y = y & ~7;
|
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 stride = framebuffer.width * bytes_per_pixel;
|
||||||
|
|
||||||
u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
|
u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
|
||||||
u8* src_pixel = depth_buffer + src_offset;
|
u8* src_pixel = depth_buffer + src_offset;
|
||||||
|
|
||||||
switch (framebuffer.depth_format) {
|
switch (framebuffer.depth_format) {
|
||||||
case Regs::DepthFormat::D24S8:
|
case FramebufferRegs::DepthFormat::D24S8:
|
||||||
return Color::DecodeD24S8(src_pixel).y;
|
return Color::DecodeD24S8(src_pixel).y;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -165,29 +165,29 @@ static u8 GetStencil(int x, int y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetDepth(int x, int y, u32 value) {
|
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();
|
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
|
||||||
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
|
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
|
||||||
|
|
||||||
y = framebuffer.height - y;
|
y = framebuffer.height - y;
|
||||||
|
|
||||||
const u32 coarse_y = y & ~7;
|
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 stride = framebuffer.width * bytes_per_pixel;
|
||||||
|
|
||||||
u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
|
u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
|
||||||
u8* dst_pixel = depth_buffer + dst_offset;
|
u8* dst_pixel = depth_buffer + dst_offset;
|
||||||
|
|
||||||
switch (framebuffer.depth_format) {
|
switch (framebuffer.depth_format) {
|
||||||
case Regs::DepthFormat::D16:
|
case FramebufferRegs::DepthFormat::D16:
|
||||||
Color::EncodeD16(value, dst_pixel);
|
Color::EncodeD16(value, dst_pixel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::DepthFormat::D24:
|
case FramebufferRegs::DepthFormat::D24:
|
||||||
Color::EncodeD24(value, dst_pixel);
|
Color::EncodeD24(value, dst_pixel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::DepthFormat::D24S8:
|
case FramebufferRegs::DepthFormat::D24S8:
|
||||||
Color::EncodeD24X8(value, dst_pixel);
|
Color::EncodeD24X8(value, dst_pixel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -199,26 +199,26 @@ static void SetDepth(int x, int y, u32 value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetStencil(int x, int y, u8 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();
|
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
|
||||||
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
|
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
|
||||||
|
|
||||||
y = framebuffer.height - y;
|
y = framebuffer.height - y;
|
||||||
|
|
||||||
const u32 coarse_y = y & ~7;
|
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 stride = framebuffer.width * bytes_per_pixel;
|
||||||
|
|
||||||
u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
|
u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
|
||||||
u8* dst_pixel = depth_buffer + dst_offset;
|
u8* dst_pixel = depth_buffer + dst_offset;
|
||||||
|
|
||||||
switch (framebuffer.depth_format) {
|
switch (framebuffer.depth_format) {
|
||||||
case Pica::Regs::DepthFormat::D16:
|
case Pica::FramebufferRegs::DepthFormat::D16:
|
||||||
case Pica::Regs::DepthFormat::D24:
|
case Pica::FramebufferRegs::DepthFormat::D24:
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Pica::Regs::DepthFormat::D24S8:
|
case Pica::FramebufferRegs::DepthFormat::D24S8:
|
||||||
Color::EncodeX24S8(value, dst_pixel);
|
Color::EncodeX24S8(value, dst_pixel);
|
||||||
break;
|
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) {
|
switch (action) {
|
||||||
case Regs::StencilAction::Keep:
|
case FramebufferRegs::StencilAction::Keep:
|
||||||
return old_stencil;
|
return old_stencil;
|
||||||
|
|
||||||
case Regs::StencilAction::Zero:
|
case FramebufferRegs::StencilAction::Zero:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case Regs::StencilAction::Replace:
|
case FramebufferRegs::StencilAction::Replace:
|
||||||
return ref;
|
return ref;
|
||||||
|
|
||||||
case Regs::StencilAction::Increment:
|
case FramebufferRegs::StencilAction::Increment:
|
||||||
// Saturated increment
|
// Saturated increment
|
||||||
return std::min<u8>(old_stencil, 254) + 1;
|
return std::min<u8>(old_stencil, 254) + 1;
|
||||||
|
|
||||||
case Regs::StencilAction::Decrement:
|
case FramebufferRegs::StencilAction::Decrement:
|
||||||
// Saturated decrement
|
// Saturated decrement
|
||||||
return std::max<u8>(old_stencil, 1) - 1;
|
return std::max<u8>(old_stencil, 1) - 1;
|
||||||
|
|
||||||
case Regs::StencilAction::Invert:
|
case FramebufferRegs::StencilAction::Invert:
|
||||||
return ~old_stencil;
|
return ~old_stencil;
|
||||||
|
|
||||||
case Regs::StencilAction::IncrementWrap:
|
case FramebufferRegs::StencilAction::IncrementWrap:
|
||||||
return old_stencil + 1;
|
return old_stencil + 1;
|
||||||
|
|
||||||
case Regs::StencilAction::DecrementWrap:
|
case FramebufferRegs::StencilAction::DecrementWrap:
|
||||||
return old_stencil - 1;
|
return old_stencil - 1;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -327,14 +327,14 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
||||||
ScreenToRasterizerCoordinates(v1.screenpos),
|
ScreenToRasterizerCoordinates(v1.screenpos),
|
||||||
ScreenToRasterizerCoordinates(v2.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
|
// 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) {
|
if (!reversed && SignedArea(vtxpos[0].xy(), vtxpos[1].xy(), vtxpos[2].xy()) <= 0) {
|
||||||
ProcessTriangleInternal(v0, v2, v1, true);
|
ProcessTriangleInternal(v0, v2, v1, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} 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.
|
// Reverse vertex order and use the CCW code path.
|
||||||
ProcessTriangleInternal(v0, v2, v1, true);
|
ProcessTriangleInternal(v0, v2, v1, true);
|
||||||
return;
|
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});
|
u16 max_y = std::max({vtxpos[0].y, vtxpos[1].y, vtxpos[2].y});
|
||||||
|
|
||||||
// Convert the scissor box coordinates to 12.4 fixed point
|
// Convert the scissor box coordinates to 12.4 fixed point
|
||||||
u16 scissor_x1 = (u16)(regs.scissor_test.x1 << 4);
|
u16 scissor_x1 = (u16)(regs.rasterizer.scissor_test.x1 << 4);
|
||||||
u16 scissor_y1 = (u16)(regs.scissor_test.y1 << 4);
|
u16 scissor_y1 = (u16)(regs.rasterizer.scissor_test.y1 << 4);
|
||||||
// x2,y2 have +1 added to cover the entire sub-pixel area
|
// x2,y2 have +1 added to cover the entire sub-pixel area
|
||||||
u16 scissor_x2 = (u16)((regs.scissor_test.x2 + 1) << 4);
|
u16 scissor_x2 = (u16)((regs.rasterizer.scissor_test.x2 + 1) << 4);
|
||||||
u16 scissor_y2 = (u16)((regs.scissor_test.y2 + 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
|
// Calculate the new bounds
|
||||||
min_x = std::max(min_x, scissor_x1);
|
min_x = std::max(min_x, scissor_x1);
|
||||||
min_y = std::max(min_y, scissor_y1);
|
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 w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w);
|
||||||
|
|
||||||
auto textures = regs.GetTextures();
|
auto textures = regs.texturing.GetTextures();
|
||||||
auto tev_stages = regs.GetTevStages();
|
auto tev_stages = regs.texturing.GetTevStages();
|
||||||
|
|
||||||
bool stencil_action_enable = g_state.regs.output_merger.stencil_test.enable &&
|
bool stencil_action_enable =
|
||||||
g_state.regs.framebuffer.depth_format == Regs::DepthFormat::D24S8;
|
g_state.regs.framebuffer.output_merger.stencil_test.enable &&
|
||||||
const auto stencil_test = g_state.regs.output_merger.stencil_test;
|
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.
|
// Enter rasterization loop, starting at the center of the topleft bounding box corner.
|
||||||
// TODO: Not sure if looping through x first might be faster
|
// 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
|
// Do not process the pixel if it's inside the scissor box and the scissor mode is set
|
||||||
// to Exclude
|
// 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)
|
if (x >= scissor_x1 && x < scissor_x2 && y >= scissor_y1 && y < scissor_y2)
|
||||||
continue;
|
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.
|
// Not fully accurate. About 3 bits in precision are missing.
|
||||||
// Z-Buffer (z / w * scale + offset)
|
// Z-Buffer (z / w * scale + offset)
|
||||||
float depth_scale = float24::FromRaw(regs.viewport_depth_range).ToFloat32();
|
float depth_scale = float24::FromRaw(regs.rasterizer.viewport_depth_range).ToFloat32();
|
||||||
float depth_offset = float24::FromRaw(regs.viewport_depth_near_plane).ToFloat32();
|
float depth_offset =
|
||||||
|
float24::FromRaw(regs.rasterizer.viewport_depth_near_plane).ToFloat32();
|
||||||
float depth = interpolated_z_over_w * depth_scale + depth_offset;
|
float depth = interpolated_z_over_w * depth_scale + depth_offset;
|
||||||
|
|
||||||
// Potentially switch to W-Buffer
|
// 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)
|
// W-Buffer (z * scale + w * offset = (z / w * scale + offset) * w)
|
||||||
depth *= interpolated_w_inverse.ToFloat32() * wsum;
|
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
|
// TODO: Refactor so cubemaps and shadowmaps can be handled
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
switch (texture.config.type) {
|
switch (texture.config.type) {
|
||||||
case Regs::TextureConfig::Texture2D:
|
case TexturingRegs::TextureConfig::Texture2D:
|
||||||
break;
|
break;
|
||||||
case Regs::TextureConfig::Projection2D: {
|
case TexturingRegs::TextureConfig::Projection2D: {
|
||||||
auto tc0_w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w);
|
auto tc0_w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w);
|
||||||
u /= tc0_w;
|
u /= tc0_w;
|
||||||
v /= 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)))
|
int t = (int)(v * float24::FromFloat32(static_cast<float>(texture.config.height)))
|
||||||
.ToFloat32();
|
.ToFloat32();
|
||||||
|
|
||||||
static auto GetWrappedTexCoord = [](Regs::TextureConfig::WrapMode mode, int val,
|
static auto GetWrappedTexCoord = [](TexturingRegs::TextureConfig::WrapMode mode,
|
||||||
unsigned size) {
|
int val, unsigned size) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case Regs::TextureConfig::ClampToEdge:
|
case TexturingRegs::TextureConfig::ClampToEdge:
|
||||||
val = std::max(val, 0);
|
val = std::max(val, 0);
|
||||||
val = std::min(val, (int)size - 1);
|
val = std::min(val, (int)size - 1);
|
||||||
return val;
|
return val;
|
||||||
|
|
||||||
case Regs::TextureConfig::ClampToBorder:
|
case TexturingRegs::TextureConfig::ClampToBorder:
|
||||||
return val;
|
return val;
|
||||||
|
|
||||||
case Regs::TextureConfig::Repeat:
|
case TexturingRegs::TextureConfig::Repeat:
|
||||||
return (int)((unsigned)val % size);
|
return (int)((unsigned)val % size);
|
||||||
|
|
||||||
case Regs::TextureConfig::MirroredRepeat: {
|
case TexturingRegs::TextureConfig::MirroredRepeat: {
|
||||||
unsigned int coord = ((unsigned)val % (2 * size));
|
unsigned int coord = ((unsigned)val % (2 * size));
|
||||||
if (coord >= size)
|
if (coord >= size)
|
||||||
coord = 2 * size - 1 - coord;
|
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)) ||
|
(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))) {
|
(t < 0 || static_cast<u32>(t) >= texture.config.height))) {
|
||||||
auto border_color = texture.config.border_color;
|
auto border_color = texture.config.border_color;
|
||||||
texture_color[i] = {border_color.r, border_color.g, border_color.b,
|
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_output;
|
||||||
Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0};
|
Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0};
|
||||||
Math::Vec4<u8> next_combiner_buffer = {
|
Math::Vec4<u8> next_combiner_buffer = {
|
||||||
regs.tev_combiner_buffer_color.r, regs.tev_combiner_buffer_color.g,
|
regs.texturing.tev_combiner_buffer_color.r,
|
||||||
regs.tev_combiner_buffer_color.b, regs.tev_combiner_buffer_color.a,
|
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();
|
for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size();
|
||||||
++tev_stage_index) {
|
++tev_stage_index) {
|
||||||
const auto& tev_stage = tev_stages[tev_stage_index];
|
const auto& tev_stage = tev_stages[tev_stage_index];
|
||||||
using Source = Regs::TevStageConfig::Source;
|
using Source = TexturingRegs::TevStageConfig::Source;
|
||||||
using ColorModifier = Regs::TevStageConfig::ColorModifier;
|
using ColorModifier = TexturingRegs::TevStageConfig::ColorModifier;
|
||||||
using AlphaModifier = Regs::TevStageConfig::AlphaModifier;
|
using AlphaModifier = TexturingRegs::TevStageConfig::AlphaModifier;
|
||||||
using Operation = Regs::TevStageConfig::Operation;
|
using Operation = TexturingRegs::TevStageConfig::Operation;
|
||||||
|
|
||||||
auto GetSource = [&](Source source) -> Math::Vec4<u8> {
|
auto GetSource = [&](Source source) -> Math::Vec4<u8> {
|
||||||
switch (source) {
|
switch (source) {
|
||||||
|
@ -862,54 +867,54 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
||||||
|
|
||||||
combiner_buffer = next_combiner_buffer;
|
combiner_buffer = next_combiner_buffer;
|
||||||
|
|
||||||
if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(
|
if (regs.texturing.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(
|
||||||
tev_stage_index)) {
|
tev_stage_index)) {
|
||||||
next_combiner_buffer.r() = combiner_output.r();
|
next_combiner_buffer.r() = combiner_output.r();
|
||||||
next_combiner_buffer.g() = combiner_output.g();
|
next_combiner_buffer.g() = combiner_output.g();
|
||||||
next_combiner_buffer.b() = combiner_output.b();
|
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)) {
|
tev_stage_index)) {
|
||||||
next_combiner_buffer.a() = combiner_output.a();
|
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?
|
// TODO: Does alpha testing happen before or after stencil?
|
||||||
if (output_merger.alpha_test.enable) {
|
if (output_merger.alpha_test.enable) {
|
||||||
bool pass = false;
|
bool pass = false;
|
||||||
|
|
||||||
switch (output_merger.alpha_test.func) {
|
switch (output_merger.alpha_test.func) {
|
||||||
case Regs::CompareFunc::Never:
|
case FramebufferRegs::CompareFunc::Never:
|
||||||
pass = false;
|
pass = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::Always:
|
case FramebufferRegs::CompareFunc::Always:
|
||||||
pass = true;
|
pass = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::Equal:
|
case FramebufferRegs::CompareFunc::Equal:
|
||||||
pass = combiner_output.a() == output_merger.alpha_test.ref;
|
pass = combiner_output.a() == output_merger.alpha_test.ref;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::NotEqual:
|
case FramebufferRegs::CompareFunc::NotEqual:
|
||||||
pass = combiner_output.a() != output_merger.alpha_test.ref;
|
pass = combiner_output.a() != output_merger.alpha_test.ref;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::LessThan:
|
case FramebufferRegs::CompareFunc::LessThan:
|
||||||
pass = combiner_output.a() < output_merger.alpha_test.ref;
|
pass = combiner_output.a() < output_merger.alpha_test.ref;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::LessThanOrEqual:
|
case FramebufferRegs::CompareFunc::LessThanOrEqual:
|
||||||
pass = combiner_output.a() <= output_merger.alpha_test.ref;
|
pass = combiner_output.a() <= output_merger.alpha_test.ref;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::GreaterThan:
|
case FramebufferRegs::CompareFunc::GreaterThan:
|
||||||
pass = combiner_output.a() > output_merger.alpha_test.ref;
|
pass = combiner_output.a() > output_merger.alpha_test.ref;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::GreaterThanOrEqual:
|
case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
|
||||||
pass = combiner_output.a() >= output_merger.alpha_test.ref;
|
pass = combiner_output.a() >= output_merger.alpha_test.ref;
|
||||||
break;
|
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
|
// 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
|
// store the depth etc. Using float for now until we know more
|
||||||
// about Pica datatypes
|
// about Pica datatypes
|
||||||
if (regs.fog_mode == Regs::FogMode::Fog) {
|
if (regs.texturing.fog_mode == TexturingRegs::FogMode::Fog) {
|
||||||
const Math::Vec3<u8> fog_color = {
|
const Math::Vec3<u8> fog_color = {
|
||||||
static_cast<u8>(regs.fog_color.r.Value()),
|
static_cast<u8>(regs.texturing.fog_color.r.Value()),
|
||||||
static_cast<u8>(regs.fog_color.g.Value()),
|
static_cast<u8>(regs.texturing.fog_color.g.Value()),
|
||||||
static_cast<u8>(regs.fog_color.b.Value()),
|
static_cast<u8>(regs.texturing.fog_color.b.Value()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get index into fog LUT
|
// Get index into fog LUT
|
||||||
float fog_index;
|
float fog_index;
|
||||||
if (g_state.regs.fog_flip) {
|
if (g_state.regs.texturing.fog_flip) {
|
||||||
fog_index = (1.0f - depth) * 128.0f;
|
fog_index = (1.0f - depth) * 128.0f;
|
||||||
} else {
|
} else {
|
||||||
fog_index = depth * 128.0f;
|
fog_index = depth * 128.0f;
|
||||||
|
@ -955,10 +960,10 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
||||||
u8 old_stencil = 0;
|
u8 old_stencil = 0;
|
||||||
|
|
||||||
auto UpdateStencil = [stencil_test, x, y,
|
auto UpdateStencil = [stencil_test, x, y,
|
||||||
&old_stencil](Pica::Regs::StencilAction action) {
|
&old_stencil](Pica::FramebufferRegs::StencilAction action) {
|
||||||
u8 new_stencil =
|
u8 new_stencil =
|
||||||
PerformStencilAction(action, old_stencil, stencil_test.reference_value);
|
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) |
|
SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) |
|
||||||
(old_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;
|
bool pass = false;
|
||||||
switch (stencil_test.func) {
|
switch (stencil_test.func) {
|
||||||
case Regs::CompareFunc::Never:
|
case FramebufferRegs::CompareFunc::Never:
|
||||||
pass = false;
|
pass = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::Always:
|
case FramebufferRegs::CompareFunc::Always:
|
||||||
pass = true;
|
pass = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::Equal:
|
case FramebufferRegs::CompareFunc::Equal:
|
||||||
pass = (ref == dest);
|
pass = (ref == dest);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::NotEqual:
|
case FramebufferRegs::CompareFunc::NotEqual:
|
||||||
pass = (ref != dest);
|
pass = (ref != dest);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::LessThan:
|
case FramebufferRegs::CompareFunc::LessThan:
|
||||||
pass = (ref < dest);
|
pass = (ref < dest);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::LessThanOrEqual:
|
case FramebufferRegs::CompareFunc::LessThanOrEqual:
|
||||||
pass = (ref <= dest);
|
pass = (ref <= dest);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::GreaterThan:
|
case FramebufferRegs::CompareFunc::GreaterThan:
|
||||||
pass = (ref > dest);
|
pass = (ref > dest);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::GreaterThanOrEqual:
|
case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
|
||||||
pass = (ref >= dest);
|
pass = (ref >= dest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1010,7 +1015,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert float to integer
|
// 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));
|
u32 z = (u32)(depth * ((1 << num_bits) - 1));
|
||||||
|
|
||||||
if (output_merger.depth_test_enable) {
|
if (output_merger.depth_test_enable) {
|
||||||
|
@ -1019,35 +1025,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
||||||
bool pass = false;
|
bool pass = false;
|
||||||
|
|
||||||
switch (output_merger.depth_test_func) {
|
switch (output_merger.depth_test_func) {
|
||||||
case Regs::CompareFunc::Never:
|
case FramebufferRegs::CompareFunc::Never:
|
||||||
pass = false;
|
pass = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::Always:
|
case FramebufferRegs::CompareFunc::Always:
|
||||||
pass = true;
|
pass = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::Equal:
|
case FramebufferRegs::CompareFunc::Equal:
|
||||||
pass = z == ref_z;
|
pass = z == ref_z;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::NotEqual:
|
case FramebufferRegs::CompareFunc::NotEqual:
|
||||||
pass = z != ref_z;
|
pass = z != ref_z;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::LessThan:
|
case FramebufferRegs::CompareFunc::LessThan:
|
||||||
pass = z < ref_z;
|
pass = z < ref_z;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::LessThanOrEqual:
|
case FramebufferRegs::CompareFunc::LessThanOrEqual:
|
||||||
pass = z <= ref_z;
|
pass = z <= ref_z;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::GreaterThan:
|
case FramebufferRegs::CompareFunc::GreaterThan:
|
||||||
pass = z > ref_z;
|
pass = z > ref_z;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::CompareFunc::GreaterThanOrEqual:
|
case FramebufferRegs::CompareFunc::GreaterThanOrEqual:
|
||||||
pass = z >= ref_z;
|
pass = z >= ref_z;
|
||||||
break;
|
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);
|
SetDepth(x >> 4, y >> 4, z);
|
||||||
|
}
|
||||||
|
|
||||||
// The stencil depth_pass action is executed even if depth testing is disabled
|
// The stencil depth_pass action is executed even if depth testing is disabled
|
||||||
if (stencil_action_enable)
|
if (stencil_action_enable)
|
||||||
|
@ -1072,7 +1081,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
||||||
if (output_merger.alphablend_enable) {
|
if (output_merger.alphablend_enable) {
|
||||||
auto params = output_merger.alpha_blending;
|
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);
|
DEBUG_ASSERT(channel < 4);
|
||||||
|
|
||||||
const Math::Vec4<u8> blend_const = {
|
const Math::Vec4<u8> blend_const = {
|
||||||
|
@ -1083,49 +1093,49 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (factor) {
|
switch (factor) {
|
||||||
case Regs::BlendFactor::Zero:
|
case FramebufferRegs::BlendFactor::Zero:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case Regs::BlendFactor::One:
|
case FramebufferRegs::BlendFactor::One:
|
||||||
return 255;
|
return 255;
|
||||||
|
|
||||||
case Regs::BlendFactor::SourceColor:
|
case FramebufferRegs::BlendFactor::SourceColor:
|
||||||
return combiner_output[channel];
|
return combiner_output[channel];
|
||||||
|
|
||||||
case Regs::BlendFactor::OneMinusSourceColor:
|
case FramebufferRegs::BlendFactor::OneMinusSourceColor:
|
||||||
return 255 - combiner_output[channel];
|
return 255 - combiner_output[channel];
|
||||||
|
|
||||||
case Regs::BlendFactor::DestColor:
|
case FramebufferRegs::BlendFactor::DestColor:
|
||||||
return dest[channel];
|
return dest[channel];
|
||||||
|
|
||||||
case Regs::BlendFactor::OneMinusDestColor:
|
case FramebufferRegs::BlendFactor::OneMinusDestColor:
|
||||||
return 255 - dest[channel];
|
return 255 - dest[channel];
|
||||||
|
|
||||||
case Regs::BlendFactor::SourceAlpha:
|
case FramebufferRegs::BlendFactor::SourceAlpha:
|
||||||
return combiner_output.a();
|
return combiner_output.a();
|
||||||
|
|
||||||
case Regs::BlendFactor::OneMinusSourceAlpha:
|
case FramebufferRegs::BlendFactor::OneMinusSourceAlpha:
|
||||||
return 255 - combiner_output.a();
|
return 255 - combiner_output.a();
|
||||||
|
|
||||||
case Regs::BlendFactor::DestAlpha:
|
case FramebufferRegs::BlendFactor::DestAlpha:
|
||||||
return dest.a();
|
return dest.a();
|
||||||
|
|
||||||
case Regs::BlendFactor::OneMinusDestAlpha:
|
case FramebufferRegs::BlendFactor::OneMinusDestAlpha:
|
||||||
return 255 - dest.a();
|
return 255 - dest.a();
|
||||||
|
|
||||||
case Regs::BlendFactor::ConstantColor:
|
case FramebufferRegs::BlendFactor::ConstantColor:
|
||||||
return blend_const[channel];
|
return blend_const[channel];
|
||||||
|
|
||||||
case Regs::BlendFactor::OneMinusConstantColor:
|
case FramebufferRegs::BlendFactor::OneMinusConstantColor:
|
||||||
return 255 - blend_const[channel];
|
return 255 - blend_const[channel];
|
||||||
|
|
||||||
case Regs::BlendFactor::ConstantAlpha:
|
case FramebufferRegs::BlendFactor::ConstantAlpha:
|
||||||
return blend_const.a();
|
return blend_const.a();
|
||||||
|
|
||||||
case Regs::BlendFactor::OneMinusConstantAlpha:
|
case FramebufferRegs::BlendFactor::OneMinusConstantAlpha:
|
||||||
return 255 - blend_const.a();
|
return 255 - blend_const.a();
|
||||||
|
|
||||||
case Regs::BlendFactor::SourceAlphaSaturate:
|
case FramebufferRegs::BlendFactor::SourceAlphaSaturate:
|
||||||
// Returns 1.0 for the alpha channel
|
// Returns 1.0 for the alpha channel
|
||||||
if (channel == 3)
|
if (channel == 3)
|
||||||
return 255;
|
return 255;
|
||||||
|
@ -1143,36 +1153,37 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
||||||
static auto EvaluateBlendEquation = [](
|
static auto EvaluateBlendEquation = [](
|
||||||
const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
|
const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
|
||||||
const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
|
const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
|
||||||
Regs::BlendEquation equation) {
|
FramebufferRegs::BlendEquation equation) {
|
||||||
|
|
||||||
Math::Vec4<int> result;
|
Math::Vec4<int> result;
|
||||||
|
|
||||||
auto src_result = (src * srcfactor).Cast<int>();
|
auto src_result = (src * srcfactor).Cast<int>();
|
||||||
auto dst_result = (dest * destfactor).Cast<int>();
|
auto dst_result = (dest * destfactor).Cast<int>();
|
||||||
|
|
||||||
switch (equation) {
|
switch (equation) {
|
||||||
case Regs::BlendEquation::Add:
|
case FramebufferRegs::BlendEquation::Add:
|
||||||
result = (src_result + dst_result) / 255;
|
result = (src_result + dst_result) / 255;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::BlendEquation::Subtract:
|
case FramebufferRegs::BlendEquation::Subtract:
|
||||||
result = (src_result - dst_result) / 255;
|
result = (src_result - dst_result) / 255;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::BlendEquation::ReverseSubtract:
|
case FramebufferRegs::BlendEquation::ReverseSubtract:
|
||||||
result = (dst_result - src_result) / 255;
|
result = (dst_result - src_result) / 255;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TODO: How do these two actually work?
|
// TODO: How do these two actually work?
|
||||||
// OpenGL doesn't include the blend factors in the min/max computations,
|
// OpenGL doesn't include the blend factors in the min/max computations,
|
||||||
// but is this what the 3DS actually does?
|
// 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.r() = std::min(src.r(), dest.r());
|
||||||
result.g() = std::min(src.g(), dest.g());
|
result.g() = std::min(src.g(), dest.g());
|
||||||
result.b() = std::min(src.b(), dest.b());
|
result.b() = std::min(src.b(), dest.b());
|
||||||
result.a() = std::min(src.a(), dest.a());
|
result.a() = std::min(src.a(), dest.a());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::BlendEquation::Max:
|
case FramebufferRegs::BlendEquation::Max:
|
||||||
result.r() = std::max(src.r(), dest.r());
|
result.r() = std::max(src.r(), dest.r());
|
||||||
result.g() = std::max(src.g(), dest.g());
|
result.g() = std::max(src.g(), dest.g());
|
||||||
result.b() = std::max(src.b(), dest.b());
|
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)
|
dstfactor, params.blend_equation_a)
|
||||||
.a();
|
.a();
|
||||||
} else {
|
} 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) {
|
switch (op) {
|
||||||
case Regs::LogicOp::Clear:
|
case FramebufferRegs::LogicOp::Clear:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case Regs::LogicOp::And:
|
case FramebufferRegs::LogicOp::And:
|
||||||
return src & dest;
|
return src & dest;
|
||||||
|
|
||||||
case Regs::LogicOp::AndReverse:
|
case FramebufferRegs::LogicOp::AndReverse:
|
||||||
return src & ~dest;
|
return src & ~dest;
|
||||||
|
|
||||||
case Regs::LogicOp::Copy:
|
case FramebufferRegs::LogicOp::Copy:
|
||||||
return src;
|
return src;
|
||||||
|
|
||||||
case Regs::LogicOp::Set:
|
case FramebufferRegs::LogicOp::Set:
|
||||||
return 255;
|
return 255;
|
||||||
|
|
||||||
case Regs::LogicOp::CopyInverted:
|
case FramebufferRegs::LogicOp::CopyInverted:
|
||||||
return ~src;
|
return ~src;
|
||||||
|
|
||||||
case Regs::LogicOp::NoOp:
|
case FramebufferRegs::LogicOp::NoOp:
|
||||||
return dest;
|
return dest;
|
||||||
|
|
||||||
case Regs::LogicOp::Invert:
|
case FramebufferRegs::LogicOp::Invert:
|
||||||
return ~dest;
|
return ~dest;
|
||||||
|
|
||||||
case Regs::LogicOp::Nand:
|
case FramebufferRegs::LogicOp::Nand:
|
||||||
return ~(src & dest);
|
return ~(src & dest);
|
||||||
|
|
||||||
case Regs::LogicOp::Or:
|
case FramebufferRegs::LogicOp::Or:
|
||||||
return src | dest;
|
return src | dest;
|
||||||
|
|
||||||
case Regs::LogicOp::Nor:
|
case FramebufferRegs::LogicOp::Nor:
|
||||||
return ~(src | dest);
|
return ~(src | dest);
|
||||||
|
|
||||||
case Regs::LogicOp::Xor:
|
case FramebufferRegs::LogicOp::Xor:
|
||||||
return src ^ dest;
|
return src ^ dest;
|
||||||
|
|
||||||
case Regs::LogicOp::Equiv:
|
case FramebufferRegs::LogicOp::Equiv:
|
||||||
return ~(src ^ dest);
|
return ~(src ^ dest);
|
||||||
|
|
||||||
case Regs::LogicOp::AndInverted:
|
case FramebufferRegs::LogicOp::AndInverted:
|
||||||
return ~src & dest;
|
return ~src & dest;
|
||||||
|
|
||||||
case Regs::LogicOp::OrReverse:
|
case FramebufferRegs::LogicOp::OrReverse:
|
||||||
return src | ~dest;
|
return src | ~dest;
|
||||||
|
|
||||||
case Regs::LogicOp::OrInverted:
|
case FramebufferRegs::LogicOp::OrInverted:
|
||||||
return ~src | dest;
|
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(),
|
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);
|
DrawPixel(x >> 4, y >> 4, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
493
src/video_core/regs.cpp
Normal file
493
src/video_core/regs.cpp
Normal file
|
@ -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
|
164
src/video_core/regs.h
Normal file
164
src/video_core/regs.h
Normal file
|
@ -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
|
284
src/video_core/regs_framebuffer.h
Normal file
284
src/video_core/regs_framebuffer.h
Normal file
|
@ -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
|
294
src/video_core/regs_lighting.h
Normal file
294
src/video_core/regs_lighting.h
Normal file
|
@ -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
|
224
src/video_core/regs_pipeline.h
Normal file
224
src/video_core/regs_pipeline.h
Normal file
|
@ -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
|
129
src/video_core/regs_rasterizer.h
Normal file
129
src/video_core/regs_rasterizer.h
Normal file
|
@ -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
|
104
src/video_core/regs_shader.h
Normal file
104
src/video_core/regs_shader.h
Normal file
|
@ -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
|
328
src/video_core/regs_texturing.h
Normal file
328
src/video_core/regs_texturing.h
Normal file
|
@ -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
|
|
@ -14,8 +14,8 @@
|
||||||
#include "common/microprofile.h"
|
#include "common/microprofile.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "core/hw/gpu.h"
|
#include "core/hw/gpu.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/pica_state.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_rasterizer.h"
|
||||||
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
||||||
#include "video_core/renderer_opengl/gl_shader_util.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_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
|
||||||
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
|
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
|
||||||
|
|
||||||
static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
|
static bool IsPassThroughTevStage(const Pica::TexturingRegs::TevStageConfig& stage) {
|
||||||
return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace &&
|
using TevStageConfig = Pica::TexturingRegs::TevStageConfig;
|
||||||
stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace &&
|
|
||||||
stage.color_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
|
return (stage.color_op == TevStageConfig::Operation::Replace &&
|
||||||
stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
|
stage.alpha_op == TevStageConfig::Operation::Replace &&
|
||||||
stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor &&
|
stage.color_source1 == TevStageConfig::Source::Previous &&
|
||||||
stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha &&
|
stage.alpha_source1 == TevStageConfig::Source::Previous &&
|
||||||
|
stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor &&
|
||||||
|
stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha &&
|
||||||
stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1);
|
stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +183,7 @@ void RasterizerOpenGL::DrawTriangles() {
|
||||||
CachedSurface* depth_surface;
|
CachedSurface* depth_surface;
|
||||||
MathUtil::Rectangle<int> rect;
|
MathUtil::Rectangle<int> rect;
|
||||||
std::tie(color_surface, depth_surface, 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.draw.draw_framebuffer = framebuffer.handle;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
@ -190,20 +192,24 @@ void RasterizerOpenGL::DrawTriangles() {
|
||||||
color_surface != nullptr ? color_surface->texture.handle : 0, 0);
|
color_surface != nullptr ? color_surface->texture.handle : 0, 0);
|
||||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
|
||||||
depth_surface != nullptr ? depth_surface->texture.handle : 0, 0);
|
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(
|
glFramebufferTexture2D(
|
||||||
GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
||||||
(has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0);
|
(has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0);
|
||||||
|
|
||||||
// Sync the viewport
|
// Sync the viewport
|
||||||
// These registers hold half-width and half-height, so must be multiplied by 2
|
// 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_width =
|
||||||
GLsizei viewport_height = (GLsizei)Pica::float24::FromRaw(regs.viewport_size_y).ToFloat32() * 2;
|
(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),
|
glViewport(
|
||||||
(GLint)(rect.bottom + regs.viewport_corner.y * color_surface->res_scale_height),
|
(GLint)(rect.left + regs.rasterizer.viewport_corner.x * color_surface->res_scale_width),
|
||||||
(GLsizei)(viewport_width * color_surface->res_scale_width),
|
(GLint)(rect.bottom + regs.rasterizer.viewport_corner.y * color_surface->res_scale_height),
|
||||||
(GLsizei)(viewport_height * 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 ||
|
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) {
|
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
|
// 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.
|
// sub-rect changes, the scissor bounds also need to be updated.
|
||||||
GLint scissor_x1 =
|
GLint scissor_x1 = static_cast<GLint>(
|
||||||
static_cast<GLint>(rect.left + regs.scissor_test.x1 * color_surface->res_scale_width);
|
rect.left + regs.rasterizer.scissor_test.x1 * color_surface->res_scale_width);
|
||||||
GLint scissor_y1 =
|
GLint scissor_y1 = static_cast<GLint>(
|
||||||
static_cast<GLint>(rect.bottom + regs.scissor_test.y1 * color_surface->res_scale_height);
|
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
|
// x2, y2 have +1 added to cover the entire pixel area, otherwise you might get cracks when
|
||||||
// scaling or doing multisampling.
|
// scaling or doing multisampling.
|
||||||
GLint scissor_x2 =
|
GLint scissor_x2 = static_cast<GLint>(
|
||||||
static_cast<GLint>(rect.left + (regs.scissor_test.x2 + 1) * color_surface->res_scale_width);
|
rect.left + (regs.rasterizer.scissor_test.x2 + 1) * color_surface->res_scale_width);
|
||||||
GLint scissor_y2 = static_cast<GLint>(
|
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 ||
|
if (uniform_block_data.data.scissor_x1 != scissor_x1 ||
|
||||||
uniform_block_data.data.scissor_x2 != scissor_x2 ||
|
uniform_block_data.data.scissor_x2 != scissor_x2 ||
|
||||||
|
@ -239,7 +245,7 @@ void RasterizerOpenGL::DrawTriangles() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync and bind the texture surfaces
|
// 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) {
|
for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
|
||||||
const auto& texture = pica_textures[texture_index];
|
const auto& texture = pica_textures[texture_index];
|
||||||
|
|
||||||
|
@ -316,69 +322,69 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
// Culling
|
// Culling
|
||||||
case PICA_REG_INDEX(cull_mode):
|
case PICA_REG_INDEX(rasterizer.cull_mode):
|
||||||
SyncCullMode();
|
SyncCullMode();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Depth modifiers
|
// Depth modifiers
|
||||||
case PICA_REG_INDEX(viewport_depth_range):
|
case PICA_REG_INDEX(rasterizer.viewport_depth_range):
|
||||||
SyncDepthScale();
|
SyncDepthScale();
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(viewport_depth_near_plane):
|
case PICA_REG_INDEX(rasterizer.viewport_depth_near_plane):
|
||||||
SyncDepthOffset();
|
SyncDepthOffset();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Depth buffering
|
// Depth buffering
|
||||||
case PICA_REG_INDEX(depthmap_enable):
|
case PICA_REG_INDEX(rasterizer.depthmap_enable):
|
||||||
shader_dirty = true;
|
shader_dirty = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Blending
|
// Blending
|
||||||
case PICA_REG_INDEX(output_merger.alphablend_enable):
|
case PICA_REG_INDEX(framebuffer.output_merger.alphablend_enable):
|
||||||
SyncBlendEnabled();
|
SyncBlendEnabled();
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(output_merger.alpha_blending):
|
case PICA_REG_INDEX(framebuffer.output_merger.alpha_blending):
|
||||||
SyncBlendFuncs();
|
SyncBlendFuncs();
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(output_merger.blend_const):
|
case PICA_REG_INDEX(framebuffer.output_merger.blend_const):
|
||||||
SyncBlendColor();
|
SyncBlendColor();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Fog state
|
// Fog state
|
||||||
case PICA_REG_INDEX(fog_color):
|
case PICA_REG_INDEX(texturing.fog_color):
|
||||||
SyncFogColor();
|
SyncFogColor();
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[0], 0xe8):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[0], 0xe8):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[1], 0xe9):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[1], 0xe9):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[2], 0xea):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[2], 0xea):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[3], 0xeb):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[3], 0xeb):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[4], 0xec):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[4], 0xec):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[5], 0xed):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[5], 0xed):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[6], 0xee):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[6], 0xee):
|
||||||
case PICA_REG_INDEX_WORKAROUND(fog_lut_data[7], 0xef):
|
case PICA_REG_INDEX_WORKAROUND(texturing.fog_lut_data[7], 0xef):
|
||||||
uniform_block_data.fog_lut_dirty = true;
|
uniform_block_data.fog_lut_dirty = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Alpha test
|
// Alpha test
|
||||||
case PICA_REG_INDEX(output_merger.alpha_test):
|
case PICA_REG_INDEX(framebuffer.output_merger.alpha_test):
|
||||||
SyncAlphaTest();
|
SyncAlphaTest();
|
||||||
shader_dirty = true;
|
shader_dirty = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Sync GL stencil test + stencil write mask
|
// Sync GL stencil test + stencil write mask
|
||||||
// (Pica stencil test function register also contains a 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();
|
SyncStencilTest();
|
||||||
SyncStencilWriteMask();
|
SyncStencilWriteMask();
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(output_merger.stencil_test.raw_op):
|
case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_op):
|
||||||
case PICA_REG_INDEX(framebuffer.depth_format):
|
case PICA_REG_INDEX(framebuffer.framebuffer.depth_format):
|
||||||
SyncStencilTest();
|
SyncStencilTest();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Sync GL depth test + depth and color write mask
|
// Sync GL depth test + depth and color write mask
|
||||||
// (Pica depth test function register also contains a 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();
|
SyncDepthTest();
|
||||||
SyncDepthWriteMask();
|
SyncDepthWriteMask();
|
||||||
SyncColorWriteMask();
|
SyncColorWriteMask();
|
||||||
|
@ -386,82 +392,82 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
|
||||||
|
|
||||||
// Sync GL depth and stencil write mask
|
// Sync GL depth and stencil write mask
|
||||||
// (This is a dedicated combined depth / stencil write-enable register)
|
// (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();
|
SyncDepthWriteMask();
|
||||||
SyncStencilWriteMask();
|
SyncStencilWriteMask();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Sync GL color write mask
|
// Sync GL color write mask
|
||||||
// (This is a dedicated color write-enable register)
|
// (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();
|
SyncColorWriteMask();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Scissor test
|
// Scissor test
|
||||||
case PICA_REG_INDEX(scissor_test.mode):
|
case PICA_REG_INDEX(rasterizer.scissor_test.mode):
|
||||||
shader_dirty = true;
|
shader_dirty = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Logic op
|
// Logic op
|
||||||
case PICA_REG_INDEX(output_merger.logic_op):
|
case PICA_REG_INDEX(framebuffer.output_merger.logic_op):
|
||||||
SyncLogicOp();
|
SyncLogicOp();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Texture 0 type
|
// Texture 0 type
|
||||||
case PICA_REG_INDEX(texture0.type):
|
case PICA_REG_INDEX(texturing.texture0.type):
|
||||||
shader_dirty = true;
|
shader_dirty = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TEV stages
|
// TEV stages
|
||||||
// (This also syncs fog_mode and fog_flip which are part of tev_combiner_buffer_input)
|
// (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(texturing.tev_stage0.color_source1):
|
||||||
case PICA_REG_INDEX(tev_stage0.color_modifier1):
|
case PICA_REG_INDEX(texturing.tev_stage0.color_modifier1):
|
||||||
case PICA_REG_INDEX(tev_stage0.color_op):
|
case PICA_REG_INDEX(texturing.tev_stage0.color_op):
|
||||||
case PICA_REG_INDEX(tev_stage0.color_scale):
|
case PICA_REG_INDEX(texturing.tev_stage0.color_scale):
|
||||||
case PICA_REG_INDEX(tev_stage1.color_source1):
|
case PICA_REG_INDEX(texturing.tev_stage1.color_source1):
|
||||||
case PICA_REG_INDEX(tev_stage1.color_modifier1):
|
case PICA_REG_INDEX(texturing.tev_stage1.color_modifier1):
|
||||||
case PICA_REG_INDEX(tev_stage1.color_op):
|
case PICA_REG_INDEX(texturing.tev_stage1.color_op):
|
||||||
case PICA_REG_INDEX(tev_stage1.color_scale):
|
case PICA_REG_INDEX(texturing.tev_stage1.color_scale):
|
||||||
case PICA_REG_INDEX(tev_stage2.color_source1):
|
case PICA_REG_INDEX(texturing.tev_stage2.color_source1):
|
||||||
case PICA_REG_INDEX(tev_stage2.color_modifier1):
|
case PICA_REG_INDEX(texturing.tev_stage2.color_modifier1):
|
||||||
case PICA_REG_INDEX(tev_stage2.color_op):
|
case PICA_REG_INDEX(texturing.tev_stage2.color_op):
|
||||||
case PICA_REG_INDEX(tev_stage2.color_scale):
|
case PICA_REG_INDEX(texturing.tev_stage2.color_scale):
|
||||||
case PICA_REG_INDEX(tev_stage3.color_source1):
|
case PICA_REG_INDEX(texturing.tev_stage3.color_source1):
|
||||||
case PICA_REG_INDEX(tev_stage3.color_modifier1):
|
case PICA_REG_INDEX(texturing.tev_stage3.color_modifier1):
|
||||||
case PICA_REG_INDEX(tev_stage3.color_op):
|
case PICA_REG_INDEX(texturing.tev_stage3.color_op):
|
||||||
case PICA_REG_INDEX(tev_stage3.color_scale):
|
case PICA_REG_INDEX(texturing.tev_stage3.color_scale):
|
||||||
case PICA_REG_INDEX(tev_stage4.color_source1):
|
case PICA_REG_INDEX(texturing.tev_stage4.color_source1):
|
||||||
case PICA_REG_INDEX(tev_stage4.color_modifier1):
|
case PICA_REG_INDEX(texturing.tev_stage4.color_modifier1):
|
||||||
case PICA_REG_INDEX(tev_stage4.color_op):
|
case PICA_REG_INDEX(texturing.tev_stage4.color_op):
|
||||||
case PICA_REG_INDEX(tev_stage4.color_scale):
|
case PICA_REG_INDEX(texturing.tev_stage4.color_scale):
|
||||||
case PICA_REG_INDEX(tev_stage5.color_source1):
|
case PICA_REG_INDEX(texturing.tev_stage5.color_source1):
|
||||||
case PICA_REG_INDEX(tev_stage5.color_modifier1):
|
case PICA_REG_INDEX(texturing.tev_stage5.color_modifier1):
|
||||||
case PICA_REG_INDEX(tev_stage5.color_op):
|
case PICA_REG_INDEX(texturing.tev_stage5.color_op):
|
||||||
case PICA_REG_INDEX(tev_stage5.color_scale):
|
case PICA_REG_INDEX(texturing.tev_stage5.color_scale):
|
||||||
case PICA_REG_INDEX(tev_combiner_buffer_input):
|
case PICA_REG_INDEX(texturing.tev_combiner_buffer_input):
|
||||||
shader_dirty = true;
|
shader_dirty = true;
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage0.const_r):
|
case PICA_REG_INDEX(texturing.tev_stage0.const_r):
|
||||||
SyncTevConstColor(0, regs.tev_stage0);
|
SyncTevConstColor(0, regs.texturing.tev_stage0);
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage1.const_r):
|
case PICA_REG_INDEX(texturing.tev_stage1.const_r):
|
||||||
SyncTevConstColor(1, regs.tev_stage1);
|
SyncTevConstColor(1, regs.texturing.tev_stage1);
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage2.const_r):
|
case PICA_REG_INDEX(texturing.tev_stage2.const_r):
|
||||||
SyncTevConstColor(2, regs.tev_stage2);
|
SyncTevConstColor(2, regs.texturing.tev_stage2);
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage3.const_r):
|
case PICA_REG_INDEX(texturing.tev_stage3.const_r):
|
||||||
SyncTevConstColor(3, regs.tev_stage3);
|
SyncTevConstColor(3, regs.texturing.tev_stage3);
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage4.const_r):
|
case PICA_REG_INDEX(texturing.tev_stage4.const_r):
|
||||||
SyncTevConstColor(4, regs.tev_stage4);
|
SyncTevConstColor(4, regs.texturing.tev_stage4);
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage5.const_r):
|
case PICA_REG_INDEX(texturing.tev_stage5.const_r):
|
||||||
SyncTevConstColor(5, regs.tev_stage5);
|
SyncTevConstColor(5, regs.texturing.tev_stage5);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TEV combiner buffer color
|
// TEV combiner buffer color
|
||||||
case PICA_REG_INDEX(tev_combiner_buffer_color):
|
case PICA_REG_INDEX(texturing.tev_combiner_buffer_color):
|
||||||
SyncCombinerColor();
|
SyncCombinerColor();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -976,7 +982,9 @@ void RasterizerOpenGL::SamplerInfo::Create() {
|
||||||
// Other attributes have correct defaults
|
// 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;
|
GLuint s = sampler.handle;
|
||||||
|
|
||||||
if (mag_filter != config.mag_filter) {
|
if (mag_filter != config.mag_filter) {
|
||||||
|
@ -1088,7 +1096,7 @@ void RasterizerOpenGL::SetShader() {
|
||||||
SyncDepthOffset();
|
SyncDepthOffset();
|
||||||
SyncAlphaTest();
|
SyncAlphaTest();
|
||||||
SyncCombinerColor();
|
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)
|
for (int index = 0; index < tev_stages.size(); ++index)
|
||||||
SyncTevConstColor(index, tev_stages[index]);
|
SyncTevConstColor(index, tev_stages[index]);
|
||||||
|
|
||||||
|
@ -1110,30 +1118,31 @@ void RasterizerOpenGL::SetShader() {
|
||||||
void RasterizerOpenGL::SyncCullMode() {
|
void RasterizerOpenGL::SyncCullMode() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
|
|
||||||
switch (regs.cull_mode) {
|
switch (regs.rasterizer.cull_mode) {
|
||||||
case Pica::Regs::CullMode::KeepAll:
|
case Pica::RasterizerRegs::CullMode::KeepAll:
|
||||||
state.cull.enabled = false;
|
state.cull.enabled = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Pica::Regs::CullMode::KeepClockWise:
|
case Pica::RasterizerRegs::CullMode::KeepClockWise:
|
||||||
state.cull.enabled = true;
|
state.cull.enabled = true;
|
||||||
state.cull.front_face = GL_CW;
|
state.cull.front_face = GL_CW;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Pica::Regs::CullMode::KeepCounterClockWise:
|
case Pica::RasterizerRegs::CullMode::KeepCounterClockWise:
|
||||||
state.cull.enabled = true;
|
state.cull.enabled = true;
|
||||||
state.cull.front_face = GL_CCW;
|
state.cull.front_face = GL_CCW;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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();
|
UNIMPLEMENTED();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncDepthScale() {
|
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) {
|
if (depth_scale != uniform_block_data.data.depth_scale) {
|
||||||
uniform_block_data.data.depth_scale = depth_scale;
|
uniform_block_data.data.depth_scale = depth_scale;
|
||||||
uniform_block_data.dirty = true;
|
uniform_block_data.dirty = true;
|
||||||
|
@ -1142,7 +1151,7 @@ void RasterizerOpenGL::SyncDepthScale() {
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncDepthOffset() {
|
void RasterizerOpenGL::SyncDepthOffset() {
|
||||||
float depth_offset =
|
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) {
|
if (depth_offset != uniform_block_data.data.depth_offset) {
|
||||||
uniform_block_data.data.depth_offset = depth_offset;
|
uniform_block_data.data.depth_offset = depth_offset;
|
||||||
uniform_block_data.dirty = true;
|
uniform_block_data.dirty = true;
|
||||||
|
@ -1150,25 +1159,28 @@ void RasterizerOpenGL::SyncDepthOffset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncBlendEnabled() {
|
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() {
|
void RasterizerOpenGL::SyncBlendFuncs() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
state.blend.rgb_equation =
|
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 =
|
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 =
|
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 =
|
state.blend.dst_rgb_func =
|
||||||
PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb);
|
PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_rgb);
|
||||||
state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a);
|
state.blend.src_a_func =
|
||||||
state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a);
|
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() {
|
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.red = blend_color[0];
|
||||||
state.blend.color.green = blend_color[1];
|
state.blend.color.green = blend_color[1];
|
||||||
state.blend.color.blue = blend_color[2];
|
state.blend.color.blue = blend_color[2];
|
||||||
|
@ -1178,8 +1190,8 @@ void RasterizerOpenGL::SyncBlendColor() {
|
||||||
void RasterizerOpenGL::SyncFogColor() {
|
void RasterizerOpenGL::SyncFogColor() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
uniform_block_data.data.fog_color = {
|
uniform_block_data.data.fog_color = {
|
||||||
regs.fog_color.r.Value() / 255.0f, regs.fog_color.g.Value() / 255.0f,
|
regs.texturing.fog_color.r.Value() / 255.0f, regs.texturing.fog_color.g.Value() / 255.0f,
|
||||||
regs.fog_color.b.Value() / 255.0f,
|
regs.texturing.fog_color.b.Value() / 255.0f,
|
||||||
};
|
};
|
||||||
uniform_block_data.dirty = true;
|
uniform_block_data.dirty = true;
|
||||||
}
|
}
|
||||||
|
@ -1200,70 +1212,78 @@ void RasterizerOpenGL::SyncFogLUT() {
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncAlphaTest() {
|
void RasterizerOpenGL::SyncAlphaTest() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
if (regs.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) {
|
if (regs.framebuffer.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) {
|
||||||
uniform_block_data.data.alphatest_ref = regs.output_merger.alpha_test.ref;
|
uniform_block_data.data.alphatest_ref = regs.framebuffer.output_merger.alpha_test.ref;
|
||||||
uniform_block_data.dirty = true;
|
uniform_block_data.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncLogicOp() {
|
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() {
|
void RasterizerOpenGL::SyncColorWriteMask() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
|
|
||||||
auto IsColorWriteEnabled = [&](u32 value) {
|
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.red_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.red_enable);
|
||||||
state.color_mask.green_enabled = IsColorWriteEnabled(regs.output_merger.green_enable);
|
state.color_mask.green_enabled =
|
||||||
state.color_mask.blue_enabled = IsColorWriteEnabled(regs.output_merger.blue_enable);
|
IsColorWriteEnabled(regs.framebuffer.output_merger.green_enable);
|
||||||
state.color_mask.alpha_enabled = IsColorWriteEnabled(regs.output_merger.alpha_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() {
|
void RasterizerOpenGL::SyncStencilWriteMask() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
state.stencil.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0)
|
state.stencil.write_mask =
|
||||||
? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask)
|
(regs.framebuffer.framebuffer.allow_depth_stencil_write != 0)
|
||||||
: 0;
|
? static_cast<GLuint>(regs.framebuffer.output_merger.stencil_test.write_mask)
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncDepthWriteMask() {
|
void RasterizerOpenGL::SyncDepthWriteMask() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
state.depth.write_mask =
|
state.depth.write_mask = (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 &&
|
||||||
(regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable)
|
regs.framebuffer.output_merger.depth_write_enable)
|
||||||
? GL_TRUE
|
? GL_TRUE
|
||||||
: GL_FALSE;
|
: GL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncStencilTest() {
|
void RasterizerOpenGL::SyncStencilTest() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
state.stencil.test_enabled = regs.output_merger.stencil_test.enable &&
|
state.stencil.test_enabled =
|
||||||
regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8;
|
regs.framebuffer.output_merger.stencil_test.enable &&
|
||||||
state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func);
|
regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8;
|
||||||
state.stencil.test_ref = regs.output_merger.stencil_test.reference_value;
|
state.stencil.test_func =
|
||||||
state.stencil.test_mask = regs.output_merger.stencil_test.input_mask;
|
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 =
|
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 =
|
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 =
|
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() {
|
void RasterizerOpenGL::SyncDepthTest() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
state.depth.test_enabled =
|
state.depth.test_enabled = regs.framebuffer.output_merger.depth_test_enable == 1 ||
|
||||||
regs.output_merger.depth_test_enable == 1 || regs.output_merger.depth_write_enable == 1;
|
regs.framebuffer.output_merger.depth_write_enable == 1;
|
||||||
state.depth.test_func = regs.output_merger.depth_test_enable == 1
|
state.depth.test_func =
|
||||||
? PicaToGL::CompareFunc(regs.output_merger.depth_test_func)
|
regs.framebuffer.output_merger.depth_test_enable == 1
|
||||||
: GL_ALWAYS;
|
? PicaToGL::CompareFunc(regs.framebuffer.output_merger.depth_test_func)
|
||||||
|
: GL_ALWAYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncCombinerColor() {
|
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) {
|
if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) {
|
||||||
uniform_block_data.data.tev_combiner_buffer_color = combiner_color;
|
uniform_block_data.data.tev_combiner_buffer_color = combiner_color;
|
||||||
uniform_block_data.dirty = true;
|
uniform_block_data.dirty = true;
|
||||||
|
@ -1271,7 +1291,7 @@ void RasterizerOpenGL::SyncCombinerColor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncTevConstColor(int stage_index,
|
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);
|
auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color);
|
||||||
if (const_color != uniform_block_data.data.const_color[stage_index]) {
|
if (const_color != uniform_block_data.data.const_color[stage_index]) {
|
||||||
uniform_block_data.data.const_color[stage_index] = const_color;
|
uniform_block_data.data.const_color[stage_index] = const_color;
|
||||||
|
|
|
@ -16,10 +16,10 @@
|
||||||
#include "common/hash.h"
|
#include "common/hash.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "core/hw/gpu.h"
|
#include "core/hw/gpu.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
#include "video_core/pica_types.h"
|
#include "video_core/pica_types.h"
|
||||||
#include "video_core/rasterizer_interface.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_rasterizer_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||||
#include "video_core/renderer_opengl/gl_state.h"
|
#include "video_core/renderer_opengl/gl_state.h"
|
||||||
|
@ -52,20 +52,20 @@ union PicaShaderConfig {
|
||||||
|
|
||||||
const auto& regs = Pica::g_state.regs;
|
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
|
state.alpha_test_func = regs.framebuffer.output_merger.alpha_test.enable
|
||||||
? regs.output_merger.alpha_test.func.Value()
|
? regs.framebuffer.output_merger.alpha_test.func.Value()
|
||||||
: Pica::Regs::CompareFunc::Always;
|
: Pica::FramebufferRegs::CompareFunc::Always;
|
||||||
|
|
||||||
state.texture0_type = regs.texture0.type;
|
state.texture0_type = regs.texturing.texture0.type;
|
||||||
|
|
||||||
// Copy relevant tev stages fields.
|
// Copy relevant tev stages fields.
|
||||||
// We don't sync const_color here because of the high variance, it is a
|
// We don't sync const_color here because of the high variance, it is a
|
||||||
// shader uniform instead.
|
// 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());
|
DEBUG_ASSERT(state.tev_stages.size() == tev_stages.size());
|
||||||
for (size_t i = 0; i < tev_stages.size(); i++) {
|
for (size_t i = 0; i < tev_stages.size(); i++) {
|
||||||
const auto& tev_stage = tev_stages[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.tev_stages[i].scales_raw = tev_stage.scales_raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.fog_mode = regs.fog_mode;
|
state.fog_mode = regs.texturing.fog_mode;
|
||||||
state.fog_flip = regs.fog_flip != 0;
|
state.fog_flip = regs.texturing.fog_flip != 0;
|
||||||
|
|
||||||
state.combiner_buffer_input = regs.tev_combiner_buffer_input.update_mask_rgb.Value() |
|
state.combiner_buffer_input =
|
||||||
regs.tev_combiner_buffer_input.update_mask_a.Value() << 4;
|
regs.texturing.tev_combiner_buffer_input.update_mask_rgb.Value() |
|
||||||
|
regs.texturing.tev_combiner_buffer_input.update_mask_a.Value() << 4;
|
||||||
|
|
||||||
// Fragment lighting
|
// Fragment lighting
|
||||||
|
|
||||||
|
@ -159,8 +160,8 @@ union PicaShaderConfig {
|
||||||
u32 modifiers_raw;
|
u32 modifiers_raw;
|
||||||
u32 ops_raw;
|
u32 ops_raw;
|
||||||
u32 scales_raw;
|
u32 scales_raw;
|
||||||
explicit operator Pica::Regs::TevStageConfig() const noexcept {
|
explicit operator Pica::TexturingRegs::TevStageConfig() const noexcept {
|
||||||
Pica::Regs::TevStageConfig stage;
|
Pica::TexturingRegs::TevStageConfig stage;
|
||||||
stage.sources_raw = sources_raw;
|
stage.sources_raw = sources_raw;
|
||||||
stage.modifiers_raw = modifiers_raw;
|
stage.modifiers_raw = modifiers_raw;
|
||||||
stage.ops_raw = ops_raw;
|
stage.ops_raw = ops_raw;
|
||||||
|
@ -171,14 +172,14 @@ union PicaShaderConfig {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
Pica::Regs::CompareFunc alpha_test_func;
|
Pica::FramebufferRegs::CompareFunc alpha_test_func;
|
||||||
Pica::Regs::ScissorMode scissor_test_mode;
|
Pica::RasterizerRegs::ScissorMode scissor_test_mode;
|
||||||
Pica::Regs::TextureConfig::TextureType texture0_type;
|
Pica::TexturingRegs::TextureConfig::TextureType texture0_type;
|
||||||
std::array<TevStageConfigRaw, 6> tev_stages;
|
std::array<TevStageConfigRaw, 6> tev_stages;
|
||||||
u8 combiner_buffer_input;
|
u8 combiner_buffer_input;
|
||||||
|
|
||||||
Pica::Regs::DepthBuffering depthmap_enable;
|
Pica::RasterizerRegs::DepthBuffering depthmap_enable;
|
||||||
Pica::Regs::FogMode fog_mode;
|
Pica::TexturingRegs::FogMode fog_mode;
|
||||||
bool fog_flip;
|
bool fog_flip;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -191,18 +192,18 @@ union PicaShaderConfig {
|
||||||
|
|
||||||
bool enable;
|
bool enable;
|
||||||
unsigned src_num;
|
unsigned src_num;
|
||||||
Pica::Regs::LightingBumpMode bump_mode;
|
Pica::LightingRegs::LightingBumpMode bump_mode;
|
||||||
unsigned bump_selector;
|
unsigned bump_selector;
|
||||||
bool bump_renorm;
|
bool bump_renorm;
|
||||||
bool clamp_highlights;
|
bool clamp_highlights;
|
||||||
|
|
||||||
Pica::Regs::LightingConfig config;
|
Pica::LightingRegs::LightingConfig config;
|
||||||
Pica::Regs::LightingFresnelSelector fresnel_selector;
|
Pica::LightingRegs::LightingFresnelSelector fresnel_selector;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool enable;
|
bool enable;
|
||||||
bool abs_input;
|
bool abs_input;
|
||||||
Pica::Regs::LightingLutInput type;
|
Pica::LightingRegs::LightingLutInput type;
|
||||||
float scale;
|
float scale;
|
||||||
} lut_d0, lut_d1, lut_fr, lut_rr, lut_rg, lut_rb;
|
} lut_d0, lut_d1, lut_fr, lut_rr, lut_rg, lut_rb;
|
||||||
} lighting;
|
} lighting;
|
||||||
|
@ -251,7 +252,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct SamplerInfo {
|
struct SamplerInfo {
|
||||||
using TextureConfig = Pica::Regs::TextureConfig;
|
using TextureConfig = Pica::TexturingRegs::TextureConfig;
|
||||||
|
|
||||||
OGLSampler sampler;
|
OGLSampler sampler;
|
||||||
|
|
||||||
|
@ -398,7 +399,7 @@ private:
|
||||||
void SyncCombinerColor();
|
void SyncCombinerColor();
|
||||||
|
|
||||||
/// Syncs the TEV constant color to match the PICA register
|
/// 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
|
/// Syncs the lighting global ambient color to match the PICA register
|
||||||
void SyncGlobalAmbient();
|
void SyncGlobalAmbient();
|
||||||
|
|
|
@ -342,7 +342,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
|
||||||
Pica::Texture::TextureInfo tex_info;
|
Pica::Texture::TextureInfo tex_info;
|
||||||
tex_info.width = params.width;
|
tex_info.width = params.width;
|
||||||
tex_info.height = params.height;
|
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.SetDefaultStride();
|
||||||
tex_info.physical_address = params.addr;
|
tex_info.physical_address = params.addr;
|
||||||
|
|
||||||
|
@ -510,7 +510,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurfaceRect(const CachedSurface& params
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(
|
CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(
|
||||||
const Pica::Regs::FullTextureConfig& config) {
|
const Pica::TexturingRegs::FullTextureConfig& config) {
|
||||||
|
|
||||||
Pica::Texture::TextureInfo info =
|
Pica::Texture::TextureInfo info =
|
||||||
Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format);
|
Pica::Texture::TextureInfo::FromPicaRegister(config.config, config.format);
|
||||||
|
@ -525,7 +525,9 @@ CachedSurface* RasterizerCacheOpenGL::GetTextureSurface(
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>>
|
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;
|
const auto& regs = Pica::g_state.regs;
|
||||||
|
|
||||||
// Make sur that framebuffers don't overlap if both color and depth are being used
|
// 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(),
|
config.GetColorBufferPhysicalAddress(),
|
||||||
fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())),
|
fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())),
|
||||||
config.GetDepthBufferPhysicalAddress(),
|
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_color_fb = config.GetColorBufferPhysicalAddress() != 0;
|
||||||
bool using_depth_fb = config.GetDepthBufferPhysicalAddress() != 0 &&
|
bool using_depth_fb =
|
||||||
(regs.output_merger.depth_test_enable ||
|
config.GetDepthBufferPhysicalAddress() != 0 &&
|
||||||
regs.output_merger.depth_write_enable || !framebuffers_overlap);
|
(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) {
|
if (framebuffers_overlap && using_color_fb && using_depth_fb) {
|
||||||
LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; "
|
LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; "
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hw/gpu.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"
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||||
|
|
||||||
namespace MathUtil {
|
namespace MathUtil {
|
||||||
|
@ -96,15 +96,15 @@ struct CachedSurface {
|
||||||
return bpp_table[(unsigned int)format];
|
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;
|
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;
|
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)
|
return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14)
|
||||||
: PixelFormat::Invalid;
|
: PixelFormat::Invalid;
|
||||||
}
|
}
|
||||||
|
@ -212,12 +212,12 @@ public:
|
||||||
bool load_if_create, MathUtil::Rectangle<int>& out_rect);
|
bool load_if_create, MathUtil::Rectangle<int>& out_rect);
|
||||||
|
|
||||||
/// Gets a surface based on the texture configuration
|
/// 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
|
/// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer
|
||||||
/// configuration
|
/// configuration
|
||||||
std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> GetFramebufferSurfaces(
|
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
|
/// Attempt to get a surface that exactly matches the fill region and format
|
||||||
CachedSurface* TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config);
|
CachedSurface* TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config);
|
||||||
|
|
|
@ -7,13 +7,15 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/logging/log.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_rasterizer.h"
|
||||||
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
||||||
#include "video_core/renderer_opengl/gl_shader_util.h"
|
#include "video_core/renderer_opengl/gl_shader_util.h"
|
||||||
|
|
||||||
using Pica::Regs;
|
using Pica::Regs;
|
||||||
using TevStageConfig = Regs::TevStageConfig;
|
using Pica::RasterizerRegs;
|
||||||
|
using Pica::LightingRegs;
|
||||||
|
using TevStageConfig = Pica::TexturingRegs::TevStageConfig;
|
||||||
|
|
||||||
namespace GLShader {
|
namespace GLShader {
|
||||||
|
|
||||||
|
@ -46,10 +48,10 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config,
|
||||||
case Source::Texture0:
|
case Source::Texture0:
|
||||||
// Only unit 0 respects the texturing type (according to 3DBrew)
|
// Only unit 0 respects the texturing type (according to 3DBrew)
|
||||||
switch (state.texture0_type) {
|
switch (state.texture0_type) {
|
||||||
case Pica::Regs::TextureConfig::Texture2D:
|
case Pica::TexturingRegs::TextureConfig::Texture2D:
|
||||||
out += "texture(tex[0], texcoord[0])";
|
out += "texture(tex[0], texcoord[0])";
|
||||||
break;
|
break;
|
||||||
case Pica::Regs::TextureConfig::Projection2D:
|
case Pica::TexturingRegs::TextureConfig::Projection2D:
|
||||||
out += "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))";
|
out += "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -276,8 +278,8 @@ static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation oper
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the if-statement condition used to evaluate alpha testing
|
/// Writes the if-statement condition used to evaluate alpha testing
|
||||||
static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) {
|
static void AppendAlphaTestCondition(std::string& out, Pica::FramebufferRegs::CompareFunc func) {
|
||||||
using CompareFunc = Regs::CompareFunc;
|
using CompareFunc = Pica::FramebufferRegs::CompareFunc;
|
||||||
switch (func) {
|
switch (func) {
|
||||||
case CompareFunc::Never:
|
case CompareFunc::Never:
|
||||||
out += "true";
|
out += "true";
|
||||||
|
@ -307,7 +309,7 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) {
|
||||||
/// Writes the code to emulate the specified TEV stage
|
/// Writes the code to emulate the specified TEV stage
|
||||||
static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) {
|
static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) {
|
||||||
const auto stage =
|
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)) {
|
if (!IsPassThroughTevStage(stage)) {
|
||||||
std::string index_name = std::to_string(index);
|
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";
|
"vec3 refl_value = vec3(0.0);\n";
|
||||||
|
|
||||||
// Compute fragment normals
|
// 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
|
// Bump mapping is enabled using a normal map, read perturbation vector from the selected
|
||||||
// texture
|
// texture
|
||||||
std::string bump_selector = std::to_string(lighting.bump_selector);
|
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))";
|
"(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))";
|
||||||
out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n";
|
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
|
// Bump mapping is enabled using a tangent map
|
||||||
LOG_CRITICAL(HW_GPU, "unimplemented bump mapping mode (tangent mapping)");
|
LOG_CRITICAL(HW_GPU, "unimplemented bump mapping mode (tangent mapping)");
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
|
@ -392,23 +394,24 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
|
||||||
out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n";
|
out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n";
|
||||||
|
|
||||||
// Gets the index into the specified lookup table for specular lighting
|
// 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)";
|
const std::string half_angle = "normalize(normalize(view) + light_vector)";
|
||||||
std::string index;
|
std::string index;
|
||||||
switch (input) {
|
switch (input) {
|
||||||
case Regs::LightingLutInput::NH:
|
case LightingRegs::LightingLutInput::NH:
|
||||||
index = "dot(normal, " + half_angle + ")";
|
index = "dot(normal, " + half_angle + ")";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::LightingLutInput::VH:
|
case LightingRegs::LightingLutInput::VH:
|
||||||
index = std::string("dot(normalize(view), " + half_angle + ")");
|
index = std::string("dot(normalize(view), " + half_angle + ")");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::LightingLutInput::NV:
|
case LightingRegs::LightingLutInput::NV:
|
||||||
index = std::string("dot(normal, normalize(view))");
|
index = std::string("dot(normal, normalize(view))");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Regs::LightingLutInput::LN:
|
case LightingRegs::LightingLutInput::LN:
|
||||||
index = std::string("dot(light_vector, normal)");
|
index = std::string("dot(light_vector, normal)");
|
||||||
break;
|
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
|
// 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) + "], " +
|
return std::string("texture(lut[" + std::to_string((unsigned)sampler / 4) + "], " +
|
||||||
lut_index + ")[" + std::to_string((unsigned)sampler & 3) + "]");
|
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)";
|
light_src + ".position) + " + light_src + ".dist_atten_bias)";
|
||||||
index = "(OFFSET_256 + SCALE_256 * clamp(" + index + ", 0.0, 1.0))";
|
index = "(OFFSET_256 + SCALE_256 * clamp(" + index + ", 0.0, 1.0))";
|
||||||
const unsigned lut_num =
|
const unsigned lut_num =
|
||||||
((unsigned)Regs::LightingSampler::DistanceAttenuation + light_config.num);
|
((unsigned)LightingRegs::LightingSampler::DistanceAttenuation + light_config.num);
|
||||||
dist_atten = GetLutValue((Regs::LightingSampler)lut_num, index);
|
dist_atten = GetLutValue((LightingRegs::LightingSampler)lut_num, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If enabled, clamp specular component if lighting result is negative
|
// 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
|
// Specular 0 component
|
||||||
std::string d0_lut_value = "1.0";
|
std::string d0_lut_value = "1.0";
|
||||||
if (lighting.lut_d0.enable &&
|
if (lighting.lut_d0.enable &&
|
||||||
Pica::Regs::IsLightingSamplerSupported(lighting.config,
|
LightingRegs::IsLightingSamplerSupported(
|
||||||
Pica::Regs::LightingSampler::Distribution0)) {
|
lighting.config, LightingRegs::LightingSampler::Distribution0)) {
|
||||||
// Lookup specular "distribution 0" LUT value
|
// Lookup specular "distribution 0" LUT value
|
||||||
std::string index =
|
std::string index =
|
||||||
GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input);
|
GetLutIndex(light_config.num, lighting.lut_d0.type, lighting.lut_d0.abs_input);
|
||||||
d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " +
|
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)";
|
std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)";
|
||||||
|
|
||||||
// If enabled, lookup ReflectRed value, otherwise, 1.0 is used
|
// If enabled, lookup ReflectRed value, otherwise, 1.0 is used
|
||||||
if (lighting.lut_rr.enable &&
|
if (lighting.lut_rr.enable &&
|
||||||
Pica::Regs::IsLightingSamplerSupported(lighting.config,
|
LightingRegs::IsLightingSamplerSupported(lighting.config,
|
||||||
Pica::Regs::LightingSampler::ReflectRed)) {
|
LightingRegs::LightingSampler::ReflectRed)) {
|
||||||
std::string index =
|
std::string index =
|
||||||
GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input);
|
GetLutIndex(light_config.num, lighting.lut_rr.type, lighting.lut_rr.abs_input);
|
||||||
std::string value = "(" + std::to_string(lighting.lut_rr.scale) + " * " +
|
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";
|
out += "refl_value.r = " + value + ";\n";
|
||||||
} else {
|
} else {
|
||||||
out += "refl_value.r = 1.0;\n";
|
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 enabled, lookup ReflectGreen value, otherwise, ReflectRed value is used
|
||||||
if (lighting.lut_rg.enable &&
|
if (lighting.lut_rg.enable &&
|
||||||
Pica::Regs::IsLightingSamplerSupported(lighting.config,
|
LightingRegs::IsLightingSamplerSupported(lighting.config,
|
||||||
Pica::Regs::LightingSampler::ReflectGreen)) {
|
LightingRegs::LightingSampler::ReflectGreen)) {
|
||||||
std::string index =
|
std::string index =
|
||||||
GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input);
|
GetLutIndex(light_config.num, lighting.lut_rg.type, lighting.lut_rg.abs_input);
|
||||||
std::string value = "(" + std::to_string(lighting.lut_rg.scale) + " * " +
|
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";
|
out += "refl_value.g = " + value + ";\n";
|
||||||
} else {
|
} else {
|
||||||
out += "refl_value.g = refl_value.r;\n";
|
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 enabled, lookup ReflectBlue value, otherwise, ReflectRed value is used
|
||||||
if (lighting.lut_rb.enable &&
|
if (lighting.lut_rb.enable &&
|
||||||
Pica::Regs::IsLightingSamplerSupported(lighting.config,
|
LightingRegs::IsLightingSamplerSupported(lighting.config,
|
||||||
Pica::Regs::LightingSampler::ReflectBlue)) {
|
LightingRegs::LightingSampler::ReflectBlue)) {
|
||||||
std::string index =
|
std::string index =
|
||||||
GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input);
|
GetLutIndex(light_config.num, lighting.lut_rb.type, lighting.lut_rb.abs_input);
|
||||||
std::string value = "(" + std::to_string(lighting.lut_rb.scale) + " * " +
|
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";
|
out += "refl_value.b = " + value + ";\n";
|
||||||
} else {
|
} else {
|
||||||
out += "refl_value.b = refl_value.r;\n";
|
out += "refl_value.b = refl_value.r;\n";
|
||||||
|
@ -524,35 +529,39 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
|
||||||
// Specular 1 component
|
// Specular 1 component
|
||||||
std::string d1_lut_value = "1.0";
|
std::string d1_lut_value = "1.0";
|
||||||
if (lighting.lut_d1.enable &&
|
if (lighting.lut_d1.enable &&
|
||||||
Pica::Regs::IsLightingSamplerSupported(lighting.config,
|
LightingRegs::IsLightingSamplerSupported(
|
||||||
Pica::Regs::LightingSampler::Distribution1)) {
|
lighting.config, LightingRegs::LightingSampler::Distribution1)) {
|
||||||
// Lookup specular "distribution 1" LUT value
|
// Lookup specular "distribution 1" LUT value
|
||||||
std::string index =
|
std::string index =
|
||||||
GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input);
|
GetLutIndex(light_config.num, lighting.lut_d1.type, lighting.lut_d1.abs_input);
|
||||||
d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " +
|
d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " +
|
||||||
GetLutValue(Regs::LightingSampler::Distribution1, index) + ")";
|
GetLutValue(LightingRegs::LightingSampler::Distribution1, index) + ")";
|
||||||
}
|
}
|
||||||
std::string specular_1 =
|
std::string specular_1 =
|
||||||
"(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)";
|
"(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)";
|
||||||
|
|
||||||
// Fresnel
|
// Fresnel
|
||||||
if (lighting.lut_fr.enable && Pica::Regs::IsLightingSamplerSupported(
|
if (lighting.lut_fr.enable &&
|
||||||
lighting.config, Pica::Regs::LightingSampler::Fresnel)) {
|
LightingRegs::IsLightingSamplerSupported(lighting.config,
|
||||||
|
LightingRegs::LightingSampler::Fresnel)) {
|
||||||
// Lookup fresnel LUT value
|
// Lookup fresnel LUT value
|
||||||
std::string index =
|
std::string index =
|
||||||
GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input);
|
GetLutIndex(light_config.num, lighting.lut_fr.type, lighting.lut_fr.abs_input);
|
||||||
std::string value = "(" + std::to_string(lighting.lut_fr.scale) + " * " +
|
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
|
// Enabled for difffuse lighting alpha component
|
||||||
if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::PrimaryAlpha ||
|
if (lighting.fresnel_selector == LightingRegs::LightingFresnelSelector::PrimaryAlpha ||
|
||||||
lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
|
lighting.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) {
|
||||||
out += "diffuse_sum.a *= " + value + ";\n";
|
out += "diffuse_sum.a *= " + value + ";\n";
|
||||||
|
}
|
||||||
|
|
||||||
// Enabled for the specular lighting alpha component
|
// Enabled for the specular lighting alpha component
|
||||||
if (lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::SecondaryAlpha ||
|
if (lighting.fresnel_selector ==
|
||||||
lighting.fresnel_selector == Pica::Regs::LightingFresnelSelector::Both)
|
LightingRegs::LightingFresnelSelector::SecondaryAlpha ||
|
||||||
|
lighting.fresnel_selector == LightingRegs::LightingFresnelSelector::Both) {
|
||||||
out += "specular_sum.a *= " + value + ";\n";
|
out += "specular_sum.a *= " + value + ";\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute primary fragment color (diffuse lighting) function
|
// 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
|
// 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; }";
|
out += "discard; }";
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the scissor test
|
// Append the scissor test
|
||||||
if (state.scissor_test_mode != Regs::ScissorMode::Disabled) {
|
if (state.scissor_test_mode != RasterizerRegs::ScissorMode::Disabled) {
|
||||||
out += "if (";
|
out += "if (";
|
||||||
// Negate the condition if we have to keep only the pixels outside the scissor box
|
// 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 += "!";
|
||||||
out += "(gl_FragCoord.x >= scissor_x1 && "
|
out += "(gl_FragCoord.x >= scissor_x1 && "
|
||||||
"gl_FragCoord.y >= scissor_y1 && "
|
"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 z_over_w = 1.0 - gl_FragCoord.z * 2.0;\n";
|
||||||
out += "float depth = z_over_w * depth_scale + depth_offset;\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";
|
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)
|
for (size_t index = 0; index < state.tev_stages.size(); ++index)
|
||||||
WriteTevStage(out, config, (unsigned)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 (";
|
out += "if (";
|
||||||
AppendAlphaTestCondition(out, state.alpha_test_func);
|
AppendAlphaTestCondition(out, state.alpha_test_func);
|
||||||
out += ") discard;\n";
|
out += ") discard;\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append fog combiner
|
// Append fog combiner
|
||||||
if (state.fog_mode == Regs::FogMode::Fog) {
|
if (state.fog_mode == Pica::TexturingRegs::FogMode::Fog) {
|
||||||
// Get index into fog LUT
|
// Get index into fog LUT
|
||||||
if (state.fog_flip) {
|
if (state.fog_flip) {
|
||||||
out += "float fog_index = (1.0 - depth) * 128.0;\n";
|
out += "float fog_index = (1.0 - depth) * 128.0;\n";
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "video_core/pica.h"
|
#include "video_core/regs.h"
|
||||||
|
|
||||||
using GLvec2 = std::array<GLfloat, 2>;
|
using GLvec2 = std::array<GLfloat, 2>;
|
||||||
using GLvec3 = std::array<GLfloat, 3>;
|
using GLvec3 = std::array<GLfloat, 3>;
|
||||||
|
@ -20,7 +20,7 @@ using GLvec4 = std::array<GLfloat, 4>;
|
||||||
|
|
||||||
namespace PicaToGL {
|
namespace PicaToGL {
|
||||||
|
|
||||||
inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) {
|
inline GLenum TextureFilterMode(Pica::TexturingRegs::TextureConfig::TextureFilter mode) {
|
||||||
static const GLenum filter_mode_table[] = {
|
static const GLenum filter_mode_table[] = {
|
||||||
GL_NEAREST, // TextureFilter::Nearest
|
GL_NEAREST, // TextureFilter::Nearest
|
||||||
GL_LINEAR, // TextureFilter::Linear
|
GL_LINEAR, // TextureFilter::Linear
|
||||||
|
@ -47,7 +47,7 @@ inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) {
|
||||||
return gl_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[] = {
|
static const GLenum wrap_mode_table[] = {
|
||||||
GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge
|
GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge
|
||||||
GL_CLAMP_TO_BORDER, // WrapMode::ClampToBorder
|
GL_CLAMP_TO_BORDER, // WrapMode::ClampToBorder
|
||||||
|
@ -76,7 +76,7 @@ inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) {
|
||||||
return gl_mode;
|
return gl_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline GLenum BlendEquation(Pica::Regs::BlendEquation equation) {
|
inline GLenum BlendEquation(Pica::FramebufferRegs::BlendEquation equation) {
|
||||||
static const GLenum blend_equation_table[] = {
|
static const GLenum blend_equation_table[] = {
|
||||||
GL_FUNC_ADD, // BlendEquation::Add
|
GL_FUNC_ADD, // BlendEquation::Add
|
||||||
GL_FUNC_SUBTRACT, // BlendEquation::Subtract
|
GL_FUNC_SUBTRACT, // BlendEquation::Subtract
|
||||||
|
@ -96,7 +96,7 @@ inline GLenum BlendEquation(Pica::Regs::BlendEquation equation) {
|
||||||
return blend_equation_table[(unsigned)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[] = {
|
static const GLenum blend_func_table[] = {
|
||||||
GL_ZERO, // BlendFactor::Zero
|
GL_ZERO, // BlendFactor::Zero
|
||||||
GL_ONE, // BlendFactor::One
|
GL_ONE, // BlendFactor::One
|
||||||
|
@ -126,7 +126,7 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) {
|
||||||
return blend_func_table[(unsigned)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[] = {
|
static const GLenum logic_op_table[] = {
|
||||||
GL_CLEAR, // Clear
|
GL_CLEAR, // Clear
|
||||||
GL_AND, // And
|
GL_AND, // And
|
||||||
|
@ -157,7 +157,7 @@ inline GLenum LogicOp(Pica::Regs::LogicOp op) {
|
||||||
return logic_op_table[(unsigned)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[] = {
|
static const GLenum compare_func_table[] = {
|
||||||
GL_NEVER, // CompareFunc::Never
|
GL_NEVER, // CompareFunc::Never
|
||||||
GL_ALWAYS, // CompareFunc::Always
|
GL_ALWAYS, // CompareFunc::Always
|
||||||
|
@ -180,7 +180,7 @@ inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
|
||||||
return compare_func_table[(unsigned)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[] = {
|
static const GLenum stencil_op_table[] = {
|
||||||
GL_KEEP, // StencilAction::Keep
|
GL_KEEP, // StencilAction::Keep
|
||||||
GL_ZERO, // StencilAction::Zero
|
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 {{
|
return {{
|
||||||
color.r / 255.0f, color.g / 255.0f, color.b / 255.0f,
|
color.r / 255.0f, color.g / 255.0f, color.b / 255.0f,
|
||||||
}};
|
}};
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
#include "common/bit_set.h"
|
#include "common/bit_set.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/microprofile.h"
|
#include "common/microprofile.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
|
#include "video_core/regs.h"
|
||||||
#include "video_core/shader/shader.h"
|
#include "video_core/shader/shader.h"
|
||||||
#include "video_core/shader/shader_interpreter.h"
|
#include "video_core/shader/shader_interpreter.h"
|
||||||
#ifdef ARCHITECTURE_x86_64
|
#ifdef ARCHITECTURE_x86_64
|
||||||
|
@ -20,7 +20,7 @@ namespace Pica {
|
||||||
|
|
||||||
namespace Shader {
|
namespace Shader {
|
||||||
|
|
||||||
OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer& input) {
|
OutputVertex OutputVertex::FromAttributeBuffer(const RasterizerRegs& regs, AttributeBuffer& input) {
|
||||||
// Setup output data
|
// Setup output data
|
||||||
union {
|
union {
|
||||||
OutputVertex ret{};
|
OutputVertex ret{};
|
||||||
|
@ -33,16 +33,16 @@ OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer
|
||||||
for (unsigned int i = 0; i < num_attributes; ++i) {
|
for (unsigned int i = 0; i < num_attributes; ++i) {
|
||||||
const auto& output_register_map = regs.vs_output_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_x, output_register_map.map_y, output_register_map.map_z,
|
||||||
output_register_map.map_w};
|
output_register_map.map_w};
|
||||||
|
|
||||||
for (unsigned comp = 0; comp < 4; ++comp) {
|
for (unsigned comp = 0; comp < 4; ++comp) {
|
||||||
Regs::VSOutputAttributes::Semantic semantic = semantics[comp];
|
RasterizerRegs::VSOutputAttributes::Semantic semantic = semantics[comp];
|
||||||
float24* out = &vertex_slots[semantic];
|
float24* out = &vertex_slots[semantic];
|
||||||
if (semantic < vertex_slots.size()) {
|
if (semantic < vertex_slots.size()) {
|
||||||
*out = input.attr[i][comp];
|
*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);
|
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;
|
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;
|
const unsigned max_attribute = config.max_input_attribute_index;
|
||||||
|
|
||||||
for (unsigned attr = 0; attr <= max_attribute; ++attr) {
|
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;
|
unsigned int output_i = 0;
|
||||||
for (unsigned int reg : Common::BitSet<u32>(config.output_mask)) {
|
for (unsigned int reg : Common::BitSet<u32>(config.output_mask)) {
|
||||||
output.attr[output_i++] = registers.output[reg];
|
output.attr[output_i++] = registers.output[reg];
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/pica_types.h"
|
#include "video_core/pica_types.h"
|
||||||
|
#include "video_core/regs.h"
|
||||||
|
|
||||||
using nihstro::RegisterType;
|
using nihstro::RegisterType;
|
||||||
using nihstro::SourceRegister;
|
using nihstro::SourceRegister;
|
||||||
|
@ -39,19 +39,19 @@ struct OutputVertex {
|
||||||
INSERT_PADDING_WORDS(1);
|
INSERT_PADDING_WORDS(1);
|
||||||
Math::Vec2<float24> tc2;
|
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) \
|
#define ASSERT_POS(var, pos) \
|
||||||
static_assert(offsetof(OutputVertex, var) == pos * sizeof(float24), "Semantic at wrong " \
|
static_assert(offsetof(OutputVertex, var) == pos * sizeof(float24), "Semantic at wrong " \
|
||||||
"offset.")
|
"offset.")
|
||||||
ASSERT_POS(pos, Regs::VSOutputAttributes::POSITION_X);
|
ASSERT_POS(pos, RasterizerRegs::VSOutputAttributes::POSITION_X);
|
||||||
ASSERT_POS(quat, Regs::VSOutputAttributes::QUATERNION_X);
|
ASSERT_POS(quat, RasterizerRegs::VSOutputAttributes::QUATERNION_X);
|
||||||
ASSERT_POS(color, Regs::VSOutputAttributes::COLOR_R);
|
ASSERT_POS(color, RasterizerRegs::VSOutputAttributes::COLOR_R);
|
||||||
ASSERT_POS(tc0, Regs::VSOutputAttributes::TEXCOORD0_U);
|
ASSERT_POS(tc0, RasterizerRegs::VSOutputAttributes::TEXCOORD0_U);
|
||||||
ASSERT_POS(tc1, Regs::VSOutputAttributes::TEXCOORD1_U);
|
ASSERT_POS(tc1, RasterizerRegs::VSOutputAttributes::TEXCOORD1_U);
|
||||||
ASSERT_POS(tc0_w, Regs::VSOutputAttributes::TEXCOORD0_W);
|
ASSERT_POS(tc0_w, RasterizerRegs::VSOutputAttributes::TEXCOORD0_W);
|
||||||
ASSERT_POS(view, Regs::VSOutputAttributes::VIEW_X);
|
ASSERT_POS(view, RasterizerRegs::VSOutputAttributes::VIEW_X);
|
||||||
ASSERT_POS(tc2, Regs::VSOutputAttributes::TEXCOORD2_U);
|
ASSERT_POS(tc2, RasterizerRegs::VSOutputAttributes::TEXCOORD2_U);
|
||||||
#undef ASSERT_POS
|
#undef ASSERT_POS
|
||||||
static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
|
static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
|
||||||
static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size");
|
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 config Shader configuration registers corresponding to the unit.
|
||||||
* @param input Attribute buffer to load into the input registers.
|
* @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 {
|
struct ShaderSetup {
|
||||||
|
|
|
@ -669,7 +669,7 @@ void InterpreterEngine::Run(const ShaderSetup& setup, UnitState& state) const {
|
||||||
|
|
||||||
DebugData<true> InterpreterEngine::ProduceDebugInfo(const ShaderSetup& setup,
|
DebugData<true> InterpreterEngine::ProduceDebugInfo(const ShaderSetup& setup,
|
||||||
const AttributeBuffer& input,
|
const AttributeBuffer& input,
|
||||||
const Regs::ShaderConfig& config) const {
|
const ShaderRegs& config) const {
|
||||||
UnitState state;
|
UnitState state;
|
||||||
DebugData<true> debug_data;
|
DebugData<true> debug_data;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ public:
|
||||||
* @return Debug information for this shader with regards to the given vertex
|
* @return Debug information for this shader with regards to the given vertex
|
||||||
*/
|
*/
|
||||||
DebugData<true> ProduceDebugInfo(const ShaderSetup& setup, const AttributeBuffer& input,
|
DebugData<true> ProduceDebugInfo(const ShaderSetup& setup, const AttributeBuffer& input,
|
||||||
const Regs::ShaderConfig& config) const;
|
const ShaderRegs& config) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -10,12 +10,12 @@
|
||||||
#include "common/math_util.h"
|
#include "common/math_util.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "common/vector_math.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/etc1.h"
|
||||||
#include "video_core/texture/texture_decode.h"
|
#include "video_core/texture/texture_decode.h"
|
||||||
#include "video_core/utils.h"
|
#include "video_core/utils.h"
|
||||||
|
|
||||||
using TextureFormat = Pica::Regs::TextureFormat;
|
using TextureFormat = Pica::TexturingRegs::TextureFormat;
|
||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
namespace Texture {
|
namespace Texture {
|
||||||
|
@ -82,32 +82,32 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
|
||||||
using VideoCore::MortonInterleave;
|
using VideoCore::MortonInterleave;
|
||||||
|
|
||||||
switch (info.format) {
|
switch (info.format) {
|
||||||
case Regs::TextureFormat::RGBA8: {
|
case TextureFormat::RGBA8: {
|
||||||
auto res = Color::DecodeRGBA8(source + MortonInterleave(x, y) * 4);
|
auto res = Color::DecodeRGBA8(source + MortonInterleave(x, y) * 4);
|
||||||
return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
|
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);
|
auto res = Color::DecodeRGB8(source + MortonInterleave(x, y) * 3);
|
||||||
return {res.r(), res.g(), res.b(), 255};
|
return {res.r(), res.g(), res.b(), 255};
|
||||||
}
|
}
|
||||||
|
|
||||||
case Regs::TextureFormat::RGB5A1: {
|
case TextureFormat::RGB5A1: {
|
||||||
auto res = Color::DecodeRGB5A1(source + MortonInterleave(x, y) * 2);
|
auto res = Color::DecodeRGB5A1(source + MortonInterleave(x, y) * 2);
|
||||||
return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
|
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);
|
auto res = Color::DecodeRGB565(source + MortonInterleave(x, y) * 2);
|
||||||
return {res.r(), res.g(), res.b(), 255};
|
return {res.r(), res.g(), res.b(), 255};
|
||||||
}
|
}
|
||||||
|
|
||||||
case Regs::TextureFormat::RGBA4: {
|
case TextureFormat::RGBA4: {
|
||||||
auto res = Color::DecodeRGBA4(source + MortonInterleave(x, y) * 2);
|
auto res = Color::DecodeRGBA4(source + MortonInterleave(x, y) * 2);
|
||||||
return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
|
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;
|
const u8* source_ptr = source + MortonInterleave(x, y) * 2;
|
||||||
|
|
||||||
if (disable_alpha) {
|
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);
|
auto res = Color::DecodeRG8(source + MortonInterleave(x, y) * 2);
|
||||||
return {res.r(), res.g(), 0, 255};
|
return {res.r(), res.g(), 0, 255};
|
||||||
}
|
}
|
||||||
|
|
||||||
case Regs::TextureFormat::I8: {
|
case TextureFormat::I8: {
|
||||||
const u8* source_ptr = source + MortonInterleave(x, y);
|
const u8* source_ptr = source + MortonInterleave(x, y);
|
||||||
return {*source_ptr, *source_ptr, *source_ptr, 255};
|
return {*source_ptr, *source_ptr, *source_ptr, 255};
|
||||||
}
|
}
|
||||||
|
|
||||||
case Regs::TextureFormat::A8: {
|
case TextureFormat::A8: {
|
||||||
const u8* source_ptr = source + MortonInterleave(x, y);
|
const u8* source_ptr = source + MortonInterleave(x, y);
|
||||||
|
|
||||||
if (disable_alpha) {
|
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);
|
const u8* source_ptr = source + MortonInterleave(x, y);
|
||||||
|
|
||||||
u8 i = Color::Convert4To8(((*source_ptr) & 0xF0) >> 4);
|
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);
|
u32 morton_offset = MortonInterleave(x, y);
|
||||||
const u8* source_ptr = source + morton_offset / 2;
|
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};
|
return {i, i, i, 255};
|
||||||
}
|
}
|
||||||
|
|
||||||
case Regs::TextureFormat::A4: {
|
case TextureFormat::A4: {
|
||||||
u32 morton_offset = MortonInterleave(x, y);
|
u32 morton_offset = MortonInterleave(x, y);
|
||||||
const u8* source_ptr = source + morton_offset / 2;
|
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 TextureFormat::ETC1:
|
||||||
case Regs::TextureFormat::ETC1A4: {
|
case TextureFormat::ETC1A4: {
|
||||||
bool has_alpha = (info.format == Regs::TextureFormat::ETC1A4);
|
bool has_alpha = (info.format == TextureFormat::ETC1A4);
|
||||||
size_t subtile_size = has_alpha ? 16 : 8;
|
size_t subtile_size = has_alpha ? 16 : 8;
|
||||||
|
|
||||||
// ETC1 further subdivides each 8x8 tile into four 4x4 subtiles
|
// 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,
|
TextureInfo TextureInfo::FromPicaRegister(const TexturingRegs::TextureConfig& config,
|
||||||
const Regs::TextureFormat& format) {
|
const TexturingRegs::TextureFormat& format) {
|
||||||
TextureInfo info;
|
TextureInfo info;
|
||||||
info.physical_address = config.GetPhysicalAddress();
|
info.physical_address = config.GetPhysicalAddress();
|
||||||
info.width = config.width;
|
info.width = config.width;
|
||||||
|
|
|
@ -6,27 +6,27 @@
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "video_core/pica.h"
|
#include "video_core/regs_texturing.h"
|
||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
namespace Texture {
|
namespace Texture {
|
||||||
|
|
||||||
/// Returns the byte size of a 8*8 tile of the specified texture format.
|
/// 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 {
|
struct TextureInfo {
|
||||||
PAddr physical_address;
|
PAddr physical_address;
|
||||||
unsigned int width;
|
unsigned int width;
|
||||||
unsigned int height;
|
unsigned int height;
|
||||||
ptrdiff_t stride;
|
ptrdiff_t stride;
|
||||||
Pica::Regs::TextureFormat format;
|
TexturingRegs::TextureFormat format;
|
||||||
|
|
||||||
static TextureInfo FromPicaRegister(const Pica::Regs::TextureConfig& config,
|
static TextureInfo FromPicaRegister(const TexturingRegs::TextureConfig& config,
|
||||||
const Pica::Regs::TextureFormat& format);
|
const TexturingRegs::TextureFormat& format);
|
||||||
|
|
||||||
/// Calculates stride from format and width, assuming that the entire texture is contiguous.
|
/// Calculates stride from format and width, assuming that the entire texture is contiguous.
|
||||||
void SetDefaultStride() {
|
void SetDefaultStride() {
|
||||||
stride = Pica::Texture::CalculateTileSize(format) * (width / 8);
|
stride = CalculateTileSize(format) * (width / 8);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,15 +8,15 @@
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
#include "video_core/debug_utils/debug_utils.h"
|
||||||
#include "video_core/pica.h"
|
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
#include "video_core/pica_types.h"
|
#include "video_core/pica_types.h"
|
||||||
|
#include "video_core/regs_pipeline.h"
|
||||||
#include "video_core/shader/shader.h"
|
#include "video_core/shader/shader.h"
|
||||||
#include "video_core/vertex_loader.h"
|
#include "video_core/vertex_loader.h"
|
||||||
|
|
||||||
namespace Pica {
|
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.");
|
ASSERT_MSG(!is_setup, "VertexLoader is not intended to be setup more than once.");
|
||||||
|
|
||||||
const auto& attribute_config = regs.vertex_attributes;
|
const auto& attribute_config = regs.vertex_attributes;
|
||||||
|
@ -85,15 +85,16 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex,
|
||||||
memory_accesses.AddAccess(
|
memory_accesses.AddAccess(
|
||||||
source_addr,
|
source_addr,
|
||||||
vertex_attribute_elements[i] *
|
vertex_attribute_elements[i] *
|
||||||
((vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT)
|
((vertex_attribute_formats[i] == PipelineRegs::VertexAttributeFormat::FLOAT)
|
||||||
? 4
|
? 4
|
||||||
: (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT)
|
: (vertex_attribute_formats[i] ==
|
||||||
|
PipelineRegs::VertexAttributeFormat::SHORT)
|
||||||
? 2
|
? 2
|
||||||
: 1));
|
: 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (vertex_attribute_formats[i]) {
|
switch (vertex_attribute_formats[i]) {
|
||||||
case Regs::VertexAttributeFormat::BYTE: {
|
case PipelineRegs::VertexAttributeFormat::BYTE: {
|
||||||
const s8* srcdata =
|
const s8* srcdata =
|
||||||
reinterpret_cast<const s8*>(Memory::GetPhysicalPointer(source_addr));
|
reinterpret_cast<const s8*>(Memory::GetPhysicalPointer(source_addr));
|
||||||
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case Regs::VertexAttributeFormat::UBYTE: {
|
case PipelineRegs::VertexAttributeFormat::UBYTE: {
|
||||||
const u8* srcdata =
|
const u8* srcdata =
|
||||||
reinterpret_cast<const u8*>(Memory::GetPhysicalPointer(source_addr));
|
reinterpret_cast<const u8*>(Memory::GetPhysicalPointer(source_addr));
|
||||||
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case Regs::VertexAttributeFormat::SHORT: {
|
case PipelineRegs::VertexAttributeFormat::SHORT: {
|
||||||
const s16* srcdata =
|
const s16* srcdata =
|
||||||
reinterpret_cast<const s16*>(Memory::GetPhysicalPointer(source_addr));
|
reinterpret_cast<const s16*>(Memory::GetPhysicalPointer(source_addr));
|
||||||
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case Regs::VertexAttributeFormat::FLOAT: {
|
case PipelineRegs::VertexAttributeFormat::FLOAT: {
|
||||||
const float* srcdata =
|
const float* srcdata =
|
||||||
reinterpret_cast<const float*>(Memory::GetPhysicalPointer(source_addr));
|
reinterpret_cast<const float*>(Memory::GetPhysicalPointer(source_addr));
|
||||||
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
|
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/pica.h"
|
#include "video_core/regs_pipeline.h"
|
||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
|
|
||||||
|
@ -17,11 +17,11 @@ struct AttributeBuffer;
|
||||||
class VertexLoader {
|
class VertexLoader {
|
||||||
public:
|
public:
|
||||||
VertexLoader() = default;
|
VertexLoader() = default;
|
||||||
explicit VertexLoader(const Pica::Regs& regs) {
|
explicit VertexLoader(const PipelineRegs& regs) {
|
||||||
Setup(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,
|
void LoadVertex(u32 base_address, int index, int vertex, Shader::AttributeBuffer& input,
|
||||||
DebugUtils::MemoryAccessTracker& memory_accesses);
|
DebugUtils::MemoryAccessTracker& memory_accesses);
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ public:
|
||||||
private:
|
private:
|
||||||
std::array<u32, 16> vertex_attribute_sources;
|
std::array<u32, 16> vertex_attribute_sources;
|
||||||
std::array<u32, 16> vertex_attribute_strides{};
|
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<u32, 16> vertex_attribute_elements{};
|
||||||
std::array<bool, 16> vertex_attribute_is_default;
|
std::array<bool, 16> vertex_attribute_is_default;
|
||||||
int num_total_attributes = 0;
|
int num_total_attributes = 0;
|
||||||
|
|
Loading…
Reference in a new issue