diff --git a/include/PICA/shader_decompiler.hpp b/include/PICA/shader_decompiler.hpp index 42bd5642..d992d0df 100644 --- a/include/PICA/shader_decompiler.hpp +++ b/include/PICA/shader_decompiler.hpp @@ -1,10 +1,12 @@ #pragma once +#include <fmt/format.h> + +#include <map> #include <set> #include <string> #include <tuple> -#include <map> -#include <vector> #include <utility> +#include <vector> #include "PICA/shader.hpp" #include "PICA/shader_gen_types.hpp" @@ -42,9 +44,9 @@ namespace PICA::ShaderGen { explicit Function(u32 start, u32 end) : start(start), end(end) {} bool operator<(const Function& other) const { return AddressRange(start, end) < AddressRange(other.start, other.end); } - std::string getIdentifier() const { return "func_" + std::to_string(start) + "_to_" + std::to_string(end); } - std::string getForwardDecl() const { return "void " + getIdentifier() + "();\n"; } - std::string getCallStatement() const { return getIdentifier() + "()"; } + std::string getIdentifier() const { return fmt::format("fn_{}_{}", start, end); } + std::string getForwardDecl() const { return fmt::format("void fn_{}_{}();\n", start, end); } + std::string getCallStatement() const { return fmt::format("fn_{}_{}()", start, end); } }; std::set<Function> functions{}; diff --git a/src/core/PICA/shader_decompiler.cpp b/src/core/PICA/shader_decompiler.cpp index 2adc3661..899aff29 100644 --- a/src/core/PICA/shader_decompiler.cpp +++ b/src/core/PICA/shader_decompiler.cpp @@ -85,7 +85,6 @@ ExitMode ControlFlow::analyzeFunction(const PICAShader& shader, u32 start, u32 e } case ShaderOpcodes::IFU: case ShaderOpcodes::IFC: { - Helpers::panic("IFC/IFU"); const u32 num = instruction & 0xff; const u32 dest = getBits<10, 12>(instruction); @@ -122,7 +121,29 @@ ExitMode ControlFlow::analyzeFunction(const PICAShader& shader, u32 start, u32 e } break; } - case ShaderOpcodes::CALL: Helpers::panic("Unimplemented control flow operation (CALL)"); break; + case ShaderOpcodes::CALL: { + const u32 num = instruction & 0xff; + const u32 dest = getBits<10, 12>(instruction); + const Function* calledFunction = addFunction(shader, dest, dest + num); + + // Check if analysis of the branch taken func failed and return unknown if it did + if (analysisFailed) { + it->second = ExitMode::Unknown; + return it->second; + } + + if (calledFunction->exitMode == ExitMode::AlwaysEnd) { + it->second = ExitMode::AlwaysEnd; + return it->second; + } + + // Exit mode of the remainder of this function, after we return from the callee + ExitMode postCallExitMode = analyzeFunction(shader, pc + 1, end, labels); + ExitMode exitMode = exitSeries(postCallExitMode, calledFunction->exitMode); + + it->second = exitMode; + return exitMode; + } case ShaderOpcodes::CALLC: Helpers::panic("Unimplemented control flow operation (CALLC)"); break; case ShaderOpcodes::CALLU: Helpers::panic("Unimplemented control flow operation (CALLU)"); break; case ShaderOpcodes::LOOP: Helpers::panic("Unimplemented control flow operation (LOOP)"); break; @@ -464,14 +485,71 @@ void ShaderDecompiler::compileInstruction(u32& pc, bool& finished) { const uint refY = getBit<24>(instruction); const uint refX = getBit<25>(instruction); const char* condition = getCondition(condOp, refX, refY); - + decompiledShader += fmt::format("if ({}) {{ pc = {}u; break; }}", condition, dest); break; } + + case ShaderOpcodes::IFU: + case ShaderOpcodes::IFC: { + const u32 num = instruction & 0xff; + const u32 dest = getBits<10, 12>(instruction); + const Function* conditionalFunc = findFunction(AddressRange(pc + 1, dest)); + + if (opcode == ShaderOpcodes::IFC) { + const u32 condOp = getBits<22, 2>(instruction); + const uint refY = getBit<24>(instruction); + const uint refX = getBit<25>(instruction); + const char* condition = getCondition(condOp, refX, refY); + + decompiledShader += fmt::format("if ({}) {{", condition); + } else { + const u32 bit = getBits<22, 4>(instruction); // Bit of the bool uniform to check + const u32 mask = 1u << bit; + + decompiledShader += fmt::format("if ((uniform_bool & {}u) != 0u) {{", mask); + } + + callFunction(*conditionalFunc); + decompiledShader += "}\n"; + + pc = dest; + if (num > 0) { + const Function* elseFunc = findFunction(AddressRange(dest, dest + num)); + pc = dest + num; + + decompiledShader += "else { "; + callFunction(*elseFunc); + decompiledShader += "}\n"; + + if (conditionalFunc->exitMode == ExitMode::AlwaysEnd && elseFunc->exitMode == ExitMode::AlwaysEnd) { + finished = true; + return; + } + } + + return; + } + + case ShaderOpcodes::CALL: { + const u32 num = instruction & 0xff; + const u32 dest = getBits<10, 12>(instruction); + const Function* calledFunc = findFunction(AddressRange(dest, dest + num)); + callFunction(*calledFunc); + + if (opcode == ShaderOpcodes::CALL && calledFunc->exitMode == ExitMode::AlwaysEnd) { + finished = true; + return; + } + break; + } + case ShaderOpcodes::END: decompiledShader += "return;\n"; finished = true; return; + + case ShaderOpcodes::NOP: break; default: Helpers::panic("GLSL recompiler: Unknown opcode: %X", opcode); break; } } diff --git a/src/core/PICA/shader_gen_glsl.cpp b/src/core/PICA/shader_gen_glsl.cpp index 1aa30733..affe9837 100644 --- a/src/core/PICA/shader_gen_glsl.cpp +++ b/src/core/PICA/shader_gen_glsl.cpp @@ -717,15 +717,15 @@ std::string FragmentGenerator::getVertexShaderAccelerated(const std::string& pic std::string semantics = fmt::format( R"( - vec4 a_coords = vec4({}, {}, {}, {}); - vec4 a_quaternion = vec4({}, {}, {}, {}); - vec4 a_vertexColour = vec4({}, {}, {}, {}); - vec2 a_texcoord0 = vec2({}, {}); - float a_texcoord0_w = {}; - vec2 a_texcoord1 = vec2({}, {}); - vec2 a_texcoord2 = vec2({}, {}); - vec3 a_view = vec3({}, {}, {}); - )", + vec4 a_coords = vec4({}, {}, {}, {}); + vec4 a_quaternion = vec4({}, {}, {}, {}); + vec4 a_vertexColour = vec4({}, {}, {}, {}); + vec2 a_texcoord0 = vec2({}, {}); + float a_texcoord0_w = {}; + vec2 a_texcoord1 = vec2({}, {}); + vec2 a_texcoord2 = vec2({}, {}); + vec3 a_view = vec3({}, {}, {}); +)", getSemanticName(0), getSemanticName(1), getSemanticName(2), getSemanticName(3), getSemanticName(4), getSemanticName(5), getSemanticName(6), getSemanticName(7), getSemanticName(8), getSemanticName(9), getSemanticName(10), getSemanticName(11), getSemanticName(12), getSemanticName(13), getSemanticName(16), getSemanticName(14), getSemanticName(15), getSemanticName(22), getSemanticName(23),