From f02650b0d87a5dd954e194b2dc502416f02d0b1f Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Wed, 6 Apr 2016 02:16:05 +0200 Subject: [PATCH] Implement EMIT and SETEMIT --- src/video_core/pica_state.h | 9 +++++++ src/video_core/shader/shader.cpp | 27 ++++++++++++++++++++ src/video_core/shader/shader.h | 19 ++++++++++++++ src/video_core/shader/shader_interpreter.cpp | 10 ++++++++ src/video_core/shader/shader_jit_x64.cpp | 20 +++++++++++++-- src/video_core/shader/shader_jit_x64.h | 2 ++ 6 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h index 495174c25..f83b91f7d 100644 --- a/src/video_core/pica_state.h +++ b/src/video_core/pica_state.h @@ -63,6 +63,15 @@ struct State { // This is constructed with a dummy triangle topology PrimitiveAssembler 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 diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp index 6d86760a4..1423ba2f5 100644 --- a/src/video_core/shader/shader.cpp +++ b/src/video_core/shader/shader.cpp @@ -316,6 +316,33 @@ void WriteSwizzlePatterns(bool gs, u32 value) { } } +template +void HandleEMIT(UnitState& 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& state); +template void HandleEMIT(UnitState& state); + } // namespace Shader } // namespace Pica diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h index b0498f95f..cb1eda1d2 100644 --- a/src/video_core/shader/shader.h +++ b/src/video_core/shader/shader.h @@ -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::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::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 +void HandleEMIT(UnitState& state); + } // namespace Shader } // namespace Pica diff --git a/src/video_core/shader/shader_interpreter.cpp b/src/video_core/shader/shader_interpreter.cpp index fcb808a2b..96da962b3 100644 --- a/src/video_core/shader/shader_interpreter.cpp +++ b/src/video_core/shader/shader_interpreter.cpp @@ -631,6 +631,16 @@ void RunInterpreter(const ShaderSetup& setup, UnitState& 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); diff --git a/src/video_core/shader/shader_jit_x64.cpp b/src/video_core/shader/shader_jit_x64.cpp index a82573a3d..726422561 100644 --- a/src/video_core/shader/shader_jit_x64.cpp +++ b/src/video_core/shader/shader_jit_x64.cpp @@ -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& state = *static_cast*>(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(Handle_EMIT), ABI_PARAM1); + ABI_PopRegistersAndAdjustStack(PersistentCallerSavedRegs(), 0); +} + +void JitShader::Compile_SETEMIT(Instruction instr) { + MOV(32, MDisp(STATE, UnitState::EmitParamsOffset()), Imm32(*(u32*)&instr.setemit)); +} + void JitShader::Compile_JMP(Instruction instr) { if (instr.opcode.Value() == OpCode::Id::JMPC) Compile_EvaluateCondition(instr); diff --git a/src/video_core/shader/shader_jit_x64.h b/src/video_core/shader/shader_jit_x64.h index 6affa6d15..b6d4de07b 100644 --- a/src/video_core/shader/shader_jit_x64.h +++ b/src/video_core/shader/shader_jit_x64.h @@ -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);