citra-emu
/
citra-canary
Archived
1
0
Fork 0

Pica: Improve accuracy of immediate-mode support

This partially fixes Etrian Odyssey IV.
This commit is contained in:
Yuri Kunde Schlesner 2016-03-05 14:49:23 -08:00
parent 0c447e0a06
commit 81004211dd
5 changed files with 56 additions and 29 deletions

View File

@ -75,12 +75,17 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D); GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D);
break; 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): case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.index, 0x232):
if (regs.vs_default_attributes_setup.index == 15) { g_state.immediate.current_attribute = 0;
// Reset immediate primitive state default_attr_counter = 0;
g_state.immediate.primitive_assembler.Reconfigure(regs.triangle_topology);
g_state.immediate.attribute_id = 0;
}
break; break;
// Load default vertex input attributes // Load default vertex input attributes
@ -105,7 +110,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
break; break;
} }
Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index]; Math::Vec4<float24> attribute;
// NOTE: The destination component order indeed is "backwards" // NOTE: The destination component order indeed is "backwards"
attribute.w = float24::FromRaw(default_attr_write_buffer[0] >> 8); 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! // TODO: Verify that this actually modifies the register!
if (setup.index < 15) { if (setup.index < 15) {
g_state.vs.default_attributes[setup.index] = attribute;
setup.index++; setup.index++;
} else { } else {
// Put each attribute into an immediate input buffer. // Put each attribute into an immediate input buffer.
// When all specified immediate attributes are present, the Vertex Shader is invoked and everything is // When all specified immediate attributes are present, the Vertex Shader is invoked and everything is
// sent to the primitive assembler. // sent to the primitive assembler.
auto& immediate_input = g_state.immediate.input; auto& immediate_input = g_state.immediate.input_vertex;
auto& immediate_attribute_id = g_state.immediate.attribute_id; auto& immediate_attribute_id = g_state.immediate.current_attribute;
const auto& attribute_config = regs.vertex_attributes;
immediate_input.attr[immediate_attribute_id++] = 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; immediate_attribute_id = 0;
Shader::UnitState<false> shader_unit; Shader::UnitState<false> shader_unit;
Shader::Setup(shader_unit); Shader::Setup(shader_unit);
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, static_cast<void*>(&immediate_input));
// Send to vertex shader // 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 // Send to renderer
using Pica::Shader::OutputVertex; 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); 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): 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 // Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring
VideoCore::g_renderer->Rasterizer()->DrawTriangles(); VideoCore::g_renderer->Rasterizer()->DrawTriangles();
if (g_debug_context) {
g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
}
} }
break; break;
@ -241,7 +253,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
DebugUtils::GeometryDumper geometry_dumper; DebugUtils::GeometryDumper geometry_dumper;
PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value()); PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value());
#endif #endif
PrimitiveAssembler<Shader::OutputVertex> primitive_assembler(regs.triangle_topology.Value()); PrimitiveAssembler<Shader::OutputVertex>& primitive_assembler = g_state.primitive_assembler;
if (g_debug_context) { if (g_debug_context) {
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
@ -412,16 +424,10 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
range.second, range.first); range.second, range.first);
} }
VideoCore::g_renderer->Rasterizer()->DrawTriangles();
#if PICA_DUMP_GEOMETRY #if PICA_DUMP_GEOMETRY
geometry_dumper.Dump(); geometry_dumper.Dump();
#endif #endif
if (g_debug_context) {
g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
}
break; break;
} }

View File

@ -493,12 +493,25 @@ std::string Regs::GetCommandName(int index) {
} }
void Init() { void Init() {
g_state.Reset();
} }
void Shutdown() { void Shutdown() {
Shader::Shutdown(); Shader::Shutdown();
}
memset(&g_state, 0, sizeof(State)); template <typename T>
void Zero(T& o) {
memset(&o, 0, sizeof(o));
}
void State::Reset() {
Zero(regs);
Zero(vs);
Zero(gs);
Zero(cmd_list);
Zero(immediate);
primitive_assembler.Reconfigure(Regs::TriangleTopology::List);
} }
} }

View File

@ -1123,7 +1123,12 @@ struct Regs {
BitField<24, 8, u32> w; BitField<24, 8, u32> w;
} int_uniforms[4]; } 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) // Offset to shader program entry point (in words)
BitField<0, 16, u32> main_offset; BitField<0, 16, u32> main_offset;

View File

@ -12,6 +12,8 @@ namespace Pica {
/// Struct used to describe current Pica state /// Struct used to describe current Pica state
struct State { struct State {
void Reset();
/// Pica registers /// Pica registers
Regs regs; Regs regs;
@ -46,13 +48,14 @@ struct State {
/// Struct used to describe immediate mode rendering state /// Struct used to describe immediate mode rendering state
struct ImmediateModeState { struct ImmediateModeState {
Shader::InputVertex input; // Used to buffer partial vertices for immediate-mode rendering.
// This is constructed with a dummy triangle topology Shader::InputVertex input_vertex;
PrimitiveAssembler<Shader::OutputVertex> primitive_assembler; // Index of the next attribute to be loaded into `input_vertex`.
int attribute_id = 0; int current_attribute = 0;
ImmediateModeState() : primitive_assembler(Regs::TriangleTopology::List) {}
} immediate; } immediate;
// This is constructed with a dummy triangle topology
PrimitiveAssembler<Shader::OutputVertex> primitive_assembler;
}; };
extern State g_state; ///< Current Pica state extern State g_state; ///< Current Pica state

View File

@ -20,7 +20,7 @@ struct PrimitiveAssembler {
VertexType& v1, VertexType& v1,
VertexType& v2)>; 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 * Queues a vertex, builds primitives from the vertex queue according to the given