|
|
|
@ -84,7 +84,8 @@ struct Subroutine {
|
|
|
|
|
class ControlFlowAnalyzer {
|
|
|
|
|
public:
|
|
|
|
|
ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset, const std::string& suffix)
|
|
|
|
|
: program_code(program_code) {
|
|
|
|
|
: program_code(program_code), shader_coverage_begin(main_offset),
|
|
|
|
|
shader_coverage_end(main_offset + 1) {
|
|
|
|
|
|
|
|
|
|
// Recursively finds all subroutines.
|
|
|
|
|
const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END, suffix);
|
|
|
|
@ -96,10 +97,16 @@ public:
|
|
|
|
|
return std::move(subroutines);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::size_t GetShaderLength() const {
|
|
|
|
|
return shader_coverage_end * sizeof(u64);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const ProgramCode& program_code;
|
|
|
|
|
std::set<Subroutine> subroutines;
|
|
|
|
|
std::map<std::pair<u32, u32>, ExitMethod> exit_method_map;
|
|
|
|
|
u32 shader_coverage_begin;
|
|
|
|
|
u32 shader_coverage_end;
|
|
|
|
|
|
|
|
|
|
/// Adds and analyzes a new subroutine if it is not added yet.
|
|
|
|
|
const Subroutine& AddSubroutine(u32 begin, u32 end, const std::string& suffix) {
|
|
|
|
@ -141,6 +148,9 @@ private:
|
|
|
|
|
return exit_method;
|
|
|
|
|
|
|
|
|
|
for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) {
|
|
|
|
|
shader_coverage_begin = std::min(shader_coverage_begin, offset);
|
|
|
|
|
shader_coverage_end = std::max(shader_coverage_end, offset + 1);
|
|
|
|
|
|
|
|
|
|
const Instruction instr = {program_code[offset]};
|
|
|
|
|
if (const auto opcode = OpCode::Decode(instr)) {
|
|
|
|
|
switch (opcode->get().GetId()) {
|
|
|
|
@ -939,9 +949,10 @@ private:
|
|
|
|
|
class GLSLGenerator {
|
|
|
|
|
public:
|
|
|
|
|
GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
|
|
|
|
|
u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix)
|
|
|
|
|
u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix,
|
|
|
|
|
std::size_t shader_length)
|
|
|
|
|
: subroutines(subroutines), program_code(program_code), main_offset(main_offset),
|
|
|
|
|
stage(stage), suffix(suffix) {
|
|
|
|
|
stage(stage), suffix(suffix), shader_length(shader_length) {
|
|
|
|
|
std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
|
|
|
|
|
local_memory_size = header.GetLocalMemorySize();
|
|
|
|
|
regs.SetLocalMemory(local_memory_size);
|
|
|
|
@ -954,7 +965,7 @@ public:
|
|
|
|
|
|
|
|
|
|
/// Returns entries in the shader that are useful for external functions
|
|
|
|
|
ShaderEntries GetEntries() const {
|
|
|
|
|
return {regs.GetConstBuffersDeclarations(), regs.GetSamplers()};
|
|
|
|
|
return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), shader_length};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
@ -3748,6 +3759,7 @@ private:
|
|
|
|
|
Maxwell3D::Regs::ShaderStage stage;
|
|
|
|
|
const std::string& suffix;
|
|
|
|
|
u64 local_memory_size;
|
|
|
|
|
std::size_t shader_length;
|
|
|
|
|
|
|
|
|
|
ShaderWriter shader;
|
|
|
|
|
ShaderWriter declarations;
|
|
|
|
@ -3766,9 +3778,10 @@ std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u
|
|
|
|
|
Maxwell3D::Regs::ShaderStage stage,
|
|
|
|
|
const std::string& suffix) {
|
|
|
|
|
try {
|
|
|
|
|
const auto subroutines =
|
|
|
|
|
ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines();
|
|
|
|
|
GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix);
|
|
|
|
|
ControlFlowAnalyzer analyzer(program_code, main_offset, suffix);
|
|
|
|
|
const auto subroutines = analyzer.GetSubroutines();
|
|
|
|
|
GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix,
|
|
|
|
|
analyzer.GetShaderLength());
|
|
|
|
|
return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
|
|
|
|
|
} catch (const DecompileFail& exception) {
|
|
|
|
|
LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());
|
|
|
|
|