|
|
@ -185,10 +185,6 @@ std::string TextureType(const MetaTexture& meta) { |
|
|
return type; |
|
|
return type; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::string GlobalMemoryName(const GlobalMemoryBase& base) { |
|
|
|
|
|
return fmt::format("gmem{}_{}", base.cbuf_index, base.cbuf_offset); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
class ARBDecompiler final { |
|
|
class ARBDecompiler final { |
|
|
public: |
|
|
public: |
|
|
explicit ARBDecompiler(const Device& device, const ShaderIR& ir, const Registry& registry, |
|
|
explicit ARBDecompiler(const Device& device, const ShaderIR& ir, const Registry& registry, |
|
|
@ -199,6 +195,8 @@ public: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
|
|
|
|
void DefineGlobalMemory(); |
|
|
|
|
|
|
|
|
void DeclareHeader(); |
|
|
void DeclareHeader(); |
|
|
void DeclareVertex(); |
|
|
void DeclareVertex(); |
|
|
void DeclareGeometry(); |
|
|
void DeclareGeometry(); |
|
|
@ -228,6 +226,7 @@ private: |
|
|
|
|
|
|
|
|
std::pair<std::string, std::size_t> BuildCoords(Operation); |
|
|
std::pair<std::string, std::size_t> BuildCoords(Operation); |
|
|
std::string BuildAoffi(Operation); |
|
|
std::string BuildAoffi(Operation); |
|
|
|
|
|
std::string GlobalMemoryPointer(const GmemNode& gmem); |
|
|
void Exit(); |
|
|
void Exit(); |
|
|
|
|
|
|
|
|
std::string Assign(Operation); |
|
|
std::string Assign(Operation); |
|
|
@ -378,10 +377,8 @@ private: |
|
|
std::string address; |
|
|
std::string address; |
|
|
std::string_view opname; |
|
|
std::string_view opname; |
|
|
if (const auto gmem = std::get_if<GmemNode>(&*operation[0])) { |
|
|
if (const auto gmem = std::get_if<GmemNode>(&*operation[0])) { |
|
|
AddLine("SUB.U {}, {}, {};", temporary, Visit(gmem->GetRealAddress()), |
|
|
|
|
|
Visit(gmem->GetBaseAddress())); |
|
|
|
|
|
address = fmt::format("{}[{}]", GlobalMemoryName(gmem->GetDescriptor()), temporary); |
|
|
|
|
|
opname = "ATOMB"; |
|
|
|
|
|
|
|
|
address = GlobalMemoryPointer(*gmem); |
|
|
|
|
|
opname = "ATOM"; |
|
|
} else if (const auto smem = std::get_if<SmemNode>(&*operation[0])) { |
|
|
} else if (const auto smem = std::get_if<SmemNode>(&*operation[0])) { |
|
|
address = fmt::format("shared_mem[{}]", Visit(smem->GetAddress())); |
|
|
address = fmt::format("shared_mem[{}]", Visit(smem->GetAddress())); |
|
|
opname = "ATOMS"; |
|
|
opname = "ATOMS"; |
|
|
@ -456,9 +453,13 @@ private: |
|
|
shader_source += '\n'; |
|
|
shader_source += '\n'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::string AllocTemporary() { |
|
|
|
|
|
max_temporaries = std::max(max_temporaries, num_temporaries + 1); |
|
|
|
|
|
return fmt::format("T{}.x", num_temporaries++); |
|
|
|
|
|
|
|
|
std::string AllocLongVectorTemporary() { |
|
|
|
|
|
max_long_temporaries = std::max(max_long_temporaries, num_long_temporaries + 1); |
|
|
|
|
|
return fmt::format("L{}", num_long_temporaries++); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::string AllocLongTemporary() { |
|
|
|
|
|
return fmt::format("{}.x", AllocLongVectorTemporary()); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::string AllocVectorTemporary() { |
|
|
std::string AllocVectorTemporary() { |
|
|
@ -466,8 +467,13 @@ private: |
|
|
return fmt::format("T{}", num_temporaries++); |
|
|
return fmt::format("T{}", num_temporaries++); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::string AllocTemporary() { |
|
|
|
|
|
return fmt::format("{}.x", AllocVectorTemporary()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void ResetTemporaries() noexcept { |
|
|
void ResetTemporaries() noexcept { |
|
|
num_temporaries = 0; |
|
|
num_temporaries = 0; |
|
|
|
|
|
num_long_temporaries = 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const Device& device; |
|
|
const Device& device; |
|
|
@ -478,6 +484,11 @@ private: |
|
|
std::size_t num_temporaries = 0; |
|
|
std::size_t num_temporaries = 0; |
|
|
std::size_t max_temporaries = 0; |
|
|
std::size_t max_temporaries = 0; |
|
|
|
|
|
|
|
|
|
|
|
std::size_t num_long_temporaries = 0; |
|
|
|
|
|
std::size_t max_long_temporaries = 0; |
|
|
|
|
|
|
|
|
|
|
|
std::map<GlobalMemoryBase, u32> global_memory_names; |
|
|
|
|
|
|
|
|
std::string shader_source; |
|
|
std::string shader_source; |
|
|
|
|
|
|
|
|
static constexpr std::string_view ADD_F32 = "ADD.F32"; |
|
|
static constexpr std::string_view ADD_F32 = "ADD.F32"; |
|
|
@ -784,6 +795,8 @@ private: |
|
|
ARBDecompiler::ARBDecompiler(const Device& device, const ShaderIR& ir, const Registry& registry, |
|
|
ARBDecompiler::ARBDecompiler(const Device& device, const ShaderIR& ir, const Registry& registry, |
|
|
ShaderType stage, std::string_view identifier) |
|
|
ShaderType stage, std::string_view identifier) |
|
|
: device{device}, ir{ir}, registry{registry}, stage{stage} { |
|
|
: device{device}, ir{ir}, registry{registry}, stage{stage} { |
|
|
|
|
|
DefineGlobalMemory(); |
|
|
|
|
|
|
|
|
AddLine("TEMP RC;"); |
|
|
AddLine("TEMP RC;"); |
|
|
AddLine("TEMP FSWZA[4];"); |
|
|
AddLine("TEMP FSWZA[4];"); |
|
|
AddLine("TEMP FSWZB[4];"); |
|
|
AddLine("TEMP FSWZB[4];"); |
|
|
@ -829,12 +842,20 @@ std::string_view HeaderStageName(ShaderType stage) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void ARBDecompiler::DefineGlobalMemory() { |
|
|
|
|
|
u32 binding = 0; |
|
|
|
|
|
for (const auto& pair : ir.GetGlobalMemory()) { |
|
|
|
|
|
const GlobalMemoryBase base = pair.first; |
|
|
|
|
|
global_memory_names.emplace(base, binding); |
|
|
|
|
|
++binding; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void ARBDecompiler::DeclareHeader() { |
|
|
void ARBDecompiler::DeclareHeader() { |
|
|
AddLine("!!NV{}5.0", HeaderStageName(stage)); |
|
|
AddLine("!!NV{}5.0", HeaderStageName(stage)); |
|
|
// Enabling this allows us to cheat on some instructions like TXL with SHADOWARRAY2D
|
|
|
// Enabling this allows us to cheat on some instructions like TXL with SHADOWARRAY2D
|
|
|
AddLine("OPTION NV_internal;"); |
|
|
AddLine("OPTION NV_internal;"); |
|
|
AddLine("OPTION NV_gpu_program_fp64;"); |
|
|
AddLine("OPTION NV_gpu_program_fp64;"); |
|
|
AddLine("OPTION NV_shader_storage_buffer;"); |
|
|
|
|
|
AddLine("OPTION NV_shader_thread_group;"); |
|
|
AddLine("OPTION NV_shader_thread_group;"); |
|
|
if (ir.UsesWarps() && device.HasWarpIntrinsics()) { |
|
|
if (ir.UsesWarps() && device.HasWarpIntrinsics()) { |
|
|
AddLine("OPTION NV_shader_thread_shuffle;"); |
|
|
AddLine("OPTION NV_shader_thread_shuffle;"); |
|
|
@ -951,11 +972,10 @@ void ARBDecompiler::DeclareLocalMemory() { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void ARBDecompiler::DeclareGlobalMemory() { |
|
|
void ARBDecompiler::DeclareGlobalMemory() { |
|
|
u32 binding = 0; // device.GetBaseBindings(stage).shader_storage_buffer;
|
|
|
|
|
|
for (const auto& pair : ir.GetGlobalMemory()) { |
|
|
|
|
|
const auto& base = pair.first; |
|
|
|
|
|
AddLine("STORAGE {}[] = {{ program.storage[{}] }};", GlobalMemoryName(base), binding); |
|
|
|
|
|
++binding; |
|
|
|
|
|
|
|
|
const std::size_t num_entries = ir.GetGlobalMemory().size(); |
|
|
|
|
|
if (num_entries > 0) { |
|
|
|
|
|
const std::size_t num_vectors = Common::AlignUp(num_entries, 2) / 2; |
|
|
|
|
|
AddLine("PARAM c[{}] = {{ program.local[0..{}] }};", num_vectors, num_vectors - 1); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -977,6 +997,9 @@ void ARBDecompiler::DeclareTemporaries() { |
|
|
for (std::size_t i = 0; i < max_temporaries; ++i) { |
|
|
for (std::size_t i = 0; i < max_temporaries; ++i) { |
|
|
AddLine("TEMP T{};", i); |
|
|
AddLine("TEMP T{};", i); |
|
|
} |
|
|
} |
|
|
|
|
|
for (std::size_t i = 0; i < max_long_temporaries; ++i) { |
|
|
|
|
|
AddLine("LONG TEMP L{};", i); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void ARBDecompiler::DeclarePredicates() { |
|
|
void ARBDecompiler::DeclarePredicates() { |
|
|
@ -1339,10 +1362,7 @@ std::string ARBDecompiler::Visit(const Node& node) { |
|
|
|
|
|
|
|
|
if (const auto gmem = std::get_if<GmemNode>(&*node)) { |
|
|
if (const auto gmem = std::get_if<GmemNode>(&*node)) { |
|
|
std::string temporary = AllocTemporary(); |
|
|
std::string temporary = AllocTemporary(); |
|
|
AddLine("SUB.U {}, {}, {};", temporary, Visit(gmem->GetRealAddress()), |
|
|
|
|
|
Visit(gmem->GetBaseAddress())); |
|
|
|
|
|
AddLine("LDB.U32 {}, {}[{}];", temporary, GlobalMemoryName(gmem->GetDescriptor()), |
|
|
|
|
|
temporary); |
|
|
|
|
|
|
|
|
AddLine("LOAD.U32 {}, {};", temporary, GlobalMemoryPointer(*gmem)); |
|
|
return temporary; |
|
|
return temporary; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -1419,6 +1439,22 @@ std::string ARBDecompiler::BuildAoffi(Operation operation) { |
|
|
return fmt::format(", offset({})", temporary); |
|
|
return fmt::format(", offset({})", temporary); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::string ARBDecompiler::GlobalMemoryPointer(const GmemNode& gmem) { |
|
|
|
|
|
const u32 binding = global_memory_names.at(gmem.GetDescriptor()); |
|
|
|
|
|
const char result_swizzle = binding % 2 == 0 ? 'x' : 'y'; |
|
|
|
|
|
|
|
|
|
|
|
const std::string pointer = AllocLongVectorTemporary(); |
|
|
|
|
|
std::string temporary = AllocTemporary(); |
|
|
|
|
|
|
|
|
|
|
|
const u32 local_index = binding / 2; |
|
|
|
|
|
AddLine("PK64.U {}, c[{}];", pointer, local_index); |
|
|
|
|
|
AddLine("SUB.U {}, {}, {};", temporary, Visit(gmem.GetRealAddress()), |
|
|
|
|
|
Visit(gmem.GetBaseAddress())); |
|
|
|
|
|
AddLine("CVT.U64.U32 {}.z, {};", pointer, temporary); |
|
|
|
|
|
AddLine("ADD.U64 {}.x, {}.{}, {}.z;", pointer, pointer, result_swizzle, pointer); |
|
|
|
|
|
return fmt::format("{}.x", pointer); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void ARBDecompiler::Exit() { |
|
|
void ARBDecompiler::Exit() { |
|
|
if (stage != ShaderType::Fragment) { |
|
|
if (stage != ShaderType::Fragment) { |
|
|
AddLine("RET;"); |
|
|
AddLine("RET;"); |
|
|
@ -1515,11 +1551,7 @@ std::string ARBDecompiler::Assign(Operation operation) { |
|
|
ResetTemporaries(); |
|
|
ResetTemporaries(); |
|
|
return {}; |
|
|
return {}; |
|
|
} else if (const auto gmem = std::get_if<GmemNode>(&*dest)) { |
|
|
} else if (const auto gmem = std::get_if<GmemNode>(&*dest)) { |
|
|
const std::string temporary = AllocTemporary(); |
|
|
|
|
|
AddLine("SUB.U {}, {}, {};", temporary, Visit(gmem->GetRealAddress()), |
|
|
|
|
|
Visit(gmem->GetBaseAddress())); |
|
|
|
|
|
AddLine("STB.U32 {}, {}[{}];", Visit(src), GlobalMemoryName(gmem->GetDescriptor()), |
|
|
|
|
|
temporary); |
|
|
|
|
|
|
|
|
AddLine("STORE.U32 {}, {};", Visit(src), GlobalMemoryPointer(*gmem)); |
|
|
ResetTemporaries(); |
|
|
ResetTemporaries(); |
|
|
return {}; |
|
|
return {}; |
|
|
} else { |
|
|
} else { |
|
|
|