citra-emu
/
citra
Archived
1
0
Fork 0

Merge pull request #2985 from huwpascoe/pica_reg

Extracted the attribute setup and draw commands into their own functions
This commit is contained in:
bunnei 2017-10-04 11:40:29 -04:00 committed by GitHub
commit c1355ada4b
1 changed files with 222 additions and 217 deletions

View File

@ -119,64 +119,16 @@ static void WriteUniformFloatReg(ShaderRegs& config, Shader::ShaderSetup& setup,
} }
} }
static void WritePicaReg(u32 id, u32 value, u32 mask) { static void LoadDefaultVertexAttributes(u32 register_value) {
auto& regs = g_state.regs; auto& regs = g_state.regs;
if (id >= Regs::NUM_REGS) {
LOG_ERROR(HW_GPU,
"Commandlist tried to write to invalid register 0x%03X (value: %08X, mask: %X)",
id, value, mask);
return;
}
// TODO: Figure out how register masking acts on e.g. vs.uniform_setup.set_value
u32 old_value = regs.reg_array[id];
const u32 write_mask = expand_bits_to_bytes[mask];
regs.reg_array[id] = (old_value & ~write_mask) | (value & write_mask);
// Double check for is_pica_tracing to avoid call overhead
if (DebugUtils::IsPicaTracing()) {
DebugUtils::OnPicaRegWrite({(u16)id, (u16)mask, regs.reg_array[id]});
}
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded,
reinterpret_cast<void*>(&id));
switch (id) {
// Trigger IRQ
case PICA_REG_INDEX(trigger_irq):
Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D);
break;
case PICA_REG_INDEX(pipeline.triangle_topology):
g_state.primitive_assembler.Reconfigure(regs.pipeline.triangle_topology);
break;
case PICA_REG_INDEX(pipeline.restart_primitive):
g_state.primitive_assembler.Reset();
break;
case PICA_REG_INDEX(pipeline.vs_default_attributes_setup.index):
g_state.immediate.current_attribute = 0;
g_state.immediate.reset_geometry_pipeline = true;
default_attr_counter = 0;
break;
// Load default vertex input attributes
case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[0], 0x233):
case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[1], 0x234):
case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[2], 0x235): {
// TODO: Does actual hardware indeed keep an intermediate buffer or does // TODO: Does actual hardware indeed keep an intermediate buffer or does
// it directly write the values? // it directly write the values?
default_attr_write_buffer[default_attr_counter++] = value; default_attr_write_buffer[default_attr_counter++] = register_value;
// Default attributes are written in a packed format such that four float24 values are // Default attributes are written in a packed format such that four float24 values are encoded
// encoded in // in three 32-bit numbers.
// three 32-bit numbers. We write to internal memory once a full such vector is // We write to internal memory once a full such vector is written.
// written.
if (default_attr_counter >= 3) { if (default_attr_counter >= 3) {
default_attr_counter = 0; default_attr_counter = 0;
@ -184,7 +136,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
if (setup.index >= 16) { if (setup.index >= 16) {
LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index); LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index);
break; return;
} }
Math::Vec4<float24> attribute; Math::Vec4<float24> attribute;
@ -249,34 +201,16 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
// See: https://github.com/citra-emu/citra/pull/2866#issuecomment-327011550 // See: https://github.com/citra-emu/citra/pull/2866#issuecomment-327011550
VideoCore::g_renderer->Rasterizer()->DrawTriangles(); VideoCore::g_renderer->Rasterizer()->DrawTriangles();
if (g_debug_context) { if (g_debug_context) {
g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
nullptr);
} }
} }
} }
} }
break;
} }
case PICA_REG_INDEX(pipeline.gpu_mode): static void Draw(u32 command_id) {
// This register likely just enables vertex processing and doesn't need any special handling
break;
case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[0], 0x23c):
case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[1], 0x23d): {
unsigned index =
static_cast<unsigned>(id - PICA_REG_INDEX(pipeline.command_buffer.trigger[0]));
u32* head_ptr = (u32*)Memory::GetPhysicalPointer(
regs.pipeline.command_buffer.GetPhysicalAddress(index));
g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
g_state.cmd_list.length = regs.pipeline.command_buffer.GetSize(index) / sizeof(u32);
break;
}
// It seems like these trigger vertex rendering
case PICA_REG_INDEX(pipeline.trigger_draw):
case PICA_REG_INDEX(pipeline.trigger_draw_indexed): {
MICROPROFILE_SCOPE(GPU_Drawing); MICROPROFILE_SCOPE(GPU_Drawing);
auto& regs = g_state.regs;
#if PICA_LOG_TEV #if PICA_LOG_TEV
DebugUtils::DumpTevStageConfig(regs.GetTevStages()); DebugUtils::DumpTevStageConfig(regs.GetTevStages());
@ -291,7 +225,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
VertexLoader loader(regs.pipeline); VertexLoader loader(regs.pipeline);
// Load vertices // Load vertices
bool is_indexed = (id == PICA_REG_INDEX(pipeline.trigger_draw_indexed)); bool is_indexed = (command_id == PICA_REG_INDEX(pipeline.trigger_draw_indexed));
const auto& index_info = regs.pipeline.index_array; const auto& index_info = regs.pipeline.index_array;
const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset); const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset);
@ -338,8 +272,8 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
for (unsigned int index = 0; index < regs.pipeline.num_vertices; ++index) { for (unsigned int index = 0; index < regs.pipeline.num_vertices; ++index) {
// Indexed rendering doesn't use the start offset // Indexed rendering doesn't use the start offset
unsigned int vertex = unsigned int vertex = is_indexed
is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) ? (index_u16 ? index_address_16[index] : index_address_8[index])
: (index + regs.pipeline.vertex_offset); : (index + regs.pipeline.vertex_offset);
// -1 is a common special value used for primitive restart. Since it's unknown if // -1 is a common special value used for primitive restart. Since it's unknown if
@ -356,8 +290,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
if (g_debug_context && Pica::g_debug_context->recorder) { if (g_debug_context && Pica::g_debug_context->recorder) {
int size = index_u16 ? 2 : 1; int size = index_u16 ? 2 : 1;
memory_accesses.AddAccess(base_address + index_info.offset + size * index, memory_accesses.AddAccess(base_address + index_info.offset + size * index, size);
size);
} }
for (unsigned int i = 0; i < VERTEX_CACHE_SIZE; ++i) { for (unsigned int i = 0; i < VERTEX_CACHE_SIZE; ++i) {
@ -402,10 +335,82 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
if (g_debug_context) { if (g_debug_context) {
g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
} }
}
static void WritePicaReg(u32 id, u32 value, u32 mask) {
auto& regs = g_state.regs;
if (id >= Regs::NUM_REGS) {
LOG_ERROR(HW_GPU,
"Commandlist tried to write to invalid register 0x%03X (value: %08X, mask: %X)",
id, value, mask);
return;
}
// TODO: Figure out how register masking acts on e.g. vs.uniform_setup.set_value
u32 old_value = regs.reg_array[id];
const u32 write_mask = expand_bits_to_bytes[mask];
regs.reg_array[id] = (old_value & ~write_mask) | (value & write_mask);
// Double check for is_pica_tracing to avoid call overhead
if (DebugUtils::IsPicaTracing()) {
DebugUtils::OnPicaRegWrite({(u16)id, (u16)mask, regs.reg_array[id]});
}
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded,
reinterpret_cast<void*>(&id));
switch (id) {
// Trigger IRQ
case PICA_REG_INDEX(trigger_irq):
Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D);
break;
case PICA_REG_INDEX(pipeline.triangle_topology):
g_state.primitive_assembler.Reconfigure(regs.pipeline.triangle_topology);
break;
case PICA_REG_INDEX(pipeline.restart_primitive):
g_state.primitive_assembler.Reset();
break;
case PICA_REG_INDEX(pipeline.vs_default_attributes_setup.index):
g_state.immediate.current_attribute = 0;
g_state.immediate.reset_geometry_pipeline = true;
default_attr_counter = 0;
break;
// Load default vertex input attributes
case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[0], 0x233):
case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[1], 0x234):
case PICA_REG_INDEX_WORKAROUND(pipeline.vs_default_attributes_setup.set_value[2], 0x235):
LoadDefaultVertexAttributes(value);
break;
case PICA_REG_INDEX(pipeline.gpu_mode):
// This register likely just enables vertex processing and doesn't need any special handling
break;
case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[0], 0x23c):
case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[1], 0x23d): {
unsigned index =
static_cast<unsigned>(id - PICA_REG_INDEX(pipeline.command_buffer.trigger[0]));
u32* head_ptr = (u32*)Memory::GetPhysicalPointer(
regs.pipeline.command_buffer.GetPhysicalAddress(index));
g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
g_state.cmd_list.length = regs.pipeline.command_buffer.GetSize(index) / sizeof(u32);
break; break;
} }
// It seems like these trigger vertex rendering
case PICA_REG_INDEX(pipeline.trigger_draw):
case PICA_REG_INDEX(pipeline.trigger_draw_indexed):
Draw(id);
break;
case PICA_REG_INDEX(gs.bool_uniforms): case PICA_REG_INDEX(gs.bool_uniforms):
WriteUniformBoolReg(g_state.gs, g_state.regs.gs.bool_uniforms.Value()); WriteUniformBoolReg(g_state.gs, g_state.regs.gs.bool_uniforms.Value());
break; break;