mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 20:40:15 +00:00
Implement EMIT and SETEMIT
This commit is contained in:
parent
bb6f0d6010
commit
f02650b0d8
@ -63,6 +63,15 @@ struct State {
|
||||
|
||||
// This is constructed with a dummy triangle topology
|
||||
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
|
||||
|
@ -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 Pica
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "video_core/pica.h"
|
||||
#include "video_core/pica_types.h"
|
||||
#include "video_core/primitive_assembly.h"
|
||||
|
||||
using nihstro::RegisterType;
|
||||
using nihstro::SourceRegister;
|
||||
@ -285,6 +286,17 @@ struct UnitState {
|
||||
} registers;
|
||||
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;
|
||||
|
||||
bool conditional_code[2];
|
||||
@ -322,6 +334,10 @@ struct UnitState {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t EmitParamsOffset() {
|
||||
return offsetof(UnitState, emit_params.raw);
|
||||
}
|
||||
};
|
||||
|
||||
/// Clears the shader cache
|
||||
@ -401,6 +417,9 @@ void WriteProgramCode(bool gs, u32 value);
|
||||
void WriteSwizzlePatternsOffset(bool gs, u32 value);
|
||||
void WriteSwizzlePatterns(bool gs, u32 value);
|
||||
|
||||
template<bool Debug>
|
||||
void HandleEMIT(UnitState<Debug>& state);
|
||||
|
||||
} // namespace Shader
|
||||
|
||||
} // namespace Pica
|
||||
|
@ -631,6 +631,16 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::Id::EMIT: {
|
||||
Shader::HandleEMIT(state);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::Id::SETEMIT: {
|
||||
state.emit_params.raw = program_code[program_counter];
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_ERROR(HW_GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x",
|
||||
(int)instr.opcode.Value().EffectiveOpCode(), instr.opcode.Value().GetInfo().name, instr.hex);
|
||||
|
@ -73,8 +73,8 @@ const JitFunction instr_table[64] = {
|
||||
&JitShader::Compile_IF, // ifu
|
||||
&JitShader::Compile_IF, // ifc
|
||||
&JitShader::Compile_LOOP, // loop
|
||||
nullptr, // emit
|
||||
nullptr, // sete
|
||||
&JitShader::Compile_EMIT, // emit
|
||||
&JitShader::Compile_SETEMIT, // setemit
|
||||
&JitShader::Compile_JMP, // jmpc
|
||||
&JitShader::Compile_JMP, // jmpu
|
||||
&JitShader::Compile_CMP, // cmp
|
||||
@ -727,6 +727,22 @@ void JitShader::Compile_LOOP(Instruction instr) {
|
||||
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) {
|
||||
if (instr.opcode.Value() == OpCode::Id::JMPC)
|
||||
Compile_EvaluateCondition(instr);
|
||||
|
@ -65,6 +65,8 @@ public:
|
||||
void Compile_CALLU(Instruction instr);
|
||||
void Compile_IF(Instruction instr);
|
||||
void Compile_LOOP(Instruction instr);
|
||||
void Compile_EMIT(Instruction instr);
|
||||
void Compile_SETEMIT(Instruction instr);
|
||||
void Compile_JMP(Instruction instr);
|
||||
void Compile_CMP(Instruction instr);
|
||||
void Compile_MAD(Instruction instr);
|
||||
|
Loading…
Reference in New Issue
Block a user