From 81004211dda74390c02973c37e89215f5ff8829b Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sat, 5 Mar 2016 14:49:23 -0800 Subject: Pica: Improve accuracy of immediate-mode support This partially fixes Etrian Odyssey IV. --- src/video_core/command_processor.cpp | 46 ++++++++++++++++++++---------------- src/video_core/pica.cpp | 15 +++++++++++- src/video_core/pica.h | 7 +++++- src/video_core/pica_state.h | 15 +++++++----- src/video_core/primitive_assembly.h | 2 +- 5 files changed, 56 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 4b59984ad..028b59348 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -75,12 +75,17 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D); break; + case PICA_REG_INDEX_WORKAROUND(triangle_topology, 0x25E): + g_state.primitive_assembler.Reconfigure(regs.triangle_topology); + break; + + case PICA_REG_INDEX_WORKAROUND(restart_primitive, 0x25F): + g_state.primitive_assembler.Reset(); + break; + case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.index, 0x232): - if (regs.vs_default_attributes_setup.index == 15) { - // Reset immediate primitive state - g_state.immediate.primitive_assembler.Reconfigure(regs.triangle_topology); - g_state.immediate.attribute_id = 0; - } + g_state.immediate.current_attribute = 0; + default_attr_counter = 0; break; // Load default vertex input attributes @@ -105,7 +110,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { break; } - Math::Vec4& attribute = g_state.vs.default_attributes[setup.index]; + Math::Vec4 attribute; // NOTE: The destination component order indeed is "backwards" attribute.w = float24::FromRaw(default_attr_write_buffer[0] >> 8); @@ -119,26 +124,29 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { // TODO: Verify that this actually modifies the register! if (setup.index < 15) { + g_state.vs.default_attributes[setup.index] = attribute; setup.index++; } else { // Put each attribute into an immediate input buffer. // When all specified immediate attributes are present, the Vertex Shader is invoked and everything is // sent to the primitive assembler. - auto& immediate_input = g_state.immediate.input; - auto& immediate_attribute_id = g_state.immediate.attribute_id; - const auto& attribute_config = regs.vertex_attributes; + auto& immediate_input = g_state.immediate.input_vertex; + auto& immediate_attribute_id = g_state.immediate.current_attribute; immediate_input.attr[immediate_attribute_id++] = attribute; - if (immediate_attribute_id >= attribute_config.GetNumTotalAttributes()) { + if (immediate_attribute_id >= regs.vs.num_input_attributes+1) { immediate_attribute_id = 0; Shader::UnitState shader_unit; Shader::Setup(shader_unit); + if (g_debug_context) + g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, static_cast(&immediate_input)); + // Send to vertex shader - Shader::OutputVertex output = Shader::Run(shader_unit, immediate_input, attribute_config.GetNumTotalAttributes()); + Shader::OutputVertex output = Shader::Run(shader_unit, immediate_input, regs.vs.num_input_attributes+1); // Send to renderer using Pica::Shader::OutputVertex; @@ -146,7 +154,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { VideoCore::g_renderer->Rasterizer()->AddTriangle(v0, v1, v2); }; - g_state.immediate.primitive_assembler.SubmitVertex(output, AddTriangle); + g_state.primitive_assembler.SubmitVertex(output, AddTriangle); } } } @@ -154,9 +162,13 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { } case PICA_REG_INDEX(gpu_mode): - if (regs.gpu_mode == Regs::GPUMode::Configuring && regs.vs_default_attributes_setup.index == 15) { + if (regs.gpu_mode == Regs::GPUMode::Configuring) { // Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring VideoCore::g_renderer->Rasterizer()->DrawTriangles(); + + if (g_debug_context) { + g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); + } } break; @@ -241,7 +253,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { DebugUtils::GeometryDumper geometry_dumper; PrimitiveAssembler dumping_primitive_assembler(regs.triangle_topology.Value()); #endif - PrimitiveAssembler primitive_assembler(regs.triangle_topology.Value()); + PrimitiveAssembler& primitive_assembler = g_state.primitive_assembler; if (g_debug_context) { for (int i = 0; i < 3; ++i) { @@ -412,16 +424,10 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { range.second, range.first); } - VideoCore::g_renderer->Rasterizer()->DrawTriangles(); - #if PICA_DUMP_GEOMETRY geometry_dumper.Dump(); #endif - if (g_debug_context) { - g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); - } - break; } diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp index 32ad72674..ccbaf071b 100644 --- a/src/video_core/pica.cpp +++ b/src/video_core/pica.cpp @@ -493,12 +493,25 @@ std::string Regs::GetCommandName(int index) { } void Init() { + g_state.Reset(); } void Shutdown() { Shader::Shutdown(); +} + +template +void Zero(T& o) { + memset(&o, 0, sizeof(o)); +} - memset(&g_state, 0, sizeof(State)); +void State::Reset() { + Zero(regs); + Zero(vs); + Zero(gs); + Zero(cmd_list); + Zero(immediate); + primitive_assembler.Reconfigure(Regs::TriangleTopology::List); } } diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 4b783ac6b..16f9e4006 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -1123,7 +1123,12 @@ struct Regs { BitField<24, 8, u32> w; } int_uniforms[4]; - INSERT_PADDING_WORDS(0x5); + INSERT_PADDING_WORDS(0x4); + + union { + // Number of input attributes to shader unit - 1 + BitField<0, 4, u32> num_input_attributes; + }; // Offset to shader program entry point (in words) BitField<0, 16, u32> main_offset; diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h index c7616bc55..323290054 100644 --- a/src/video_core/pica_state.h +++ b/src/video_core/pica_state.h @@ -12,6 +12,8 @@ namespace Pica { /// Struct used to describe current Pica state struct State { + void Reset(); + /// Pica registers Regs regs; @@ -46,13 +48,14 @@ struct State { /// Struct used to describe immediate mode rendering state struct ImmediateModeState { - Shader::InputVertex input; - // This is constructed with a dummy triangle topology - PrimitiveAssembler primitive_assembler; - int attribute_id = 0; - - ImmediateModeState() : primitive_assembler(Regs::TriangleTopology::List) {} + // Used to buffer partial vertices for immediate-mode rendering. + Shader::InputVertex input_vertex; + // Index of the next attribute to be loaded into `input_vertex`. + int current_attribute = 0; } immediate; + + // This is constructed with a dummy triangle topology + PrimitiveAssembler primitive_assembler; }; extern State g_state; ///< Current Pica state diff --git a/src/video_core/primitive_assembly.h b/src/video_core/primitive_assembly.h index cc6e5fde5..9396b4c85 100644 --- a/src/video_core/primitive_assembly.h +++ b/src/video_core/primitive_assembly.h @@ -20,7 +20,7 @@ struct PrimitiveAssembler { VertexType& v1, VertexType& v2)>; - PrimitiveAssembler(Regs::TriangleTopology topology); + PrimitiveAssembler(Regs::TriangleTopology topology = Regs::TriangleTopology::List); /* * Queues a vertex, builds primitives from the vertex queue according to the given -- cgit v1.2.3