diff options
Diffstat (limited to 'src/video_core/shader')
| -rw-r--r-- | src/video_core/shader/shader.cpp | 11 | ||||
| -rw-r--r-- | src/video_core/shader/shader.h | 42 | ||||
| -rw-r--r-- | src/video_core/shader/shader_interpreter.cpp | 74 | ||||
| -rw-r--r-- | src/video_core/shader/shader_interpreter.h | 2 | ||||
| -rw-r--r-- | src/video_core/shader/shader_jit_x64.cpp | 32 | ||||
| -rw-r--r-- | src/video_core/shader/shader_jit_x64.h | 6 |
6 files changed, 90 insertions, 77 deletions
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp index 449fc703f..161097610 100644 --- a/src/video_core/shader/shader.cpp +++ b/src/video_core/shader/shader.cpp @@ -64,10 +64,10 @@ MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240)); OutputVertex ShaderSetup::Run(UnitState<false>& state, const InputVertex& input, int num_attributes) { auto& config = g_state.regs.vs; + auto& setup = g_state.vs; MICROPROFILE_SCOPE(GPU_Shader); - state.program_counter = config.main_offset; state.debug.max_offset = 0; state.debug.max_opdesc_id = 0; @@ -82,11 +82,11 @@ OutputVertex ShaderSetup::Run(UnitState<false>& state, const InputVertex& input, #ifdef ARCHITECTURE_x86_64 if (VideoCore::g_shader_jit_enabled) - jit_shader->Run(&state.registers, g_state.regs.vs.main_offset); + jit_shader->Run(setup, state, config.main_offset); else - RunInterpreter(state); + RunInterpreter(setup, state, config.main_offset); #else - RunInterpreter(state); + RunInterpreter(setup, state, config.main_offset); #endif // ARCHITECTURE_x86_64 // Setup output data @@ -143,7 +143,6 @@ OutputVertex ShaderSetup::Run(UnitState<false>& state, const InputVertex& input, DebugData<true> ShaderSetup::ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const ShaderSetup& setup) { UnitState<true> state; - state.program_counter = config.main_offset; state.debug.max_offset = 0; state.debug.max_opdesc_id = 0; @@ -158,7 +157,7 @@ DebugData<true> ShaderSetup::ProduceDebugInfo(const InputVertex& input, int num_ state.conditional_code[0] = false; state.conditional_code[1] = false; - RunInterpreter(state); + RunInterpreter(setup, state, config.main_offset); return state.debug; } diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h index 7f417675a..84898f21c 100644 --- a/src/video_core/shader/shader.h +++ b/src/video_core/shader/shader.h @@ -272,38 +272,21 @@ struct UnitState { } registers; static_assert(std::is_pod<Registers>::value, "Structure is not POD"); - u32 program_counter; bool conditional_code[2]; // Two Address registers and one loop counter // TODO: How many bits do these actually have? s32 address_registers[3]; - enum { - INVALID_ADDRESS = 0xFFFFFFFF - }; - - struct CallStackElement { - u32 final_address; // Address upon which we jump to return_address - u32 return_address; // Where to jump when leaving scope - u8 repeat_counter; // How often to repeat until this call stack element is removed - u8 loop_increment; // Which value to add to the loop counter after an iteration - // TODO: Should this be a signed value? Does it even matter? - u32 loop_address; // The address where we'll return to after each loop iteration - }; - - // TODO: Is there a maximal size for this? - boost::container::static_vector<CallStackElement, 16> call_stack; - DebugData<Debug> debug; static size_t InputOffset(const SourceRegister& reg) { switch (reg.GetRegisterType()) { case RegisterType::Input: - return offsetof(UnitState::Registers, input) + reg.GetIndex()*sizeof(Math::Vec4<float24>); + return offsetof(UnitState, registers.input) + reg.GetIndex()*sizeof(Math::Vec4<float24>); case RegisterType::Temporary: - return offsetof(UnitState::Registers, temporary) + reg.GetIndex()*sizeof(Math::Vec4<float24>); + return offsetof(UnitState, registers.temporary) + reg.GetIndex()*sizeof(Math::Vec4<float24>); default: UNREACHABLE(); @@ -314,10 +297,10 @@ struct UnitState { static size_t OutputOffset(const DestRegister& reg) { switch (reg.GetRegisterType()) { case RegisterType::Output: - return offsetof(UnitState::Registers, output) + reg.GetIndex()*sizeof(Math::Vec4<float24>); + return offsetof(UnitState, registers.output) + reg.GetIndex()*sizeof(Math::Vec4<float24>); case RegisterType::Temporary: - return offsetof(UnitState::Registers, temporary) + reg.GetIndex()*sizeof(Math::Vec4<float24>); + return offsetof(UnitState, registers.temporary) + reg.GetIndex()*sizeof(Math::Vec4<float24>); default: UNREACHABLE(); @@ -340,7 +323,22 @@ struct ShaderSetup { std::array<Math::Vec4<u8>, 4> i; } uniforms; - Math::Vec4<float24> default_attributes[16]; + static size_t UniformOffset(RegisterType type, unsigned index) { + switch (type) { + case RegisterType::FloatUniform: + return offsetof(ShaderSetup, uniforms.f) + index*sizeof(Math::Vec4<float24>); + + case RegisterType::BoolUniform: + return offsetof(ShaderSetup, uniforms.b) + index*sizeof(bool); + + case RegisterType::IntUniform: + return offsetof(ShaderSetup, uniforms.i) + index*sizeof(Math::Vec4<u8>); + + default: + UNREACHABLE(); + return 0; + } + } std::array<u32, 1024> program_code; std::array<u32, 1024> swizzle_data; diff --git a/src/video_core/shader/shader_interpreter.cpp b/src/video_core/shader/shader_interpreter.cpp index 7710f7fbc..714e8bfd5 100644 --- a/src/video_core/shader/shader_interpreter.cpp +++ b/src/video_core/shader/shader_interpreter.cpp @@ -29,8 +29,24 @@ namespace Pica { namespace Shader { +constexpr u32 INVALID_ADDRESS = 0xFFFFFFFF; + +struct CallStackElement { + u32 final_address; // Address upon which we jump to return_address + u32 return_address; // Where to jump when leaving scope + u8 repeat_counter; // How often to repeat until this call stack element is removed + u8 loop_increment; // Which value to add to the loop counter after an iteration + // TODO: Should this be a signed value? Does it even matter? + u32 loop_address; // The address where we'll return to after each loop iteration +}; + template<bool Debug> -void RunInterpreter(UnitState<Debug>& state) { +void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned offset) { + // TODO: Is there a maximal size for this? + boost::container::static_vector<CallStackElement, 16> call_stack; + + u32 program_counter = offset; + const auto& uniforms = g_state.vs.uniforms; const auto& swizzle_data = g_state.vs.swizzle_data; const auto& program_code = g_state.vs.program_code; @@ -41,16 +57,16 @@ void RunInterpreter(UnitState<Debug>& state) { unsigned iteration = 0; bool exit_loop = false; while (!exit_loop) { - if (!state.call_stack.empty()) { - auto& top = state.call_stack.back(); - if (state.program_counter == top.final_address) { + if (!call_stack.empty()) { + auto& top = call_stack.back(); + if (program_counter == top.final_address) { state.address_registers[2] += top.loop_increment; if (top.repeat_counter-- == 0) { - state.program_counter = top.return_address; - state.call_stack.pop_back(); + program_counter = top.return_address; + call_stack.pop_back(); } else { - state.program_counter = top.loop_address; + program_counter = top.loop_address; } // TODO: Is "trying again" accurate to hardware? @@ -58,20 +74,20 @@ void RunInterpreter(UnitState<Debug>& state) { } } - const Instruction instr = { program_code[state.program_counter] }; + const Instruction instr = { program_code[program_counter] }; const SwizzlePattern swizzle = { swizzle_data[instr.common.operand_desc_id] }; - static auto call = [](UnitState<Debug>& state, u32 offset, u32 num_instructions, + static auto call = [&program_counter, &call_stack](UnitState<Debug>& state, u32 offset, u32 num_instructions, u32 return_offset, u8 repeat_count, u8 loop_increment) { - state.program_counter = offset - 1; // -1 to make sure when incrementing the PC we end up at the correct offset - ASSERT(state.call_stack.size() < state.call_stack.capacity()); - state.call_stack.push_back({ offset + num_instructions, return_offset, repeat_count, loop_increment, offset }); + program_counter = offset - 1; // -1 to make sure when incrementing the PC we end up at the correct offset + ASSERT(call_stack.size() < call_stack.capacity()); + call_stack.push_back({ offset + num_instructions, return_offset, repeat_count, loop_increment, offset }); }; - Record<DebugDataRecord::CUR_INSTR>(state.debug, iteration, state.program_counter); + Record<DebugDataRecord::CUR_INSTR>(state.debug, iteration, program_counter); if (iteration > 0) - Record<DebugDataRecord::NEXT_INSTR>(state.debug, iteration - 1, state.program_counter); + Record<DebugDataRecord::NEXT_INSTR>(state.debug, iteration - 1, program_counter); - state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + state.program_counter); + state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + program_counter); auto LookupSourceRegister = [&](const SourceRegister& source_reg) -> const float24* { switch (source_reg.GetRegisterType()) { @@ -519,7 +535,7 @@ void RunInterpreter(UnitState<Debug>& state) { case OpCode::Id::JMPC: Record<DebugDataRecord::COND_CMP_IN>(state.debug, iteration, state.conditional_code); if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) { - state.program_counter = instr.flow_control.dest_offset - 1; + program_counter = instr.flow_control.dest_offset - 1; } break; @@ -527,7 +543,7 @@ void RunInterpreter(UnitState<Debug>& state) { Record<DebugDataRecord::COND_BOOL_IN>(state.debug, iteration, uniforms.b[instr.flow_control.bool_uniform_id]); if (uniforms.b[instr.flow_control.bool_uniform_id] == !(instr.flow_control.num_instructions & 1)) { - state.program_counter = instr.flow_control.dest_offset - 1; + program_counter = instr.flow_control.dest_offset - 1; } break; @@ -535,7 +551,7 @@ void RunInterpreter(UnitState<Debug>& state) { call(state, instr.flow_control.dest_offset, instr.flow_control.num_instructions, - state.program_counter + 1, 0, 0); + program_counter + 1, 0, 0); break; case OpCode::Id::CALLU: @@ -544,7 +560,7 @@ void RunInterpreter(UnitState<Debug>& state) { call(state, instr.flow_control.dest_offset, instr.flow_control.num_instructions, - state.program_counter + 1, 0, 0); + program_counter + 1, 0, 0); } break; @@ -554,7 +570,7 @@ void RunInterpreter(UnitState<Debug>& state) { call(state, instr.flow_control.dest_offset, instr.flow_control.num_instructions, - state.program_counter + 1, 0, 0); + program_counter + 1, 0, 0); } break; @@ -565,8 +581,8 @@ void RunInterpreter(UnitState<Debug>& state) { Record<DebugDataRecord::COND_BOOL_IN>(state.debug, iteration, uniforms.b[instr.flow_control.bool_uniform_id]); if (uniforms.b[instr.flow_control.bool_uniform_id]) { call(state, - state.program_counter + 1, - instr.flow_control.dest_offset - state.program_counter - 1, + program_counter + 1, + instr.flow_control.dest_offset - program_counter - 1, instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0); } else { call(state, @@ -584,8 +600,8 @@ void RunInterpreter(UnitState<Debug>& state) { Record<DebugDataRecord::COND_CMP_IN>(state.debug, iteration, state.conditional_code); if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) { call(state, - state.program_counter + 1, - instr.flow_control.dest_offset - state.program_counter - 1, + program_counter + 1, + instr.flow_control.dest_offset - program_counter - 1, instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0); } else { call(state, @@ -607,8 +623,8 @@ void RunInterpreter(UnitState<Debug>& state) { Record<DebugDataRecord::LOOP_INT_IN>(state.debug, iteration, loop_param); call(state, - state.program_counter + 1, - instr.flow_control.dest_offset - state.program_counter + 1, + program_counter + 1, + instr.flow_control.dest_offset - program_counter + 1, instr.flow_control.dest_offset + 1, loop_param.x, loop_param.z); @@ -625,14 +641,14 @@ void RunInterpreter(UnitState<Debug>& state) { } } - ++state.program_counter; + ++program_counter; ++iteration; } } // Explicit instantiation -template void RunInterpreter(UnitState<false>& state); -template void RunInterpreter(UnitState<true>& state); +template void RunInterpreter(const ShaderSetup& setup, UnitState<false>& state, unsigned offset); +template void RunInterpreter(const ShaderSetup& setup, UnitState<true>& state, unsigned offset); } // namespace diff --git a/src/video_core/shader/shader_interpreter.h b/src/video_core/shader/shader_interpreter.h index 6048cdf3a..bb3ce1c6e 100644 --- a/src/video_core/shader/shader_interpreter.h +++ b/src/video_core/shader/shader_interpreter.h @@ -11,7 +11,7 @@ namespace Shader { template <bool Debug> struct UnitState; template<bool Debug> -void RunInterpreter(UnitState<Debug>& state); +void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned offset); } // namespace diff --git a/src/video_core/shader/shader_jit_x64.cpp b/src/video_core/shader/shader_jit_x64.cpp index 99f6c51eb..43e7e6b4c 100644 --- a/src/video_core/shader/shader_jit_x64.cpp +++ b/src/video_core/shader/shader_jit_x64.cpp @@ -102,7 +102,7 @@ const JitFunction instr_table[64] = { // purposes, as documented below: /// Pointer to the uniform memory -static const X64Reg UNIFORMS = R9; +static const X64Reg SETUP = R9; /// The two 32-bit VS address offset registers set by the MOVA instruction static const X64Reg ADDROFFS_REG_0 = R10; static const X64Reg ADDROFFS_REG_1 = R11; @@ -117,7 +117,7 @@ static const X64Reg COND0 = R13; /// Result of the previous CMP instruction for the Y-component comparison static const X64Reg COND1 = R14; /// Pointer to the UnitState instance for the current VS unit -static const X64Reg REGISTERS = R15; +static const X64Reg STATE = R15; /// SIMD scratch register static const X64Reg SCRATCH = XMM0; /// Loaded with the first swizzled source register, otherwise can be used as a scratch register @@ -136,7 +136,7 @@ static const X64Reg NEGBIT = XMM15; // State registers that must not be modified by external functions calls // Scratch registers, e.g., SRC1 and SCRATCH, have to be saved on the side if needed static const BitSet32 persistent_regs = { - UNIFORMS, REGISTERS, // Pointers to register blocks + SETUP, STATE, // Pointers to register blocks ADDROFFS_REG_0, ADDROFFS_REG_1, LOOPCOUNT_REG, COND0, COND1, // Cached registers ONE+16, NEGBIT+16, // Constants }; @@ -177,10 +177,10 @@ void JitShader::Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRe size_t src_offset; if (src_reg.GetRegisterType() == RegisterType::FloatUniform) { - src_ptr = UNIFORMS; - src_offset = src_reg.GetIndex() * sizeof(float24) * 4; + src_ptr = SETUP; + src_offset = ShaderSetup::UniformOffset(RegisterType::FloatUniform, src_reg.GetIndex()); } else { - src_ptr = REGISTERS; + src_ptr = STATE; src_offset = UnitState<false>::InputOffset(src_reg); } @@ -264,11 +264,11 @@ void JitShader::Compile_DestEnable(Instruction instr,X64Reg src) { // If all components are enabled, write the result to the destination register if (swiz.dest_mask == NO_DEST_REG_MASK) { // Store dest back to memory - MOVAPS(MDisp(REGISTERS, dest_offset_disp), src); + MOVAPS(MDisp(STATE, dest_offset_disp), src); } else { // Not all components are enabled, so mask the result when storing to the destination register... - MOVAPS(SCRATCH, MDisp(REGISTERS, dest_offset_disp)); + MOVAPS(SCRATCH, MDisp(STATE, dest_offset_disp)); if (Common::GetCPUCaps().sse4_1) { u8 mask = ((swiz.dest_mask & 1) << 3) | ((swiz.dest_mask & 8) >> 3) | ((swiz.dest_mask & 2) << 1) | ((swiz.dest_mask & 4) >> 1); @@ -287,7 +287,7 @@ void JitShader::Compile_DestEnable(Instruction instr,X64Reg src) { } // Store dest back to memory - MOVAPS(MDisp(REGISTERS, dest_offset_disp), SCRATCH); + MOVAPS(MDisp(STATE, dest_offset_disp), SCRATCH); } } @@ -336,8 +336,8 @@ void JitShader::Compile_EvaluateCondition(Instruction instr) { } void JitShader::Compile_UniformCondition(Instruction instr) { - int offset = offsetof(decltype(g_state.vs.uniforms), b) + (instr.flow_control.bool_uniform_id * sizeof(bool)); - CMP(sizeof(bool) * 8, MDisp(UNIFORMS, offset), Imm8(0)); + int offset = ShaderSetup::UniformOffset(RegisterType::BoolUniform, instr.flow_control.bool_uniform_id); + CMP(sizeof(bool) * 8, MDisp(SETUP, offset), Imm8(0)); } BitSet32 JitShader::PersistentCallerSavedRegs() { @@ -714,8 +714,8 @@ void JitShader::Compile_LOOP(Instruction instr) { looping = true; - int offset = offsetof(decltype(g_state.vs.uniforms), i) + (instr.flow_control.int_uniform_id * sizeof(Math::Vec4<u8>)); - MOV(32, R(LOOPCOUNT), MDisp(UNIFORMS, offset)); + int offset = ShaderSetup::UniformOffset(RegisterType::IntUniform, instr.flow_control.int_uniform_id); + MOV(32, R(LOOPCOUNT), MDisp(SETUP, offset)); MOV(32, R(LOOPCOUNT_REG), R(LOOPCOUNT)); SHR(32, R(LOOPCOUNT_REG), Imm8(8)); AND(32, R(LOOPCOUNT_REG), Imm32(0xff)); // Y-component is the start @@ -826,8 +826,8 @@ void JitShader::Compile() { // The stack pointer is 8 modulo 16 at the entry of a procedure ABI_PushRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8); - MOV(PTRBITS, R(REGISTERS), R(ABI_PARAM1)); - MOV(PTRBITS, R(UNIFORMS), ImmPtr(&g_state.vs.uniforms)); + MOV(PTRBITS, R(SETUP), R(ABI_PARAM1)); + MOV(PTRBITS, R(STATE), R(ABI_PARAM2)); // Zero address/loop registers XOR(64, R(ADDROFFS_REG_0), R(ADDROFFS_REG_0)); @@ -845,7 +845,7 @@ void JitShader::Compile() { MOVAPS(NEGBIT, MatR(RAX)); // Jump to start of the shader program - JMPptr(R(ABI_PARAM2)); + JMPptr(R(ABI_PARAM3)); // Compile entire program Compile_Block(static_cast<unsigned>(g_state.vs.program_code.size())); diff --git a/src/video_core/shader/shader_jit_x64.h b/src/video_core/shader/shader_jit_x64.h index 30aa7ff30..5468459d4 100644 --- a/src/video_core/shader/shader_jit_x64.h +++ b/src/video_core/shader/shader_jit_x64.h @@ -36,8 +36,8 @@ class JitShader : public Gen::XCodeBlock { public: JitShader(); - void Run(void* registers, unsigned offset) const { - program(registers, code_ptr[offset]); + void Run(const ShaderSetup& setup, UnitState<false>& state, unsigned offset) const { + program(&setup, &state, code_ptr[offset]); } void Compile(); @@ -117,7 +117,7 @@ private: /// Branches that need to be fixed up once the entire shader program is compiled std::vector<std::pair<Gen::FixupBranch, unsigned>> fixup_branches; - using CompiledShader = void(void* registers, const u8* start_addr); + using CompiledShader = void(const void* setup, void* state, const u8* start_addr); CompiledShader* program = nullptr; }; |
