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