Implement EMIT and SETEMIT

This commit is contained in:
Jannik Vogel 2016-04-06 02:16:05 +02:00
parent bb6f0d6010
commit f02650b0d8
6 changed files with 85 additions and 2 deletions

View File

@ -63,6 +63,15 @@ struct State {
// This is constructed with a dummy triangle topology // This is constructed with a dummy triangle topology
PrimitiveAssembler<Shader::OutputVertex> primitive_assembler; PrimitiveAssembler<Shader::OutputVertex> primitive_assembler;
/// Current geometry shader state
struct GeometryShaderState {
// Buffer used for geometry shader inputs
Shader::InputVertex buffer;
// The current index into the buffer
unsigned int index;
} gs_input_buffer;
}; };
extern State g_state; ///< Current Pica state extern State g_state; ///< Current Pica state

View File

@ -316,6 +316,33 @@ void WriteSwizzlePatterns(bool gs, u32 value) {
} }
} }
template<bool Debug>
void HandleEMIT(UnitState<Debug>& state) {
auto &config = g_state.regs.gs;
auto &emit_params = state.emit_params;
auto &emit_buffers = state.emit_buffers;
ASSERT(emit_params.vertex_id < 3);
emit_buffers[emit_params.vertex_id] = state.output_registers;
if (emit_params.primitive_emit) {
ASSERT_MSG(state.emit_triangle_callback, "EMIT invoked but no handler set!");
OutputVertex v0 = emit_buffers[0].ToVertex(config);
OutputVertex v1 = emit_buffers[1].ToVertex(config);
OutputVertex v2 = emit_buffers[2].ToVertex(config);
if (emit_params.winding) {
state.emit_triangle_callback(v2, v1, v0);
} else {
state.emit_triangle_callback(v0, v1, v2);
}
}
}
// Explicit instantiation
template void HandleEMIT(UnitState<false>& state);
template void HandleEMIT(UnitState<true>& state);
} // namespace Shader } // namespace Shader
} // namespace Pica } // namespace Pica

View File

@ -21,6 +21,7 @@
#include "video_core/pica.h" #include "video_core/pica.h"
#include "video_core/pica_types.h" #include "video_core/pica_types.h"
#include "video_core/primitive_assembly.h"
using nihstro::RegisterType; using nihstro::RegisterType;
using nihstro::SourceRegister; using nihstro::SourceRegister;
@ -285,6 +286,17 @@ struct UnitState {
} registers; } registers;
static_assert(std::is_pod<Registers>::value, "Structure is not POD"); static_assert(std::is_pod<Registers>::value, "Structure is not POD");
OutputRegisters emit_buffers[3]; //TODO: 3dbrew suggests this only stores the first 7 output registers
union EmitParameters {
u32 raw;
BitField<22, 1, u32> winding;
BitField<23, 1, u32> primitive_emit;
BitField<24, 2, u32> vertex_id;
} emit_params;
PrimitiveAssembler<OutputVertex>::TriangleHandler emit_triangle_callback;
OutputRegisters output_registers; OutputRegisters output_registers;
bool conditional_code[2]; bool conditional_code[2];
@ -322,6 +334,10 @@ struct UnitState {
return 0; return 0;
} }
} }
static size_t EmitParamsOffset() {
return offsetof(UnitState, emit_params.raw);
}
}; };
/// Clears the shader cache /// Clears the shader cache
@ -401,6 +417,9 @@ void WriteProgramCode(bool gs, u32 value);
void WriteSwizzlePatternsOffset(bool gs, u32 value); void WriteSwizzlePatternsOffset(bool gs, u32 value);
void WriteSwizzlePatterns(bool gs, u32 value); void WriteSwizzlePatterns(bool gs, u32 value);
template<bool Debug>
void HandleEMIT(UnitState<Debug>& state);
} // namespace Shader } // namespace Shader
} // namespace Pica } // namespace Pica

View File

@ -631,6 +631,16 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
break; break;
} }
case OpCode::Id::EMIT: {
Shader::HandleEMIT(state);
break;
}
case OpCode::Id::SETEMIT: {
state.emit_params.raw = program_code[program_counter];
break;
}
default: default:
LOG_ERROR(HW_GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x", LOG_ERROR(HW_GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x",
(int)instr.opcode.Value().EffectiveOpCode(), instr.opcode.Value().GetInfo().name, instr.hex); (int)instr.opcode.Value().EffectiveOpCode(), instr.opcode.Value().GetInfo().name, instr.hex);

View File

@ -73,8 +73,8 @@ const JitFunction instr_table[64] = {
&JitShader::Compile_IF, // ifu &JitShader::Compile_IF, // ifu
&JitShader::Compile_IF, // ifc &JitShader::Compile_IF, // ifc
&JitShader::Compile_LOOP, // loop &JitShader::Compile_LOOP, // loop
nullptr, // emit &JitShader::Compile_EMIT, // emit
nullptr, // sete &JitShader::Compile_SETEMIT, // setemit
&JitShader::Compile_JMP, // jmpc &JitShader::Compile_JMP, // jmpc
&JitShader::Compile_JMP, // jmpu &JitShader::Compile_JMP, // jmpu
&JitShader::Compile_CMP, // cmp &JitShader::Compile_CMP, // cmp
@ -727,6 +727,22 @@ void JitShader::Compile_LOOP(Instruction instr) {
looping = false; looping = false;
} }
static void Handle_EMIT(void* param1) {
UnitState<false>& state = *static_cast<UnitState<false>*>(param1);
Shader::HandleEMIT(state);
};
void JitShader::Compile_EMIT(Instruction instr) {
ABI_PushRegistersAndAdjustStack(PersistentCallerSavedRegs(), 0);
MOV(PTRBITS, R(ABI_PARAM1), R(STATE));
ABI_CallFunctionR(reinterpret_cast<const void*>(Handle_EMIT), ABI_PARAM1);
ABI_PopRegistersAndAdjustStack(PersistentCallerSavedRegs(), 0);
}
void JitShader::Compile_SETEMIT(Instruction instr) {
MOV(32, MDisp(STATE, UnitState<false>::EmitParamsOffset()), Imm32(*(u32*)&instr.setemit));
}
void JitShader::Compile_JMP(Instruction instr) { void JitShader::Compile_JMP(Instruction instr) {
if (instr.opcode.Value() == OpCode::Id::JMPC) if (instr.opcode.Value() == OpCode::Id::JMPC)
Compile_EvaluateCondition(instr); Compile_EvaluateCondition(instr);

View File

@ -65,6 +65,8 @@ public:
void Compile_CALLU(Instruction instr); void Compile_CALLU(Instruction instr);
void Compile_IF(Instruction instr); void Compile_IF(Instruction instr);
void Compile_LOOP(Instruction instr); void Compile_LOOP(Instruction instr);
void Compile_EMIT(Instruction instr);
void Compile_SETEMIT(Instruction instr);
void Compile_JMP(Instruction instr); void Compile_JMP(Instruction instr);
void Compile_CMP(Instruction instr); void Compile_CMP(Instruction instr);
void Compile_MAD(Instruction instr); void Compile_MAD(Instruction instr);