From 27965527906d10eb5255c75da9cd904e58166ad8 Mon Sep 17 00:00:00 2001 From: Jannik Vogel Date: Wed, 30 Mar 2016 06:42:30 +0200 Subject: [PATCH] Make shader code less VS-specific --- .../debugger/graphics_vertex_shader.cpp | 2 +- src/video_core/command_processor.cpp | 4 +-- src/video_core/shader/shader.cpp | 29 ++++++++--------- src/video_core/shader/shader.h | 19 ++++++++--- src/video_core/shader/shader_interpreter.cpp | 6 ++-- src/video_core/shader/shader_jit_x64.cpp | 32 +++++++++---------- src/video_core/shader/shader_jit_x64.h | 15 ++++++++- 7 files changed, 62 insertions(+), 45 deletions(-) diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp index 391666d35..50be59856 100644 --- a/src/citra_qt/debugger/graphics_vertex_shader.cpp +++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp @@ -501,7 +501,7 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d info.labels.insert({ entry_point, "main" }); // Generate debug information - debug_data = Pica::g_state.vs.ProduceDebugInfo(input_vertex, num_attributes, shader_config, shader_setup); + debug_data = Pica::g_state.vs.ProduceDebugInfo(input_vertex, num_attributes, shader_config); // Reload widget state for (int attr = 0; attr < num_attributes; ++attr) { diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 19e03adf4..6c5c3c7cb 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -149,7 +149,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { // Send to vertex shader if (g_debug_context) g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation, static_cast(&immediate_input)); - g_state.vs.Run(shader_unit, immediate_input, regs.vs.num_input_attributes+1); + g_state.vs.Run(shader_unit, immediate_input, regs.vs.num_input_attributes+1, regs.vs); Shader::OutputVertex output_vertex = shader_unit.output_registers.ToVertex(regs.vs); // Send to renderer @@ -274,7 +274,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { // Send to vertex shader if (g_debug_context) g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation, (void*)&input); - g_state.vs.Run(shader_unit, input, loader.GetNumTotalAttributes()); + g_state.vs.Run(shader_unit, input, loader.GetNumTotalAttributes(), regs.vs); output_registers = shader_unit.output_registers; if (is_indexed) { diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp index f565e2c91..9080cb397 100644 --- a/src/video_core/shader/shader.cpp +++ b/src/video_core/shader/shader.cpp @@ -83,8 +83,7 @@ OutputVertex OutputRegisters::ToVertex(const Regs::ShaderConfig& config) { } #ifdef ARCHITECTURE_x86_64 -static std::unordered_map> shader_map; -static const JitShader* jit_shader; +static std::unordered_map> shader_map; #endif // ARCHITECTURE_x86_64 void ClearCache() { @@ -96,16 +95,16 @@ void ClearCache() { void ShaderSetup::Setup() { #ifdef ARCHITECTURE_x86_64 if (VideoCore::g_shader_jit_enabled) { - u64 cache_key = (Common::ComputeHash64(&g_state.vs.program_code, sizeof(g_state.vs.program_code)) ^ - Common::ComputeHash64(&g_state.vs.swizzle_data, sizeof(g_state.vs.swizzle_data))); + u64 cache_key = (Common::ComputeHash64(&program_code, sizeof(program_code)) ^ + Common::ComputeHash64(&swizzle_data, sizeof(swizzle_data))); auto iter = shader_map.find(cache_key); if (iter != shader_map.end()) { - jit_shader = iter->second.get(); + jit_shader = iter->second; } else { - auto shader = std::make_unique(); - shader->Compile(); - jit_shader = shader.get(); + auto shader = std::make_shared(); + shader->Compile(*this); + jit_shader = shader; shader_map[cache_key] = std::move(shader); } } @@ -114,9 +113,7 @@ void ShaderSetup::Setup() { MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240)); -void ShaderSetup::Run(UnitState& state, const InputVertex& input, int num_attributes) { - auto& config = g_state.regs.vs; - auto& setup = g_state.vs; +void ShaderSetup::Run(UnitState& state, const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config) { MICROPROFILE_SCOPE(GPU_Shader); @@ -134,16 +131,16 @@ void ShaderSetup::Run(UnitState& state, const InputVertex& input, int num #ifdef ARCHITECTURE_x86_64 if (VideoCore::g_shader_jit_enabled) - jit_shader->Run(setup, state, config.main_offset); + jit_shader.lock().get()->Run(*this, state, config.main_offset); else - RunInterpreter(setup, state, config.main_offset); + RunInterpreter(*this, state, config.main_offset); #else - RunInterpreter(setup, state, config.main_offset); + RunInterpreter(*this, state, config.main_offset); #endif // ARCHITECTURE_x86_64 } -DebugData ShaderSetup::ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const ShaderSetup& setup) { +DebugData ShaderSetup::ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config) { UnitState state; state.debug.max_offset = 0; @@ -160,7 +157,7 @@ DebugData ShaderSetup::ProduceDebugInfo(const InputVertex& input, int num_ state.conditional_code[0] = false; state.conditional_code[1] = false; - RunInterpreter(setup, state, config.main_offset); + RunInterpreter(*this, state, config.main_offset); return state.debug; } diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h index fee16df62..e9a56c578 100644 --- a/src/video_core/shader/shader.h +++ b/src/video_core/shader/shader.h @@ -30,6 +30,11 @@ namespace Pica { namespace Shader { +#ifdef ARCHITECTURE_x86_64 +// Forward declare JitShader because shader_jit_x64.h requires ShaderSetup (which uses JitShader) from this file +class JitShader; +#endif // ARCHITECTURE_x86_64 + struct InputVertex { alignas(16) Math::Vec4 attr[16]; }; @@ -191,9 +196,9 @@ inline void SetField(DebugDataRecord& record, float24* va record.src3.x = value[0]; record.src3.y = value[1]; record.src3.z = value[2]; + record.src3.w = value[3]; } - template<> inline void SetField(DebugDataRecord& record, float24* value) { record.dest_in.x = value[0]; @@ -353,8 +358,12 @@ struct ShaderSetup { std::array program_code; std::array swizzle_data; +#ifdef ARCHITECTURE_x86_64 + std::weak_ptr jit_shader; +#endif + /** - * Performs any shader unit setup that only needs to happen once per shader (as opposed to once per + * Performs any shader setup that only needs to happen once per shader (as opposed to once per * vertex, which would happen within the `Run` function). */ void Setup(); @@ -364,18 +373,18 @@ struct ShaderSetup { * @param state Shader unit state, must be setup per shader and per shader unit * @param input Input vertex into the shader * @param num_attributes The number of vertex shader attributes + * @param config Configuration object for the shader pipeline */ - void Run(UnitState& state, const InputVertex& input, int num_attributes); + void Run(UnitState& state, const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config); /** * Produce debug information based on the given shader and input vertex * @param input Input vertex into the shader * @param num_attributes The number of vertex shader attributes * @param config Configuration object for the shader pipeline - * @param setup Setup object for the shader pipeline * @return Debug information for this shader with regards to the given vertex */ - DebugData ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const ShaderSetup& setup); + DebugData ProduceDebugInfo(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config); }; diff --git a/src/video_core/shader/shader_interpreter.cpp b/src/video_core/shader/shader_interpreter.cpp index b1eadc071..fcb808a2b 100644 --- a/src/video_core/shader/shader_interpreter.cpp +++ b/src/video_core/shader/shader_interpreter.cpp @@ -47,9 +47,9 @@ void RunInterpreter(const ShaderSetup& setup, UnitState& state, unsigned 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; + const auto& uniforms = setup.uniforms; + const auto& swizzle_data = setup.swizzle_data; + const auto& program_code = setup.program_code; // Placeholder for invalid inputs static float24 dummy_vec4_float24[4]; diff --git a/src/video_core/shader/shader_jit_x64.cpp b/src/video_core/shader/shader_jit_x64.cpp index 43e7e6b4c..a82573a3d 100644 --- a/src/video_core/shader/shader_jit_x64.cpp +++ b/src/video_core/shader/shader_jit_x64.cpp @@ -146,15 +146,6 @@ static const u8 NO_SRC_REG_SWIZZLE = 0x1b; /// Raw constant for the destination register enable mask that indicates all components are enabled static const u8 NO_DEST_REG_MASK = 0xf; -/** - * Get the vertex shader instruction for a given offset in the current shader program - * @param offset Offset in the current shader program of the instruction - * @return Instruction at the specified offset - */ -static Instruction GetVertexShaderInstruction(size_t offset) { - return { g_state.vs.program_code[offset] }; -} - static void LogCritical(const char* msg) { LOG_CRITICAL(HW_GPU, "%s", msg); } @@ -225,7 +216,7 @@ void JitShader::Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRe MOVAPS(dest, MDisp(src_ptr, src_offset_disp)); } - SwizzlePattern swiz = { g_state.vs.swizzle_data[operand_desc_id] }; + SwizzlePattern swiz = { setup->swizzle_data[operand_desc_id] }; // Generate instructions for source register swizzling as needed u8 sel = swiz.GetRawSelector(src_num); @@ -256,7 +247,7 @@ void JitShader::Compile_DestEnable(Instruction instr,X64Reg src) { dest = instr.common.dest.Value(); } - SwizzlePattern swiz = { g_state.vs.swizzle_data[operand_desc_id] }; + SwizzlePattern swiz = { setup->swizzle_data[operand_desc_id] }; int dest_offset_disp = (int)UnitState::OutputOffset(dest); ASSERT_MSG(dest_offset_disp == UnitState::OutputOffset(dest), "Destinaton offset too large for int type"); @@ -512,7 +503,7 @@ void JitShader::Compile_MIN(Instruction instr) { } void JitShader::Compile_MOVA(Instruction instr) { - SwizzlePattern swiz = { g_state.vs.swizzle_data[instr.common.operand_desc_id] }; + SwizzlePattern swiz = { setup->swizzle_data[instr.common.operand_desc_id] }; if (!swiz.DestComponentEnabled(0) && !swiz.DestComponentEnabled(1)) { return; // NoOp @@ -776,7 +767,7 @@ void JitShader::Compile_NextInstr() { ASSERT_MSG(code_ptr[program_counter] == nullptr, "Tried to compile already compiled shader location!"); code_ptr[program_counter] = GetCodePtr(); - Instruction instr = GetVertexShaderInstruction(program_counter++); + Instruction instr = GetShaderInstruction(program_counter++); OpCode::Id opcode = instr.opcode.Value(); auto instr_func = instr_table[static_cast(opcode)]; @@ -794,8 +785,8 @@ void JitShader::Compile_NextInstr() { void JitShader::FindReturnOffsets() { return_offsets.clear(); - for (size_t offset = 0; offset < g_state.vs.program_code.size(); ++offset) { - Instruction instr = GetVertexShaderInstruction(offset); + for (size_t offset = 0; offset < setup->program_code.size(); ++offset) { + Instruction instr = GetShaderInstruction(offset); switch (instr.opcode.Value()) { case OpCode::Id::CALL: @@ -812,7 +803,11 @@ void JitShader::FindReturnOffsets() { std::sort(return_offsets.begin(), return_offsets.end()); } -void JitShader::Compile() { +void JitShader::Compile(const ShaderSetup& setup) { + + // Get a pointer to the setup to access program_code and swizzle_data + this->setup = &setup; + // Reset flow control state program = (CompiledShader*)GetCodePtr(); program_counter = 0; @@ -848,7 +843,7 @@ void JitShader::Compile() { JMPptr(R(ABI_PARAM3)); // Compile entire program - Compile_Block(static_cast(g_state.vs.program_code.size())); + Compile_Block(static_cast(this->setup->program_code.size())); // Set the target for any incomplete branches now that the entire shader program has been emitted for (const auto& branch : fixup_branches) { @@ -865,6 +860,9 @@ void JitShader::Compile() { ASSERT_MSG(size <= MAX_SHADER_SIZE, "Compiled a shader that exceeds the allocated size!"); LOG_DEBUG(HW_GPU, "Compiled shader size=%lu", size); + + // We don't need the setup anymore + this->setup = nullptr; } JitShader::JitShader() { diff --git a/src/video_core/shader/shader_jit_x64.h b/src/video_core/shader/shader_jit_x64.h index 5468459d4..6affa6d15 100644 --- a/src/video_core/shader/shader_jit_x64.h +++ b/src/video_core/shader/shader_jit_x64.h @@ -40,7 +40,7 @@ public: program(&setup, &state, code_ptr[offset]); } - void Compile(); + void Compile(const ShaderSetup& setup); void Compile_ADD(Instruction instr); void Compile_DP3(Instruction instr); @@ -99,6 +99,17 @@ private: */ void Compile_Assert(bool condition, const char* msg); + /** + * Get the shader instruction for a given offset in the current shader program + * @param offset Offset in the current shader program of the instruction + * @return Instruction at the specified offset + */ + Instruction GetShaderInstruction(size_t offset) { + Instruction instruction; + std::memcpy(&instruction, &setup->program_code[offset], sizeof(Instruction)); + return instruction; + } + /** * Analyzes the entire shader program for `CALL` instructions before emitting any code, * identifying the locations where a return needs to be inserted. @@ -119,6 +130,8 @@ private: using CompiledShader = void(const void* setup, void* state, const u8* start_addr); CompiledShader* program = nullptr; + + const ShaderSetup* setup = nullptr; }; } // Shader