Implement EMIT and SETEMIT
This commit is contained in:
		@@ -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);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user