mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-27 16:02:37 +00:00
217 lines
8.2 KiB
C++
217 lines
8.2 KiB
C++
#include "common/assert.h"
|
|
#include "graphics/shader/recompiler/BufferFormat.h"
|
|
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
|
#include "graphics/shader/recompiler/ir/ShaderIRInternal.h"
|
|
|
|
#include <algorithm>
|
|
#include <fmt/format.h>
|
|
#include <utility>
|
|
|
|
namespace Libs::Graphics::ShaderRecompiler::IR {
|
|
|
|
std::string RegisterToString(Register reg) {
|
|
switch (reg.file) {
|
|
case RegisterFile::Scalar: return fmt::format("s{}", reg.index);
|
|
case RegisterFile::Vector: return fmt::format("v{}", reg.index);
|
|
case RegisterFile::Vcc:
|
|
return reg.index == 0 ? std::string("vcc_lo") : std::string("vcc_hi");
|
|
case RegisterFile::Exec:
|
|
return reg.index == 0 ? std::string("exec_lo") : std::string("exec_hi");
|
|
case RegisterFile::Scc:
|
|
if (reg.index == static_cast<uint32_t>(Decoder::OperandKind::Scc)) {
|
|
return "scc";
|
|
}
|
|
if (reg.index == static_cast<uint32_t>(Decoder::OperandKind::VccZ)) {
|
|
return "vccz";
|
|
}
|
|
if (reg.index == static_cast<uint32_t>(Decoder::OperandKind::ExecZ)) {
|
|
return "execz";
|
|
}
|
|
return fmt::format("scc_like_{}", reg.index);
|
|
case RegisterFile::M0: return "m0";
|
|
default: return "unknown_reg";
|
|
}
|
|
}
|
|
|
|
std::string OperandToString(const Operand& operand) {
|
|
std::string text;
|
|
switch (operand.kind) {
|
|
case OperandKind::Register: text = RegisterToString(operand.reg); break;
|
|
case OperandKind::ImmediateU32: text = fmt::format("0x{:08x}", operand.imm); break;
|
|
case OperandKind::PcRelativeU32: text = fmt::format("pc_rel(0x{:08x})", operand.imm); break;
|
|
case OperandKind::PcRelativeHighU32:
|
|
text = fmt::format("pc_rel_hi(0x{:08x})", operand.imm);
|
|
break;
|
|
case OperandKind::Null: text = "null"; break;
|
|
default: text = "unknown"; break;
|
|
}
|
|
if (operand.sdwa_sel != 6 || operand.sdwa_sext) {
|
|
text += fmt::format(".sdwa(sel={},sext={})", operand.sdwa_sel, operand.sdwa_sext ? 1u : 0u);
|
|
}
|
|
if (operand.absolute) {
|
|
text += ".abs";
|
|
}
|
|
if (operand.negate) {
|
|
text += ".neg";
|
|
}
|
|
if (operand.op_sel || operand.op_sel_hi || operand.negate_hi) {
|
|
text += fmt::format(".opsel(lo={},hi={},neghi={})", operand.op_sel ? 1u : 0u,
|
|
operand.op_sel_hi ? 1u : 0u, operand.negate_hi ? 1u : 0u);
|
|
}
|
|
if (operand.omod != 0) {
|
|
text += fmt::format(".omod({})", operand.omod);
|
|
}
|
|
if (operand.clamp) {
|
|
text += ".clamp";
|
|
}
|
|
if (operand.dpp) {
|
|
text += fmt::format(".dpp(ctrl=0x{:x},fi={},bc={})", operand.dpp_ctrl,
|
|
operand.dpp_fetch_inactive ? 1u : 0u, operand.dpp_bound_ctrl ? 1u : 0u);
|
|
}
|
|
return text;
|
|
}
|
|
|
|
std::string ResourceKindToString(ResourceKind kind) {
|
|
switch (kind) {
|
|
case ResourceKind::ScalarBuffer: return "scalar_buffer";
|
|
case ResourceKind::ScalarAddress: return "scalar_address";
|
|
case ResourceKind::Buffer: return "buffer";
|
|
case ResourceKind::Flat: return "flat";
|
|
case ResourceKind::Global: return "global";
|
|
case ResourceKind::Scratch: return "scratch";
|
|
case ResourceKind::Lds: return "lds";
|
|
case ResourceKind::Gds: return "gds";
|
|
case ResourceKind::Image: return "image";
|
|
case ResourceKind::ImageUint: return "image_uint";
|
|
case ResourceKind::StorageImage: return "storage_image";
|
|
case ResourceKind::StorageImageUint: return "storage_image_uint";
|
|
case ResourceKind::Sampler: return "sampler";
|
|
default: return "none";
|
|
}
|
|
}
|
|
|
|
std::string MemoryInfoToString(const MemoryInfo& mem) {
|
|
if (mem.kind == ResourceKind::None) {
|
|
return "";
|
|
}
|
|
std::string text = fmt::format(
|
|
" ; {} resource={} sampler={} offset={} offset2={} dmask=0x{:x} data_dwords={} "
|
|
"data_bits={} component={}/{} dfmt={} nfmt={} signed={} typed={} formatted={} segment={} "
|
|
"glc={} slc={} idxen={} offen={} image_flags=0x{:x} image_dim={} image_addr={} "
|
|
"image_mip={} image_r128={}",
|
|
ResourceKindToString(mem.kind).c_str(), mem.resource, mem.sampler, mem.offset,
|
|
mem.secondary_offset, mem.dmask, mem.data_dwords, mem.data_bits, mem.component_index,
|
|
mem.component_count, mem.data_format, mem.number_format, mem.data_signed ? 1u : 0u,
|
|
mem.typed ? 1u : 0u, mem.formatted ? 1u : 0u, mem.memory_segment, mem.glc ? 1u : 0u,
|
|
mem.slc ? 1u : 0u, mem.idxen ? 1u : 0u, mem.offen ? 1u : 0u, mem.image_sample_flags,
|
|
Decoder::ImageDimensionToString(mem.image_dimension), mem.image_address_components,
|
|
mem.image_has_mip ? 1u : 0u, mem.image_r128 ? 1u : 0u);
|
|
if (mem.image_nsa_dwords != 0) {
|
|
text += fmt::format(" image_nsa_dwords={} image_nsa_addr=", mem.image_nsa_dwords);
|
|
const auto count =
|
|
std::min<uint32_t>(mem.image_nsa_dwords * 4u, Decoder::MaxImageNsaAddressComponents);
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
if (i != 0) {
|
|
text += ",";
|
|
}
|
|
text += fmt::format("{}", mem.image_nsa_addr[i]);
|
|
}
|
|
}
|
|
return text;
|
|
}
|
|
|
|
std::string ExportInfoToString(const ExportInfo& exp) {
|
|
return fmt::format(" ; target={} index={} raw=0x{:02x} en=0x{:x} done={} compr={} vm={}",
|
|
ExportTargetKindToString(exp.kind).c_str(), exp.index, exp.target, exp.en,
|
|
exp.done ? 1u : 0u, exp.compr ? 1u : 0u, exp.vm ? 1u : 0u);
|
|
}
|
|
|
|
std::string InputInfoToString(Opcode op, const InputInfo& input) {
|
|
if (op != Opcode::LoadInputF32) {
|
|
return "";
|
|
}
|
|
return fmt::format(" ; input_attr={} input_chan={} input_components={}", input.attr, input.chan,
|
|
input.component_count);
|
|
}
|
|
|
|
std::string TerminatorToString(const CFG::Terminator& term) {
|
|
return fmt::format(
|
|
"term={} cond={} true={} false={} merge={} continue={} loop={} indirect_sgpr={} "
|
|
"indirect_selector={} indirect_targets={} selector_values={}",
|
|
static_cast<uint32_t>(term.kind), CFG::BranchConditionToString(term.condition).c_str(),
|
|
term.true_block, term.false_block, term.merge_block, term.continue_block,
|
|
term.loop_header ? 1u : 0u, term.indirect_pc_sgpr, term.indirect_selector_code,
|
|
static_cast<uint32_t>(term.indirect_targets.size()),
|
|
static_cast<uint32_t>(term.indirect_selector_values.size()));
|
|
}
|
|
|
|
std::string ExportSourcesToString(const Instruction& inst) {
|
|
std::string text;
|
|
for (uint32_t i = 0; i < inst.src_count && i < 4u; i++) {
|
|
text += i == 0 ? " " : ", ";
|
|
text += OperandToString(inst.src[i]);
|
|
}
|
|
return text;
|
|
}
|
|
|
|
std::string InstructionToString(const Instruction& inst) {
|
|
std::string text = fmt::format("0x{:08x}: ", inst.pc);
|
|
if (inst.op == Opcode::Export) {
|
|
text += "Export";
|
|
text += ExportSourcesToString(inst);
|
|
text += ExportInfoToString(inst.export_info);
|
|
return text;
|
|
}
|
|
text += OpcodeName(inst.op);
|
|
text += " ";
|
|
text += OperandToString(inst.dst);
|
|
if (inst.dst2.kind != OperandKind::Null) {
|
|
text += ", ";
|
|
text += OperandToString(inst.dst2);
|
|
}
|
|
for (uint32_t i = 0; i < inst.src_count; i++) {
|
|
text += i == 0 ? ", " : ", ";
|
|
text += OperandToString(inst.src[i]);
|
|
}
|
|
text += MemoryInfoToString(inst.memory);
|
|
text += InputInfoToString(inst.op, inst.input_info);
|
|
return text;
|
|
}
|
|
|
|
std::string ExportTargetKindToString(ExportTargetKind kind) {
|
|
switch (kind) {
|
|
case ExportTargetKind::Null: return "null";
|
|
case ExportTargetKind::Position: return "position";
|
|
case ExportTargetKind::Primitive: return "primitive";
|
|
case ExportTargetKind::Parameter: return "parameter";
|
|
case ExportTargetKind::Mrt: return "mrt";
|
|
case ExportTargetKind::MrtZ: return "mrtz";
|
|
default: return "unknown";
|
|
}
|
|
}
|
|
|
|
std::string ProgramToString(const Program& program) {
|
|
std::string text;
|
|
text += fmt::format("mode={} masks={} fallback={} reason={}\n",
|
|
program.dispatcher_fallback ? "dispatcher" : "structured",
|
|
program.lane_mask_mode == ShaderLaneMaskMode::NativeWave ? "native-wave"
|
|
: "per-invocation",
|
|
CFG::FailureKindToString(program.cfg_failure_kind).c_str(),
|
|
program.fallback_reason.c_str());
|
|
for (const auto& block: program.blocks) {
|
|
text += fmt::format("block_{} pc=0x{:08x} end=0x{:08x} preds={} succs={} {}\n", block.id,
|
|
block.start_pc, block.end_pc,
|
|
static_cast<uint32_t>(block.predecessors.size()),
|
|
static_cast<uint32_t>(block.successors.size()),
|
|
TerminatorToString(block.terminator).c_str());
|
|
for (const auto& inst: block.instructions) {
|
|
text += " ";
|
|
text += InstructionToString(inst);
|
|
text += "\n";
|
|
}
|
|
}
|
|
return text;
|
|
}
|
|
|
|
} // namespace Libs::Graphics::ShaderRecompiler::IR
|