From 0242926a7ca410adb8664955b22677593a29c3ee Mon Sep 17 00:00:00 2001 From: InoriRus Date: Mon, 6 Dec 2021 15:45:28 +1000 Subject: [PATCH] Improve shader recompiler --- source/CMakeLists.txt | 2 +- .../include/Emulator/Graphics/Shader.h | 150 +- .../emulator/src/Graphics/GraphicsRender.cpp | 2 +- source/emulator/src/Graphics/Shader.cpp | 487 +++-- source/emulator/src/Graphics/ShaderSpirv.cpp | 1704 ++++++++++------- 5 files changed, 1417 insertions(+), 928 deletions(-) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index ab6e85a..576fb26 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -75,7 +75,7 @@ if (CLANG AND (KYTY_LINKER STREQUAL LLD)) set(KYTY_LD_OPTIONS "-fuse-ld=lld") endif() -project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.0.1) +project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.0.2) include(src_script.cmake) diff --git a/source/emulator/include/Emulator/Graphics/Shader.h b/source/emulator/include/Emulator/Graphics/Shader.h index 85c8058..4bfee24 100644 --- a/source/emulator/include/Emulator/Graphics/Shader.h +++ b/source/emulator/include/Emulator/Graphics/Shader.h @@ -7,6 +7,8 @@ #include "Emulator/Common.h" +#include + #ifdef KYTY_EMU_ENABLED namespace Kyty::Libs::Graphics { @@ -27,9 +29,6 @@ enum class ShaderType enum class ShaderInstructionType { Unknown, - DsAppend, - DsConsume, - Exp, BufferLoadDword, BufferLoadFormatX, BufferLoadFormatXy, @@ -37,50 +36,78 @@ enum class ShaderInstructionType BufferLoadFormatXyzw, BufferStoreDword, BufferStoreFormatX, + DsAppend, + DsConsume, + Exp, ImageSample, - TBufferLoadFormatXyzw, + SAddI32, + SAndB32, SAndn2B64, SAndSaveexecB64, - SEndpgm, - SCbranchExecz, - SLshlB32, - SLoadDwordx4, - SLoadDwordx8, SBufferLoadDword, + SBufferLoadDwordx16, + SBufferLoadDwordx2, SBufferLoadDwordx4, SBufferLoadDwordx8, - SBufferLoadDwordx16, + SCbranchExecz, + SCbranchScc0, + SCmpEqU32, + SEndpgm, + SLoadDwordx4, + SLoadDwordx8, + SLshlB32, + SLshrB32, SMovB32, SMovB64, + SMulI32, + SNorB64, + SOrB64, + SCselectB32, SSetpcB64, SSwappcB64, SWaitcnt, SWqmB64, + TBufferLoadFormatXyzw, VAddI32, VAndB32, + VAshrrevI32, + VBfeU32, VCmpEqF32, VCmpEqU32, + VCmpGtI32, VCmpLeF32, VCmpLeU32, - VCmpNeU32, VCmpNeqF32, + VCmpNeU32, VCmpxEqU32, VCmpxGtU32, + VCmpxNeU32, VCndmaskB32, VCvtF32U32, + VCvtF32Ubyte0, + VCvtF32Ubyte1, + VCvtF32Ubyte2, + VCvtF32Ubyte3, VCvtPkrtzF16F32, VCvtU32F32, + VInterpP1F32, + VInterpP2F32, + VLshlrevB32, + VLshrB32, + VLshrrevB32, VMacF32, VMadakF32, VMadF32, + VMadU32U24, VMaxF32, VMbcntHiU32B32, VMbcntLoU32B32, VMinF32, VMovB32, VMulF32, - VInterpP1F32, - VInterpP2F32, + VMulLoI32, + VMulU32U24, + VNotB32, VRcpF32, VRsqF32, VSadU32, @@ -123,6 +150,7 @@ enum FormatByte : uint64_t S2A4, // operand_array_to_str(inst.src[2], 4) Attr, // attr%u.%u <- inst.src[1].constant.u, inst.src[2].constant.u Idxen, // idxen + Offen, // offen Float4, // format:float4 Pos0, // pos0 Done, // done @@ -131,6 +159,7 @@ enum FormatByte : uint64_t Param2, // param2 Param3, // param3 Mrt0, // mrt_color0 + Off, // off Compr, // compr Vm, // vm L, // label_%u @@ -151,41 +180,46 @@ constexpr uint64_t FormatDefine(std::initializer_list f) enum Format : uint64_t { - Unknown = FormatDefine({U}), - Empty = FormatDefine({N}), - Imm = FormatDefine({S0}), - Label = FormatDefine({L}), - Mrt0Vsrc0Vsrc1ComprVmDone = FormatDefine({Mrt0, S0, S1, Compr, Vm, Done}), - Mrt0Vsrc0Vsrc1Vsrc2Vsrc3VmDone = FormatDefine({Mrt0, S0, S1, S2, S3, Vm, Done}), - Param0Vsrc0Vsrc1Vsrc2Vsrc3 = FormatDefine({Param0, S0, S1, S2, S3}), - Param1Vsrc0Vsrc1Vsrc2Vsrc3 = FormatDefine({Param1, S0, S1, S2, S3}), - Param2Vsrc0Vsrc1Vsrc2Vsrc3 = FormatDefine({Param2, S0, S1, S2, S3}), - Param3Vsrc0Vsrc1Vsrc2Vsrc3 = FormatDefine({Param3, S0, S1, S2, S3}), - Pos0Vsrc0Vsrc1Vsrc2Vsrc3Done = FormatDefine({Pos0, S0, S1, S2, S3, Done}), - Saddr = FormatDefine({S0A2}), - Sdst4SbaseSoffset = FormatDefine({DA4, S0A2, S1}), - Sdst8SbaseSoffset = FormatDefine({DA8, S0A2, S1}), - SdstSvSoffset = FormatDefine({D, S0A4, S1}), - Sdst4SvSoffset = FormatDefine({DA4, S0A4, S1}), - Sdst8SvSoffset = FormatDefine({DA8, S0A4, S1}), - Sdst16SvSoffset = FormatDefine({DA16, S0A4, S1}), - SVdstSVsrc0 = FormatDefine({D, S0}), - SVdstSVsrc0SVsrc1 = FormatDefine({D, S0, S1}), - Sdst2Ssrc02 = FormatDefine({DA2, S0A2}), - Sdst2Ssrc02Ssrc12 = FormatDefine({DA2, S0A2, S1A2}), - SmaskVsrc0Vsrc1 = FormatDefine({DA2, S0, S1}), - Vdata1VaddrSvSoffsIdxen = FormatDefine({D, S0, S1A4, S2, Idxen}), - Vdata2VaddrSvSoffsIdxen = FormatDefine({DA2, S0, S1A4, S2, Idxen}), - Vdata3VaddrSvSoffsIdxen = FormatDefine({DA3, S0, S1A4, S2, Idxen}), - Vdata4VaddrSvSoffsIdxen = FormatDefine({DA4, S0, S1A4, S2, Idxen}), - Vdata4VaddrSvSoffsIdxenFloat4 = FormatDefine({DA4, S0, S1A4, S2, Idxen, Float4}), - Vdata3Vaddr3StSsDmask7 = FormatDefine({DA3, S0A3, S1A8, S2A4, Dmask7}), - Vdata4Vaddr3StSsDmaskF = FormatDefine({DA4, S0A3, S1A8, S2A4, DmaskF}), - VdstVsrc0Vsrc1Smask2 = FormatDefine({D, S0, S1, S2A2}), - VdstVsrc0Vsrc1Vsrc2 = FormatDefine({D, S0, S1, S2}), - VdstVsrcAttrChan = FormatDefine({D, S0, Attr}), - VdstSdst2Vsrc0Vsrc1 = FormatDefine({D, D2A2, S0, S1}), - VdstGds = FormatDefine({D, Gds}) + Unknown = FormatDefine({U}), + Empty = FormatDefine({N}), + Imm = FormatDefine({S0}), + Label = FormatDefine({L}), + Mrt0OffOffComprVmDone = FormatDefine({Mrt0, Off, Off, Compr, Vm, Done}), + Mrt0Vsrc0Vsrc1ComprVmDone = FormatDefine({Mrt0, S0, S1, Compr, Vm, Done}), + Mrt0Vsrc0Vsrc1Vsrc2Vsrc3VmDone = FormatDefine({Mrt0, S0, S1, S2, S3, Vm, Done}), + Param0Vsrc0Vsrc1Vsrc2Vsrc3 = FormatDefine({Param0, S0, S1, S2, S3}), + Param1Vsrc0Vsrc1Vsrc2Vsrc3 = FormatDefine({Param1, S0, S1, S2, S3}), + Param2Vsrc0Vsrc1Vsrc2Vsrc3 = FormatDefine({Param2, S0, S1, S2, S3}), + Param3Vsrc0Vsrc1Vsrc2Vsrc3 = FormatDefine({Param3, S0, S1, S2, S3}), + Pos0Vsrc0Vsrc1Vsrc2Vsrc3Done = FormatDefine({Pos0, S0, S1, S2, S3, Done}), + Saddr = FormatDefine({S0A2}), + Sdst4SbaseSoffset = FormatDefine({DA4, S0A2, S1}), + Sdst8SbaseSoffset = FormatDefine({DA8, S0A2, S1}), + SdstSvSoffset = FormatDefine({D, S0A4, S1}), + Sdst2SvSoffset = FormatDefine({DA2, S0A4, S1}), + Sdst4SvSoffset = FormatDefine({DA4, S0A4, S1}), + Sdst8SvSoffset = FormatDefine({DA8, S0A4, S1}), + Sdst16SvSoffset = FormatDefine({DA16, S0A4, S1}), + SVdstSVsrc0 = FormatDefine({D, S0}), + SVdstSVsrc0SVsrc1 = FormatDefine({D, S0, S1}), + Sdst2Ssrc02 = FormatDefine({DA2, S0A2}), + Sdst2Ssrc0 = FormatDefine({DA2, S0}), + Sdst2Ssrc02Ssrc12 = FormatDefine({DA2, S0A2, S1A2}), + SmaskVsrc0Vsrc1 = FormatDefine({DA2, S0, S1}), + Ssrc0Ssrc1 = FormatDefine({S0, S1}), + Vdata1VaddrSvSoffsIdxen = FormatDefine({D, S0, S1A4, S2, Idxen}), + Vdata2VaddrSvSoffsIdxen = FormatDefine({DA2, S0, S1A4, S2, Idxen}), + Vdata3VaddrSvSoffsIdxen = FormatDefine({DA3, S0, S1A4, S2, Idxen}), + Vdata4VaddrSvSoffsIdxen = FormatDefine({DA4, S0, S1A4, S2, Idxen}), + Vdata4VaddrSvSoffsIdxenFloat4 = FormatDefine({DA4, S0, S1A4, S2, Idxen, Float4}), + Vdata4Vaddr2SvSoffsOffenIdxenFloat4 = FormatDefine({DA4, S0A2, S1A4, S2, Offen, Idxen, Float4}), + Vdata3Vaddr3StSsDmask7 = FormatDefine({DA3, S0A3, S1A8, S2A4, Dmask7}), + Vdata4Vaddr3StSsDmaskF = FormatDefine({DA4, S0A3, S1A8, S2A4, DmaskF}), + VdstVsrc0Vsrc1Smask2 = FormatDefine({D, S0, S1, S2A2}), + VdstVsrc0Vsrc1Vsrc2 = FormatDefine({D, S0, S1, S2}), + VdstVsrcAttrChan = FormatDefine({D, S0, Attr}), + VdstSdst2Vsrc0Vsrc1 = FormatDefine({D, D2A2, S0, S1}), + VdstGds = FormatDefine({D, Gds}), }; } // namespace ShaderInstructionFormat @@ -201,6 +235,7 @@ enum class ShaderOperandType ExecLo, ExecHi, ExecZ, + Scc, Vgpr, Sgpr, M0 @@ -240,6 +275,12 @@ struct ShaderInstruction ShaderOperand dst2; }; +struct ShaderLabel +{ + uint32_t dst; + uint32_t src; +}; + class ShaderCode { public: @@ -249,8 +290,8 @@ public: [[nodiscard]] const Vector& GetInstructions() const { return m_instructions; } Vector& GetInstructions() { return m_instructions; } - [[nodiscard]] const Vector& GetLabels() const { return m_labels; } - Vector& GetLabels() { return m_labels; } + [[nodiscard]] const Vector& GetLabels() const { return m_labels; } + Vector& GetLabels() { return m_labels; } [[nodiscard]] String DbgDump() const; @@ -259,9 +300,16 @@ public: [[nodiscard]] ShaderType GetType() const { return m_type; } void SetType(ShaderType type) { this->m_type = type; } + [[nodiscard]] bool HasAnyOf(std::initializer_list types) const + { + return std::any_of(types.begin(), types.end(), + [this](auto type) + { return m_instructions.Contains(type, [](auto inst, auto type) { return inst.type == type; }); }); + } + private: Vector m_instructions; - Vector m_labels; + Vector m_labels; ShaderType m_type = ShaderType::Unknown; }; diff --git a/source/emulator/src/Graphics/GraphicsRender.cpp b/source/emulator/src/Graphics/GraphicsRender.cpp index d2b66a4..9454e61 100644 --- a/source/emulator/src/Graphics/GraphicsRender.cpp +++ b/source/emulator/src/Graphics/GraphicsRender.cpp @@ -2616,7 +2616,7 @@ static void FindRenderDepthInfo(const HardwareContext& hw, RenderDepthInfo* r) TileGetDepthSize(z.width, z.height, z.z_info.format, z.stencil_info.format, htile, neo, &stencil_size, &htile_size, &depth_size, &pitch); - EXIT_NOT_IMPLEMENTED((z.pitch_div8_minus1 + 1) * 8 != pitch); + EXIT_NOT_IMPLEMENTED(pitch != 0 && (z.pitch_div8_minus1 + 1) * 8 != pitch); switch (z.z_info.format * 2 + z.stencil_info.format) { diff --git a/source/emulator/src/Graphics/Shader.cpp b/source/emulator/src/Graphics/Shader.cpp index 8b09c1d..15f8c21 100644 --- a/source/emulator/src/Graphics/Shader.cpp +++ b/source/emulator/src/Graphics/Shader.cpp @@ -24,7 +24,8 @@ #ifdef KYTY_EMU_ENABLED #define KYTY_SHADER_PARSER_ARGS \ - [[maybe_unused]] uint32_t pc, const uint32_t *src, [[maybe_unused]] const uint32_t *buffer, [[maybe_unused]] ShaderCode *dst + [[maybe_unused]] uint32_t pc, [[maybe_unused]] const uint32_t *src, [[maybe_unused]] const uint32_t *buffer, \ + [[maybe_unused]] ShaderCode *dst #define KYTY_SHADER_PARSER(f) static uint32_t f(KYTY_SHADER_PARSER_ARGS) #define KYTY_CP_OP_PARSER_ARGS \ [[maybe_unused]] CommandProcessor *cp, [[maybe_unused]] uint32_t cmd_id, [[maybe_unused]] const uint32_t *buffer, \ @@ -103,6 +104,7 @@ static String operand_to_str(ShaderOperand op) case ShaderOperandType::ExecHi: ret = U"exec_hi"; break; case ShaderOperandType::ExecLo: ret = U"exec_lo"; break; case ShaderOperandType::ExecZ: ret = U"execz"; break; + case ShaderOperandType::Scc: ret = U"scc"; break; case ShaderOperandType::M0: ret = U"m0"; break; case ShaderOperandType::Vgpr: ret = String::FromPrintf("v%d", op.register_id); break; case ShaderOperandType::Sgpr: ret = String::FromPrintf("s%d", op.register_id); break; @@ -142,6 +144,8 @@ static String operand_array_to_str(ShaderOperand op, int n) default: break; } + EXIT_IF(ret == U"???"); + if (op.negate) { return U"-" + ret; @@ -157,6 +161,7 @@ static String dbg_fmt_to_str(const ShaderInstruction& inst) case ShaderInstructionFormat::Unknown: return U"Unknown"; break; case ShaderInstructionFormat::Empty: return U"Empty"; break; case ShaderInstructionFormat::Imm: return U"Imm"; break; + case ShaderInstructionFormat::Mrt0OffOffComprVmDone: return U"Mrt0OffOffComprVmDone"; break; case ShaderInstructionFormat::Mrt0Vsrc0Vsrc1ComprVmDone: return U"Mrt0Vsrc0Vsrc1ComprVmDone"; break; case ShaderInstructionFormat::Mrt0Vsrc0Vsrc1Vsrc2Vsrc3VmDone: return U"Mrt0Vsrc0Vsrc1Vsrc2Vsrc3VmDone"; break; case ShaderInstructionFormat::Param0Vsrc0Vsrc1Vsrc2Vsrc3: return U"Param0Vsrc0Vsrc1Vsrc2Vsrc3"; break; @@ -168,18 +173,22 @@ static String dbg_fmt_to_str(const ShaderInstruction& inst) case ShaderInstructionFormat::Sdst4SbaseSoffset: return U"Sdst4SbaseSoffset"; break; case ShaderInstructionFormat::Sdst8SbaseSoffset: return U"Sdst8SbaseSoffset"; break; case ShaderInstructionFormat::SdstSvSoffset: return U"SdstSvSoffset"; break; + case ShaderInstructionFormat::Sdst2SvSoffset: return U"Sdst2SvSoffset"; break; case ShaderInstructionFormat::Sdst4SvSoffset: return U"Sdst4SvSoffset"; break; case ShaderInstructionFormat::Sdst8SvSoffset: return U"Sdst8SvSoffset"; break; case ShaderInstructionFormat::Sdst16SvSoffset: return U"Sdst16SvSoffset"; break; case ShaderInstructionFormat::SVdstSVsrc0: return U"SVdstSVsrc0"; break; case ShaderInstructionFormat::Sdst2Ssrc02: return U"Sdst2Ssrc02"; break; + case ShaderInstructionFormat::Sdst2Ssrc0: return U"Sdst2Ssrc0"; break; case ShaderInstructionFormat::Sdst2Ssrc02Ssrc12: return U"Sdst2Ssrc02Ssrc12"; break; case ShaderInstructionFormat::SmaskVsrc0Vsrc1: return U"SmaskVsrc0Vsrc1"; break; + case ShaderInstructionFormat::Ssrc0Ssrc1: return U"Ssrc0Ssrc1"; break; case ShaderInstructionFormat::Vdata1VaddrSvSoffsIdxen: return U"Vdata1VaddrSvSoffsIdxen"; break; case ShaderInstructionFormat::Vdata2VaddrSvSoffsIdxen: return U"Vdata2VaddrSvSoffsIdxen"; break; case ShaderInstructionFormat::Vdata3VaddrSvSoffsIdxen: return U"Vdata3VaddrSvSoffsIdxen"; break; case ShaderInstructionFormat::Vdata4VaddrSvSoffsIdxen: return U"Vdata4VaddrSvSoffsIdxen"; break; case ShaderInstructionFormat::Vdata4VaddrSvSoffsIdxenFloat4: return U"Vdata4VaddrSvSoffsIdxenFloat4"; break; + case ShaderInstructionFormat::Vdata4Vaddr2SvSoffsOffenIdxenFloat4: return U"Vdata4Vaddr2SvSoffsOffenIdxenFloat4"; break; case ShaderInstructionFormat::Vdata3Vaddr3StSsDmask7: return U"Vdata4Vaddr3StSsDmask7"; break; case ShaderInstructionFormat::Vdata4Vaddr3StSsDmaskF: return U"Vdata4Vaddr3StSsDmaskF"; break; case ShaderInstructionFormat::SVdstSVsrc0SVsrc1: return U"SVdstSVsrc0SVsrc1"; break; @@ -202,6 +211,7 @@ static String dbg_fmt_print(const ShaderInstruction& inst) { return str; } + int src_num = 0; for (;;) { String s; @@ -238,6 +248,7 @@ static String dbg_fmt_print(const ShaderInstruction& inst) case ShaderInstructionFormat::S2A4: s = operand_array_to_str(inst.src[2], 4); break; case ShaderInstructionFormat::Attr: s = String::FromPrintf("attr%u.%u", inst.src[1].constant.u, inst.src[2].constant.u); break; case ShaderInstructionFormat::Idxen: s = U"idxen"; break; + case ShaderInstructionFormat::Offen: s = U"offen"; break; case ShaderInstructionFormat::Float4: s = U"format:float4"; break; case ShaderInstructionFormat::Pos0: s = U"pos0"; break; case ShaderInstructionFormat::Done: s = U"done"; break; @@ -246,6 +257,7 @@ static String dbg_fmt_print(const ShaderInstruction& inst) case ShaderInstructionFormat::Param2: s = U"param2"; break; case ShaderInstructionFormat::Param3: s = U"param3"; break; case ShaderInstructionFormat::Mrt0: s = U"mrt_color0"; break; + case ShaderInstructionFormat::Off: s = U"off"; break; case ShaderInstructionFormat::Compr: s = U"compr"; break; case ShaderInstructionFormat::Vm: s = U"vm"; break; case ShaderInstructionFormat::L: s = String::FromPrintf("label_%04" PRIx32, inst.pc + 4 + inst.src[0].constant.i); break; @@ -254,9 +266,30 @@ static String dbg_fmt_print(const ShaderInstruction& inst) case ShaderInstructionFormat::Gds: s = U"gds"; break; default: EXIT("unknown code: %u\n", static_cast(fu)); } + switch (fu) + { + case ShaderInstructionFormat::L: + case ShaderInstructionFormat::S0: + case ShaderInstructionFormat::S0A2: + case ShaderInstructionFormat::S0A3: + case ShaderInstructionFormat::S0A4: src_num = std::max(src_num, 1); break; + case ShaderInstructionFormat::S1: + case ShaderInstructionFormat::S1A2: + case ShaderInstructionFormat::S1A3: + case ShaderInstructionFormat::S1A4: + case ShaderInstructionFormat::S1A8: src_num = std::max(src_num, 2); break; + case ShaderInstructionFormat::S2: + case ShaderInstructionFormat::S2A2: + case ShaderInstructionFormat::S2A3: + case ShaderInstructionFormat::S2A4: + case ShaderInstructionFormat::Attr: src_num = std::max(src_num, 3); break; + case ShaderInstructionFormat::S3: src_num = std::max(src_num, 4); break; + default: break; + } str = s + (str.IsEmpty() ? U"" : U", " + str); f >>= 8u; } + EXIT_IF(src_num != inst.src_num); if (inst.dst.multiplier == 2.0f) { str += " mul:2"; @@ -294,7 +327,7 @@ String ShaderCode::DbgDump() const String ret; for (const auto& inst: m_instructions) { - if (m_labels.Contains(inst.pc)) + if (m_labels.Contains(inst.pc, [](auto label, auto pc) { return label.dst == pc; })) { ret += String::FromPrintf("label_%04" PRIx32 ":\n", inst.pc); } @@ -363,6 +396,108 @@ static ShaderOperand operand_parse(uint32_t code) return ret; } +KYTY_SHADER_PARSER(shader_parse_sopc) +{ + EXIT_IF(dst == nullptr); + EXIT_IF(src == nullptr); + EXIT_IF(buffer == nullptr || buffer < src); + + uint32_t ssrc1 = (buffer[0] >> 8u) & 0xffu; + uint32_t ssrc0 = (buffer[0] >> 0u) & 0xffu; + uint32_t opcode = (buffer[0] >> 16u) & 0x7fu; + + ShaderInstruction inst; + inst.pc = pc; + inst.src[0] = operand_parse(ssrc0); + inst.src[1] = operand_parse(ssrc1); + inst.src_num = 2; + + uint32_t size = 1; + + if (inst.src[0].type == ShaderOperandType::LiteralConstant) + { + inst.src[0].constant.u = buffer[size]; + size++; + } + + if (inst.src[1].type == ShaderOperandType::LiteralConstant) + { + inst.src[1].constant.u = buffer[size]; + size++; + } + + inst.format = ShaderInstructionFormat::Ssrc0Ssrc1; + + switch (opcode) // NOLINT + { + case 0x06: inst.type = ShaderInstructionType::SCmpEqU32; break; + + default: printf("%s", dst->DbgDump().C_Str()); EXIT("unknown sopc opcode: 0x%02" PRIx32 " at addr 0x%08" PRIx32 "\n", opcode, pc); + } + + dst->GetInstructions().Add(inst); + + return size; +} + +KYTY_SHADER_PARSER(shader_parse_sopk) +{ + KYTY_NOT_IMPLEMENTED; + return 1; +} + +KYTY_SHADER_PARSER(shader_parse_sopp) +{ + EXIT_IF(dst == nullptr); + EXIT_IF(src == nullptr); + EXIT_IF(buffer == nullptr || buffer < src); + + uint32_t opcode = (buffer[0] >> 16u) & 0x7fu; + uint32_t simm = (buffer[0] >> 0u) & 0xffffu; + + ShaderInstruction inst; + inst.pc = pc; + + switch (opcode) + { + case 0x01: + inst.type = ShaderInstructionType::SEndpgm; + inst.format = ShaderInstructionFormat::Empty; + break; + case 0x04: + inst.type = ShaderInstructionType::SCbranchScc0; + inst.format = ShaderInstructionFormat::Label; + inst.src[0].type = ShaderOperandType::LiteralConstant; + inst.src[0].constant.i = static_cast(simm) * 4; + inst.src_num = 1; + break; + case 0x08: + inst.type = ShaderInstructionType::SCbranchExecz; + inst.format = ShaderInstructionFormat::Label; + inst.src[0].type = ShaderOperandType::LiteralConstant; + inst.src[0].constant.i = static_cast(simm) * 4; + inst.src_num = 1; + break; + case 0x0c: + inst.type = ShaderInstructionType::SWaitcnt; + inst.format = ShaderInstructionFormat::Imm; + inst.src[0].type = ShaderOperandType::LiteralConstant; + inst.src[0].constant.u = simm; + inst.src_num = 1; + break; + default: printf("%s", dst->DbgDump().C_Str()); EXIT("unknown sopp opcode: 0x%02" PRIx32 " at addr 0x%08" PRIx32 "\n", opcode, pc); + } + + dst->GetInstructions().Add(inst); + + if (inst.type == ShaderInstructionType::SCbranchScc0 || inst.type == ShaderInstructionType::SCbranchExecz) + { + dst->GetLabels().Add({inst.pc + 4 + inst.src[0].constant.i, inst.pc}); + } + + return 1; +} + KYTY_SHADER_PARSER(shader_parse_sop1) { EXIT_IF(dst == nullptr); @@ -394,10 +529,19 @@ KYTY_SHADER_PARSER(shader_parse_sop1) inst.format = ShaderInstructionFormat::SVdstSVsrc0; break; case 0x04: - inst.type = ShaderInstructionType::SMovB64; - inst.format = ShaderInstructionFormat::Sdst2Ssrc02; - inst.dst.size = 2; - inst.src[0].size = 2; + inst.type = ShaderInstructionType::SMovB64; + inst.dst.size = 2; + switch (inst.src[0].type) + { + case ShaderOperandType::VccLo: + case ShaderOperandType::ExecLo: + case ShaderOperandType::Sgpr: + inst.format = ShaderInstructionFormat::Sdst2Ssrc02; + inst.src[0].size = 2; + break; + case ShaderOperandType::IntegerInlineConstant: inst.format = ShaderInstructionFormat::Sdst2Ssrc0; break; + default: EXIT("unknown src0 type"); + } break; case 0x0a: inst.type = ShaderInstructionType::SWqmB64; @@ -430,51 +574,6 @@ KYTY_SHADER_PARSER(shader_parse_sop1) return size; } -KYTY_SHADER_PARSER(shader_parse_sopp) -{ - EXIT_IF(dst == nullptr); - EXIT_IF(src == nullptr); - EXIT_IF(buffer == nullptr || buffer < src); - - uint32_t opcode = (buffer[0] >> 16u) & 0x7fu; - uint32_t simm = (buffer[0] >> 0u) & 0xffffu; - - ShaderInstruction inst; - inst.pc = pc; - - switch (opcode) - { - case 0x01: - inst.type = ShaderInstructionType::SEndpgm; - inst.format = ShaderInstructionFormat::Empty; - break; - case 0x08: - inst.type = ShaderInstructionType::SCbranchExecz; - inst.format = ShaderInstructionFormat::Label; - inst.src[0].type = ShaderOperandType::LiteralConstant; - inst.src[0].constant.i = static_cast(simm) * 4; - inst.src_num = 1; - break; - case 0x0c: - inst.type = ShaderInstructionType::SWaitcnt; - inst.format = ShaderInstructionFormat::Imm; - inst.src[0].type = ShaderOperandType::LiteralConstant; - inst.src[0].constant.u = simm; - inst.src_num = 1; - break; - default: printf("%s", dst->DbgDump().C_Str()); EXIT("unknown sopp opcode: 0x%02" PRIx32 " at addr 0x%08" PRIx32 "\n", opcode, pc); - } - - dst->GetInstructions().Add(inst); - - if (inst.type == ShaderInstructionType::SCbranchExecz) - { - dst->GetLabels().Add(inst.pc + 4 + inst.src[0].constant.i); - } - - return 1; -} - KYTY_SHADER_PARSER(shader_parse_sop2) { EXIT_IF(dst == nullptr); @@ -486,10 +585,16 @@ KYTY_SHADER_PARSER(shader_parse_sop2) switch (opcode) { case 0x7d: return shader_parse_sop1(pc, src, buffer, dst); break; + case 0x7e: return shader_parse_sopc(pc, src, buffer, dst); break; case 0x7f: return shader_parse_sopp(pc, src, buffer, dst); break; default: break; } + if (opcode >= 0x60) + { + return shader_parse_sopk(pc, src, buffer, dst); + } + uint32_t ssrc1 = (buffer[0] >> 8u) & 0xffu; uint32_t ssrc0 = (buffer[0] >> 0u) & 0xffu; uint32_t sdst = (buffer[0] >> 16u) & 0x7fu; @@ -519,6 +624,16 @@ KYTY_SHADER_PARSER(shader_parse_sop2) switch (opcode) { + case 0x02: inst.type = ShaderInstructionType::SAddI32; break; + case 0x0a: inst.type = ShaderInstructionType::SCselectB32; break; + case 0x0e: inst.type = ShaderInstructionType::SAndB32; break; + case 0x11: + inst.type = ShaderInstructionType::SOrB64; + inst.format = ShaderInstructionFormat::Sdst2Ssrc02Ssrc12; + inst.dst.size = 2; + inst.src[0].size = 2; + inst.src[1].size = 2; + break; case 0x15: inst.type = ShaderInstructionType::SAndn2B64; inst.format = ShaderInstructionFormat::Sdst2Ssrc02Ssrc12; @@ -526,7 +641,16 @@ KYTY_SHADER_PARSER(shader_parse_sop2) inst.src[0].size = 2; inst.src[1].size = 2; break; + case 0x1b: + inst.type = ShaderInstructionType::SNorB64; + inst.format = ShaderInstructionFormat::Sdst2Ssrc02Ssrc12; + inst.dst.size = 2; + inst.src[0].size = 2; + inst.src[1].size = 2; + break; case 0x1e: inst.type = ShaderInstructionType::SLshlB32; break; + case 0x20: inst.type = ShaderInstructionType::SLshrB32; break; + case 0x26: inst.type = ShaderInstructionType::SMulI32; break; default: printf("%s", dst->DbgDump().C_Str()); EXIT("unknown sop2 opcode: 0x%02" PRIx32 " at addr 0x%08" PRIx32 "\n", opcode, pc); } @@ -559,38 +683,20 @@ KYTY_SHADER_PARSER(shader_parse_vopc) size++; } + inst.format = ShaderInstructionFormat::SmaskVsrc0Vsrc1; + inst.dst.type = ShaderOperandType::VccLo; + inst.dst.size = 2; + switch (opcode) { - case 0x0d: - inst.type = ShaderInstructionType::VCmpNeqF32; - inst.format = ShaderInstructionFormat::SmaskVsrc0Vsrc1; - inst.dst.type = ShaderOperandType::VccLo; - inst.dst.size = 2; - break; - case 0xc2: - inst.type = ShaderInstructionType::VCmpEqU32; - inst.format = ShaderInstructionFormat::SmaskVsrc0Vsrc1; - inst.dst.type = ShaderOperandType::VccLo; - inst.dst.size = 2; - break; - case 0xc5: - inst.type = ShaderInstructionType::VCmpNeU32; - inst.format = ShaderInstructionFormat::SmaskVsrc0Vsrc1; - inst.dst.type = ShaderOperandType::VccLo; - inst.dst.size = 2; - break; - case 0xd2: - inst.type = ShaderInstructionType::VCmpxEqU32; - inst.format = ShaderInstructionFormat::SmaskVsrc0Vsrc1; - inst.dst.type = ShaderOperandType::VccLo; - inst.dst.size = 2; - break; - case 0xd4: - inst.type = ShaderInstructionType::VCmpxGtU32; - inst.format = ShaderInstructionFormat::SmaskVsrc0Vsrc1; - inst.dst.type = ShaderOperandType::VccLo; - inst.dst.size = 2; - break; + case 0x02: inst.type = ShaderInstructionType::VCmpEqF32; break; + case 0x0d: inst.type = ShaderInstructionType::VCmpNeqF32; break; + case 0x84: inst.type = ShaderInstructionType::VCmpGtI32; break; + case 0xc2: inst.type = ShaderInstructionType::VCmpEqU32; break; + case 0xc5: inst.type = ShaderInstructionType::VCmpNeU32; break; + case 0xd2: inst.type = ShaderInstructionType::VCmpxEqU32; break; + case 0xd4: inst.type = ShaderInstructionType::VCmpxGtU32; break; + case 0xd5: inst.type = ShaderInstructionType::VCmpxNeU32; break; default: printf("%s", dst->DbgDump().C_Str()); EXIT("unknown vopc opcode: 0x%02" PRIx32 " at addr 0x%08" PRIx32 "\n", opcode, pc); } @@ -623,32 +729,21 @@ KYTY_SHADER_PARSER(shader_parse_vop1) size++; } + inst.format = ShaderInstructionFormat::SVdstSVsrc0; + switch (opcode) { - case 0x01: - inst.type = ShaderInstructionType::VMovB32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0; - break; - case 0x06: - inst.type = ShaderInstructionType::VCvtF32U32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0; - break; - case 0x07: - inst.type = ShaderInstructionType::VCvtU32F32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0; - break; - case 0x2a: - inst.type = ShaderInstructionType::VRcpF32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0; - break; - case 0x2e: - inst.type = ShaderInstructionType::VRsqF32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0; - break; - case 0x33: - inst.type = ShaderInstructionType::VSqrtF32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0; - break; + case 0x01: inst.type = ShaderInstructionType::VMovB32; break; + case 0x06: inst.type = ShaderInstructionType::VCvtF32U32; break; + case 0x07: inst.type = ShaderInstructionType::VCvtU32F32; break; + case 0x11: inst.type = ShaderInstructionType::VCvtF32Ubyte0; break; + case 0x12: inst.type = ShaderInstructionType::VCvtF32Ubyte1; break; + case 0x13: inst.type = ShaderInstructionType::VCvtF32Ubyte2; break; + case 0x14: inst.type = ShaderInstructionType::VCvtF32Ubyte3; break; + case 0x2a: inst.type = ShaderInstructionType::VRcpF32; break; + case 0x2e: inst.type = ShaderInstructionType::VRsqF32; break; + case 0x33: inst.type = ShaderInstructionType::VSqrtF32; break; + case 0x37: inst.type = ShaderInstructionType::VNotB32; break; default: printf("%s", dst->DbgDump().C_Str()); EXIT("unknown vop1 opcode: 0x%02" PRIx32 " at addr 0x%08" PRIx32 "\n", opcode, pc); } @@ -683,6 +778,8 @@ KYTY_SHADER_PARSER(shader_parse_vop2) size++; } + inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; + switch (opcode) { case 0x00: @@ -692,34 +789,18 @@ KYTY_SHADER_PARSER(shader_parse_vop2) inst.src[2].size = 2; inst.src_num = 3; break; - case 0x04: - inst.type = ShaderInstructionType::VSubF32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; - break; - case 0x05: - inst.type = ShaderInstructionType::VSubrevF32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; - break; - case 0x08: - inst.type = ShaderInstructionType::VMulF32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; - break; - case 0x0f: - inst.type = ShaderInstructionType::VMinF32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; - break; - case 0x10: - inst.type = ShaderInstructionType::VMaxF32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; - break; - case 0x1b: - inst.type = ShaderInstructionType::VAndB32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; - break; - case 0x1f: - inst.type = ShaderInstructionType::VMacF32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; - break; + case 0x04: inst.type = ShaderInstructionType::VSubF32; break; + case 0x05: inst.type = ShaderInstructionType::VSubrevF32; break; + case 0x08: inst.type = ShaderInstructionType::VMulF32; break; + case 0x0b: inst.type = ShaderInstructionType::VMulU32U24; break; + case 0x0f: inst.type = ShaderInstructionType::VMinF32; break; + case 0x10: inst.type = ShaderInstructionType::VMaxF32; break; + case 0x15: inst.type = ShaderInstructionType::VLshrB32; break; + case 0x16: inst.type = ShaderInstructionType::VLshrrevB32; break; + case 0x18: inst.type = ShaderInstructionType::VAshrrevI32; break; + case 0x1a: inst.type = ShaderInstructionType::VLshlrevB32; break; + case 0x1b: inst.type = ShaderInstructionType::VAndB32; break; + case 0x1f: inst.type = ShaderInstructionType::VMacF32; break; case 0x21: inst.type = ShaderInstructionType::VMadakF32; inst.format = ShaderInstructionFormat::VdstVsrc0Vsrc1Vsrc2; @@ -729,14 +810,8 @@ KYTY_SHADER_PARSER(shader_parse_vop2) inst.src[2].size = 0; size++; break; - case 0x23: - inst.type = ShaderInstructionType::VMbcntLoU32B32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; - break; - case 0x24: - inst.type = ShaderInstructionType::VMbcntHiU32B32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; - break; + case 0x23: inst.type = ShaderInstructionType::VMbcntLoU32B32; break; + case 0x24: inst.type = ShaderInstructionType::VMbcntHiU32B32; break; case 0x25: inst.type = ShaderInstructionType::VAddI32; inst.format = ShaderInstructionFormat::VdstSdst2Vsrc0Vsrc1; @@ -755,10 +830,7 @@ KYTY_SHADER_PARSER(shader_parse_vop2) inst.dst2.type = ShaderOperandType::VccLo; inst.dst2.size = 2; break; - case 0x2f: - inst.type = ShaderInstructionType::VCvtPkrtzF16F32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; - break; + case 0x2f: inst.type = ShaderInstructionType::VCvtPkrtzF16F32; break; case 0x3e: return shader_parse_vopc(pc, src, buffer, dst); break; case 0x3f: return shader_parse_vop1(pc, src, buffer, dst); break; default: printf("%s", dst->DbgDump().C_Str()); EXIT("unknown vop2 opcode: 0x%02" PRIx32 " at addr 0x%08" PRIx32 "\n", opcode, pc); @@ -840,6 +912,8 @@ KYTY_SHADER_PARSER(shader_parse_vop3) size++; } + inst.format = ShaderInstructionFormat::VdstVsrc0Vsrc1Vsrc2; + switch (opcode) { case 0x02: @@ -856,6 +930,13 @@ KYTY_SHADER_PARSER(shader_parse_vop3) inst.dst = operand_parse(vdst); inst.dst.size = 2; break; + case 0x84: + inst.type = ShaderInstructionType::VCmpGtI32; + inst.format = ShaderInstructionFormat::SmaskVsrc0Vsrc1; + inst.src_num = 2; + inst.dst = operand_parse(vdst); + inst.dst.size = 2; + break; case 0xc2: inst.type = ShaderInstructionType::VCmpEqU32; inst.format = ShaderInstructionFormat::SmaskVsrc0Vsrc1; @@ -883,12 +964,14 @@ KYTY_SHADER_PARSER(shader_parse_vop3) inst.src[2].size = 2; break; case 0x104: - inst.type = ShaderInstructionType::VSubF32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; + inst.type = ShaderInstructionType::VSubF32; + inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; + inst.src_num = 2; break; case 0x108: - inst.type = ShaderInstructionType::VMulF32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; + inst.type = ShaderInstructionType::VMulF32; + inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; + inst.src_num = 2; break; case 0x11f: inst.type = ShaderInstructionType::VMacF32; @@ -901,16 +984,18 @@ KYTY_SHADER_PARSER(shader_parse_vop3) inst.src_num = 2; break; case 0x12f: - inst.type = ShaderInstructionType::VCvtPkrtzF16F32; - inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; + inst.type = ShaderInstructionType::VCvtPkrtzF16F32; + inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; + inst.src_num = 2; break; - case 0x141: - inst.type = ShaderInstructionType::VMadF32; - inst.format = ShaderInstructionFormat::VdstVsrc0Vsrc1Vsrc2; - break; - case 0x15d: - inst.type = ShaderInstructionType::VSadU32; - inst.format = ShaderInstructionFormat::VdstVsrc0Vsrc1Vsrc2; + case 0x141: inst.type = ShaderInstructionType::VMadF32; break; + case 0x143: inst.type = ShaderInstructionType::VMadU32U24; break; + case 0x148: inst.type = ShaderInstructionType::VBfeU32; break; + case 0x15d: inst.type = ShaderInstructionType::VSadU32; break; + case 0x16b: + inst.type = ShaderInstructionType::VMulLoI32; + inst.format = ShaderInstructionFormat::SVdstSVsrc0SVsrc1; + inst.src_num = 2; break; default: printf("%s", dst->DbgDump().C_Str()); EXIT("unknown vop3 opcode: 0x%02" PRIx32 " at addr 0x%08" PRIx32 "\n", opcode, pc); } @@ -937,8 +1022,6 @@ KYTY_SHADER_PARSER(shader_parse_exp) uint32_t vsrc2 = (buffer[1] >> 16u) & 0xffu; uint32_t vsrc3 = (buffer[1] >> 24u) & 0xffu; - EXIT_NOT_IMPLEMENTED(en != 0xf); - ShaderInstruction inst; inst.pc = pc; inst.src[0] = operand_parse(vsrc0 + 256); @@ -952,28 +1035,40 @@ KYTY_SHADER_PARSER(shader_parse_exp) switch (target) { case 0x00: - if (done != 0 && compr != 0 && vm != 0) + if (done != 0 && compr != 0 && vm != 0 && en == 0x0) + { + inst.format = ShaderInstructionFormat::Mrt0OffOffComprVmDone; + inst.src_num = 0; + } else if (done != 0 && compr != 0 && vm != 0 && en == 0xf) { inst.format = ShaderInstructionFormat::Mrt0Vsrc0Vsrc1ComprVmDone; inst.src_num = 2; - } else if (done != 0 && compr == 0 && vm != 0) + } else if (done != 0 && compr == 0 && vm != 0 && en == 0xf) { inst.format = ShaderInstructionFormat::Mrt0Vsrc0Vsrc1Vsrc2Vsrc3VmDone; }; break; case 0x0c: - if (done != 0) + if (done != 0 && en == 0xf) { inst.format = ShaderInstructionFormat::Pos0Vsrc0Vsrc1Vsrc2Vsrc3Done; }; break; - case 0x20: inst.format = ShaderInstructionFormat::Param0Vsrc0Vsrc1Vsrc2Vsrc3; break; - case 0x21: inst.format = ShaderInstructionFormat::Param1Vsrc0Vsrc1Vsrc2Vsrc3; break; - case 0x22: inst.format = ShaderInstructionFormat::Param2Vsrc0Vsrc1Vsrc2Vsrc3; break; - case 0x23: inst.format = ShaderInstructionFormat::Param3Vsrc0Vsrc1Vsrc2Vsrc3; break; default: break; } + if (inst.format == ShaderInstructionFormat::Unknown && done == 0 && compr == 0 && vm == 0 && en == 0xf) + { + switch (target) + { + case 0x20: inst.format = ShaderInstructionFormat::Param0Vsrc0Vsrc1Vsrc2Vsrc3; break; + case 0x21: inst.format = ShaderInstructionFormat::Param1Vsrc0Vsrc1Vsrc2Vsrc3; break; + case 0x22: inst.format = ShaderInstructionFormat::Param2Vsrc0Vsrc1Vsrc2Vsrc3; break; + case 0x23: inst.format = ShaderInstructionFormat::Param3Vsrc0Vsrc1Vsrc2Vsrc3; break; + default: break; + } + } + if (inst.format == ShaderInstructionFormat::Unknown) { printf("%s", dst->DbgDump().C_Str()); @@ -1039,6 +1134,12 @@ KYTY_SHADER_PARSER(shader_parse_smrd) inst.format = ShaderInstructionFormat::SdstSvSoffset; inst.src[0].size = 4; break; + case 0x09: + inst.type = ShaderInstructionType::SBufferLoadDwordx2; + inst.format = ShaderInstructionFormat::Sdst2SvSoffset; + inst.src[0].size = 4; + inst.dst.size = 2; + break; case 0x0a: inst.type = ShaderInstructionType::SBufferLoadDwordx4; inst.format = ShaderInstructionFormat::Sdst4SvSoffset; @@ -1293,7 +1394,7 @@ KYTY_SHADER_PARSER(shader_parse_mtbuf) uint32_t vaddr = (buffer[1] >> 0u) & 0xffu; EXIT_NOT_IMPLEMENTED(idxen == 0); - EXIT_NOT_IMPLEMENTED(offen == 1); + // EXIT_NOT_IMPLEMENTED(offen == 1); EXIT_NOT_IMPLEMENTED(offset != 0); EXIT_NOT_IMPLEMENTED(glc == 1); EXIT_NOT_IMPLEMENTED(slc == 1); @@ -1317,13 +1418,16 @@ KYTY_SHADER_PARSER(shader_parse_mtbuf) size++; } + inst.src[1].size = 4; + switch (opcode) // NOLINT { case 0x03: - inst.type = ShaderInstructionType::TBufferLoadFormatXyzw; - inst.format = ShaderInstructionFormat::Vdata4VaddrSvSoffsIdxenFloat4; - inst.src[1].size = 4; - inst.dst.size = 4; + inst.type = ShaderInstructionType::TBufferLoadFormatXyzw; + inst.format = (offen == 1 ? ShaderInstructionFormat::Vdata4Vaddr2SvSoffsOffenIdxenFloat4 + : ShaderInstructionFormat::Vdata4VaddrSvSoffsIdxenFloat4); + inst.src[0].size += static_cast(offen); + inst.dst.size = 4; break; default: printf("%s", dst->DbgDump().C_Str()); EXIT("unknown mtbuf opcode: 0x%02" PRIx32 " at addr 0x%08" PRIx32 "\n", opcode, pc); } @@ -1426,7 +1530,8 @@ KYTY_SHADER_PARSER(shader_parse) EXIT("unknown code 0x%08" PRIx32 " at addr 0x%08" PRIx32 "\n", ptr[0], pc); } - if ((instruction == 0xBF810000 && (type == ShaderType::Vertex || type == ShaderType::Pixel || type == ShaderType::Compute)) || + if ((instruction == 0xBF810000 && (type == ShaderType::Vertex || type == ShaderType::Pixel || type == ShaderType::Compute) && + !dst->GetLabels().Contains(4 * static_cast(ptr - src), [](auto label, auto pc) { return label.dst == pc; })) || (instruction == 0xBE802000 && type == ShaderType::Fetch)) { break; @@ -1512,23 +1617,23 @@ static void bi_print(const char* func, const ShaderBinaryInfo& bi) { printf("%s\n", func); - printf("\t m_signature = %.7s\n", bi.signature); - printf("\t m_version = 0x%02" PRIx8 "\n", bi.version); - printf("\t m_pssl_or_cg = 0x%08" PRIx32 "\n", static_cast(bi.pssl_or_cg)); - printf("\t m_cached = 0x%08" PRIx32 "\n", static_cast(bi.cached)); - printf("\t m_type = 0x%08" PRIx32 "\n", static_cast(bi.type)); - printf("\t m_source_type = 0x%08" PRIx32 "\n", static_cast(bi.source_type)); - printf("\t m_length = 0x%08" PRIx32 "\n", static_cast(bi.length)); - printf("\t m_chunkUsageBaseOffsetInDW = 0x%02" PRIx8 "\n", bi.chunk_usage_base_offset_dw); - printf("\t m_numInputUsageSlots = 0x%02" PRIx8 "\n", bi.num_input_usage_slots); - printf("\t m_isSrt = 0x%02" PRIx8 "\n", bi.is_srt); - printf("\t m_isSrtUsedInfoValid = 0x%02" PRIx8 "\n", bi.is_srt_used_info_valid); - printf("\t m_isExtendedUsageInfo = 0x%02" PRIx8 "\n", bi.is_extended_usage_info); - printf("\t m_reserved2 = 0x%02" PRIx8 "\n", bi.reserved2); - printf("\t m_reserved3 = 0x%02" PRIx8 "\n", bi.reserved3); - printf("\t m_shaderHash0 = 0x%08" PRIx32 "\n", bi.hash0); - printf("\t m_shaderHash1 = 0x%08" PRIx32 "\n", bi.hash1); - printf("\t m_crc32 = 0x%08" PRIx32 "\n", bi.crc32); + printf("\t signature = %.7s\n", bi.signature); + printf("\t version = 0x%02" PRIx8 "\n", bi.version); + printf("\t pssl_or_cg = 0x%08" PRIx32 "\n", static_cast(bi.pssl_or_cg)); + printf("\t cached = 0x%08" PRIx32 "\n", static_cast(bi.cached)); + printf("\t type = 0x%08" PRIx32 "\n", static_cast(bi.type)); + printf("\t source_type = 0x%08" PRIx32 "\n", static_cast(bi.source_type)); + printf("\t length = 0x%08" PRIx32 "\n", static_cast(bi.length)); + printf("\t chunk_usage_base_offset_dw = 0x%02" PRIx8 "\n", bi.chunk_usage_base_offset_dw); + printf("\t num_input_usage_slots = 0x%02" PRIx8 "\n", bi.num_input_usage_slots); + printf("\t is_srt = 0x%02" PRIx8 "\n", bi.is_srt); + printf("\t is_srt_used_info_valid = 0x%02" PRIx8 "\n", bi.is_srt_used_info_valid); + printf("\t is_extended_usage_info = 0x%02" PRIx8 "\n", bi.is_extended_usage_info); + printf("\t reserved2 = 0x%02" PRIx8 "\n", bi.reserved2); + printf("\t reserved3 = 0x%02" PRIx8 "\n", bi.reserved3); + printf("\t hash0 = 0x%08" PRIx32 "\n", bi.hash0); + printf("\t hash1 = 0x%08" PRIx32 "\n", bi.hash1); + printf("\t crc32 = 0x%08" PRIx32 "\n", bi.crc32); } static void vs_check(const VsStageRegisters& vs) @@ -2089,7 +2194,7 @@ void ShaderGetInputInfoPS(const PixelShaderInfo* regs, const ShaderVertexInputIn EXIT_IF(ps_info == nullptr); EXIT_IF(regs == nullptr); - ps_info->input_num = regs->ps_input_num; + ps_info->input_num = regs->ps_regs.ps_in_control; ps_info->ps_pos_xy = (regs->ps_regs.ps_input_ena == 0x00000302 && regs->ps_regs.ps_input_addr == 0x00000302); ps_info->ps_pixel_kill_enable = regs->ps_regs.shader_kill_enable; diff --git a/source/emulator/src/Graphics/ShaderSpirv.cpp b/source/emulator/src/Graphics/ShaderSpirv.cpp index 3918967..f8a6004 100644 --- a/source/emulator/src/Graphics/ShaderSpirv.cpp +++ b/source/emulator/src/Graphics/ShaderSpirv.cpp @@ -13,7 +13,7 @@ #define KYTY_RECOMPILER_ARGS \ [[maybe_unused]] uint32_t index, [[maybe_unused]] const ShaderCode &code, [[maybe_unused]] String *dst_source, \ - [[maybe_unused]] Spirv *spirv + [[maybe_unused]] Spirv *spirv, [[maybe_unused]] const char32_t **param, [[maybe_unused]] SccCheck scc_check #define KYTY_RECOMPILER_FUNC(f) static bool f(KYTY_RECOMPILER_ARGS) namespace Kyty::Libs::Graphics { @@ -115,6 +115,81 @@ constexpr char32_t FUNC_FETCH_1[] = UR"( OpFunctionEnd )"; +constexpr char32_t FUNC_ABS_DIFF[] = UR"( + ; uint abs_diff(uint u1, uint u2) + ; { + ; return max(u1,u2)-min(u1,u2); + ; } +%abs_diff = OpFunction %uint None %function_u_u + %abs_diff_18 = OpFunctionParameter %uint + %abs_diff_19 = OpFunctionParameter %uint + %abs_diff_21 = OpLabel + %abs_diff_50 = OpExtInst %uint %GLSL_std_450 UMax %abs_diff_18 %abs_diff_19 + %abs_diff_53 = OpExtInst %uint %GLSL_std_450 UMin %abs_diff_18 %abs_diff_19 + %abs_diff_54 = OpISub %uint %abs_diff_50 %abs_diff_53 + OpReturnValue %abs_diff_54 + OpFunctionEnd +)"; + +constexpr char32_t FUNC_MUL_EXTENDED[] = UR"( + ; uint mul_lo_uint(uint u1, uint u2) + ; { + ; uint r1, r2; + ; umulExtended(u1, u2, r1, r2); + ; return r2; + ; } + ; uint mul_hi_uint(uint u1, uint u2) + ; { + ; uint r1, r2; + ; umulExtended(u1, u2, r1, r2); + ; return r1; + ; } + ; int mul_lo_int(int i1, int i2) + ; { + ; int r1, r2; + ; imulExtended(i1, i2, r1, r2); + ; return r2; + ; } + ; int mul_hi_int(int i1, int i2) + ; { + ; int r1, r2; + ; imulExtended(i1, i2, r1, r2); + ; return r1; + ; } + %mul_lo_uint = OpFunction %uint None %function_u_u + %22 = OpFunctionParameter %uint + %23 = OpFunctionParameter %uint + %25 = OpLabel + %79 = OpUMulExtended %ResTypeU %22 %23 + %80 = OpCompositeExtract %uint %79 0 + OpReturnValue %80 + OpFunctionEnd + %mul_hi_uint = OpFunction %uint None %function_u_u + %26 = OpFunctionParameter %uint + %27 = OpFunctionParameter %uint + %29 = OpLabel + %89 = OpUMulExtended %ResTypeU %26 %27 + %91 = OpCompositeExtract %uint %89 1 + OpReturnValue %91 + OpFunctionEnd + %mul_lo_int = OpFunction %int None %function_i_i + %31 = OpFunctionParameter %int + %32 = OpFunctionParameter %int + %34 = OpLabel + %100 = OpSMulExtended %ResTypeI %31 %32 + %101 = OpCompositeExtract %int %100 0 + OpReturnValue %101 + OpFunctionEnd + %mul_hi_int = OpFunction %int None %function_i_i + %35 = OpFunctionParameter %int + %36 = OpFunctionParameter %int + %38 = OpLabel + %110 = OpSMulExtended %ResTypeI %35 %36 + %112 = OpCompositeExtract %int %110 1 + OpReturnValue %112 + OpFunctionEnd +)"; + constexpr char32_t BUFFER_LOAD_FLOAT1[] = UR"( ; void buffer_load_float1(out float p1, in int index, in int offset, in int stride, in int buffer_index) ; { @@ -392,6 +467,38 @@ constexpr char32_t SBUFFER_LOAD_DWORD[] = UR"( OpFunctionEnd )"; +constexpr char32_t SBUFFER_LOAD_DWORD_2[] = UR"( + ; void sbuffer_load_dwordx2(out uint p1, out uint p2, in int offset, in int buffer_index) + ; { + ; int addr = offset/4; + ; p1 = floatBitsToUint(buf[buffer_index].data[addr+0]); + ; p2 = floatBitsToUint(buf[buffer_index].data[addr+1]); + ; } +%sbuffer_load_dword_2 = OpFunction %void None %function_sbuffer_load_dword_2 + %sbuf_dw2_11 = OpFunctionParameter %_ptr_Function_uint + %sbuf_dw2_12 = OpFunctionParameter %_ptr_Function_uint + %sbuf_dw2_13 = OpFunctionParameter %_ptr_Function_int + %sbuf_dw2_14 = OpFunctionParameter %_ptr_Function_int + %sbuf_dw2_16 = OpLabel + %sbuf_dw2_17 = OpVariable %_ptr_Function_int Function + %sbuf_dw2_18 = OpLoad %int %sbuf_dw2_13 + %sbuf_dw2_20 = OpSDiv %int %sbuf_dw2_18 %int_4 + OpStore %sbuf_dw2_17 %sbuf_dw2_20 + %sbuf_dw2_28 = OpLoad %int %sbuf_dw2_14 + %sbuf_dw2_33 = OpAccessChain %_ptr_StorageBuffer_float %buf %sbuf_dw2_28 %int_0 %sbuf_dw2_20 + %sbuf_dw2_34 = OpLoad %float %sbuf_dw2_33 + %sbuf_dw2_35 = OpBitcast %uint %sbuf_dw2_34 + OpStore %sbuf_dw2_11 %sbuf_dw2_35 + %sbuf_dw2_36 = OpLoad %int %sbuf_dw2_14 + %sbuf_dw2_39 = OpIAdd %int %sbuf_dw2_20 %int_1 + %sbuf_dw2_40 = OpAccessChain %_ptr_StorageBuffer_float %buf %sbuf_dw2_36 %int_0 %sbuf_dw2_39 + %sbuf_dw2_41 = OpLoad %float %sbuf_dw2_40 + %sbuf_dw2_42 = OpBitcast %uint %sbuf_dw2_41 + OpStore %sbuf_dw2_12 %sbuf_dw2_42 + OpReturn + OpFunctionEnd +)"; + constexpr char32_t SBUFFER_LOAD_DWORD_4[] = UR"( ; void sbuffer_load_dwordx4(out uint p1, out uint p2, out uint p3, out uint p4, in int offset, in int buffer_index) ; { @@ -761,6 +868,36 @@ constexpr char32_t EXECZ[] = UR"( OpStore %execz %z196_ )"; +constexpr char32_t SCC_NZ_1[] = UR"( + %snz1_118_ = OpLoad %uint % + %snz1_121_ = OpINotEqual %bool %snz1_118_ %uint_0 + %snz1_123_ = OpSelect %uint %snz1_121_ %uint_1 %uint_0 + OpStore %scc %snz1_123_ +)"; + +constexpr char32_t SCC_NZ_2[] = UR"( + %snz2_124_ = OpLoad %uint % + %snz2_125_ = OpINotEqual %bool %snz2_124_ %uint_0 + %snz2_127_ = OpLoad %uint % + %snz2_128_ = OpINotEqual %bool %snz2_127_ %uint_0 + %snz2_129_ = OpLogicalOr %bool %snz2_125_ %snz2_128_ + %snz2_130_ = OpSelect %uint %snz2_129_ %uint_1 %uint_0 + OpStore %scc %snz2_130_ +)"; + +constexpr char32_t SCC_OVERFLOW_1[] = UR"( + %so1_124_ = OpExtInst %int %GLSL_std_450 SSign %t0_ + %so1_127_ = OpExtInst %int %GLSL_std_450 SSign %t1_ + %so1_129_ = OpLoad %uint % + %so1_130_ = OpBitcast %int %so1_129_ + %so1_131_ = OpExtInst %int %GLSL_std_450 SSign %so1_130_ + %so1_135_ = OpIEqual %bool %so1_124_ %so1_127_ + %so1_138_ = OpINotEqual %bool %so1_131_ %so1_124_ + %so1_139_ = OpLogicalAnd %bool %so1_135_ %so1_138_ + %so1_142_ = OpSelect %uint %so1_139_ %uint_1 %uint_0 + OpStore %scc %so1_142_ +)"; + constexpr char32_t CLAMP[] = UR"( %c197_ = OpLoad %float % %c200_ = OpExtInst %float %GLSL_std_450 FClamp %c197_ %float_0_000000 %float_1_000000 @@ -775,6 +912,13 @@ constexpr char32_t MULTIPLY[] = UR"( class Spirv; +enum class SccCheck +{ + None, + NonZero, + Overflow, +}; + using inst_recompile_func_t = bool (*)(KYTY_RECOMPILER_ARGS); enum class SpirvType @@ -878,11 +1022,14 @@ private: Core::Array2 m_extended_mapping {}; }; +// NOLINTNEXTLINE(clang-analyzer-optin.performance.Padding) struct RecompilerFunc { - inst_recompile_func_t func = nullptr; - ShaderInstructionType type = ShaderInstructionType::Unknown; - ShaderInstructionFormat::Format format = ShaderInstructionFormat::Unknown; + inst_recompile_func_t func = nullptr; + ShaderInstructionType type = ShaderInstructionType::Unknown; + ShaderInstructionFormat::Format format = ShaderInstructionFormat::Unknown; + const char32_t* param[4] = {nullptr, nullptr, nullptr, nullptr}; + SccCheck scc_check = SccCheck::None; }; static bool operand_is_constant(ShaderOperand op) @@ -895,7 +1042,7 @@ static bool operand_is_variable(ShaderOperand op) { return (op.type == ShaderOperandType::Vgpr || op.type == ShaderOperandType::VccLo || op.type == ShaderOperandType::VccHi || op.type == ShaderOperandType::Sgpr || op.type == ShaderOperandType::ExecLo || op.type == ShaderOperandType::ExecHi || - op.type == ShaderOperandType::ExecZ || op.type == ShaderOperandType::M0); + op.type == ShaderOperandType::ExecZ || op.type == ShaderOperandType::Scc || op.type == ShaderOperandType::M0); } static SpirvValue operand_variable_to_str(ShaderOperand op) @@ -934,6 +1081,10 @@ static SpirvValue operand_variable_to_str(ShaderOperand op) ret.value = U"execz"; ret.type = SpirvType::Uint; break; + case ShaderOperandType::Scc: + ret.value = U"scc"; + ret.type = SpirvType::Uint; + break; case ShaderOperandType::M0: ret.value = U"m0"; ret.type = SpirvType::Uint; @@ -1018,13 +1169,21 @@ static bool operand_load_int(Spirv* spirv, ShaderOperand op, const String& resul { auto value = operand_variable_to_str(op); - EXIT_NOT_IMPLEMENTED(value.type != SpirvType::Float); - - *load = - (String(U"%t = OpLoad %float %\n") + String(U' ', 10) + String(U"% = OpBitcast %int %t\n")) - .ReplaceStr(U"", index) - .ReplaceStr(U"", value.value) - .ReplaceStr(U"", result_id); + if (value.type == SpirvType::Float) + { + *load = (String(U"%t = OpLoad %float %\n") + String(U' ', 10) + + String(U"% = OpBitcast %int %t\n")) + .ReplaceStr(U"", index) + .ReplaceStr(U"", value.value) + .ReplaceStr(U"", result_id); + } else if (value.type == SpirvType::Uint) + { + *load = (String(U"%t = OpLoad %uint %\n") + String(U' ', 10) + + String(U"% = OpBitcast %int %t\n")) + .ReplaceStr(U"", index) + .ReplaceStr(U"", value.value) + .ReplaceStr(U"", result_id); + } } else { return false; @@ -1121,6 +1280,30 @@ static bool operand_load_float(Spirv* spirv, ShaderOperand op, const String& res return true; } +static String get_scc_check(SccCheck scc_check, int dst_num) +{ + EXIT_IF(dst_num < 1 || dst_num > 2); + + if (dst_num == 1) + { + switch (scc_check) + { + case SccCheck::NonZero: return SCC_NZ_1; break; + case SccCheck::Overflow: return SCC_OVERFLOW_1; break; + default: break; + } + } else if (dst_num == 2) + { + switch (scc_check) + { + case SccCheck::NonZero: return SCC_NZ_2; break; + case SccCheck::Overflow: KYTY_NOT_IMPLEMENTED; break; + default: break; + } + } + return U""; +} + KYTY_RECOMPILER_FUNC(Recompile_BufferLoadDword_Vdata1VaddrSvSoffsIdxen) { const auto& inst = code.GetInstructions().At(index); @@ -1453,6 +1636,40 @@ KYTY_RECOMPILER_FUNC(Recompile_DsConsume_VdstGds) return false; } +KYTY_RECOMPILER_FUNC(Recompile_Exp_Mrt0OffOffComprVmDone) +{ + EXIT_NOT_IMPLEMENTED(index == 0 || index + 1 >= code.GetInstructions().Size()); + + const auto& prev_inst = code.GetInstructions().At(index - 1); + const auto& inst = code.GetInstructions().At(index); + const auto& next_inst = code.GetInstructions().At(index + 1); + + if (!(prev_inst.type == ShaderInstructionType::SMovB64 && prev_inst.format == ShaderInstructionFormat::Sdst2Ssrc0 && + prev_inst.dst.type == ShaderOperandType::ExecLo && prev_inst.src[0].type == ShaderOperandType::IntegerInlineConstant && + prev_inst.src[0].constant.i == 0 && next_inst.type == ShaderInstructionType::SEndpgm)) + { + return false; + } + + const auto* info = spirv->GetPsInputInfo(); + + EXIT_NOT_IMPLEMENTED(info == nullptr || !info->ps_pixel_kill_enable); + EXIT_NOT_IMPLEMENTED(info->target_output_mode[0] != 4); + + EXIT_NOT_IMPLEMENTED(inst.src_num > 0); + + // TODO() check VSKIP + // TODO() check EXEC + + static const char32_t* text = UR"( + OpKill +)"; + + *dst_source += String(text); + + return true; +} + KYTY_RECOMPILER_FUNC(Recompile_Exp_Mrt0Vsrc0Vsrc1ComprVmDone) { const auto& inst = code.GetInstructions().At(index); @@ -1529,7 +1746,8 @@ KYTY_RECOMPILER_FUNC(Recompile_Exp_Mrt0Vsrc0Vsrc1Vsrc2Vsrc3VmDone) return true; } -KYTY_RECOMPILER_FUNC(Recompile_Exp_Param0Vsrc0Vsrc1Vsrc2Vsrc3) +/* XXX: 0, 1, 2, 3*/ +KYTY_RECOMPILER_FUNC(Recompile_Exp_Param_XXX_Vsrc0Vsrc1Vsrc2Vsrc3) { const auto& inst = code.GetInstructions().At(index); @@ -1552,7 +1770,7 @@ KYTY_RECOMPILER_FUNC(Recompile_Exp_Param0Vsrc0Vsrc1Vsrc2Vsrc3) %t2_ = OpLoad %float % %t3_ = OpLoad %float % %t4_ = OpCompositeConstruct %v4float %t0_ %t1_ %t2_ %t3_ - OpStore %param0 %t4_ + OpStore % %t4_ )"; *dst_source += String(text) @@ -1560,115 +1778,8 @@ KYTY_RECOMPILER_FUNC(Recompile_Exp_Param0Vsrc0Vsrc1Vsrc2Vsrc3) .ReplaceStr(U"", src0_value.value) .ReplaceStr(U"", src1_value.value) .ReplaceStr(U"", src2_value.value) - .ReplaceStr(U"", src3_value.value); - - return true; -} - -KYTY_RECOMPILER_FUNC(Recompile_Exp_Param1Vsrc0Vsrc1Vsrc2Vsrc3) -{ - const auto& inst = code.GetInstructions().At(index); - - EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.src[0])); - EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.src[1])); - EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.src[2])); - EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.src[3])); - - auto src0_value = operand_variable_to_str(inst.src[0]); - auto src1_value = operand_variable_to_str(inst.src[1]); - auto src2_value = operand_variable_to_str(inst.src[2]); - auto src3_value = operand_variable_to_str(inst.src[3]); - - // TODO() check VSKIP - // TODO() check EXEC - - static const char32_t* text = UR"( - %t0_ = OpLoad %float % - %t1_ = OpLoad %float % - %t2_ = OpLoad %float % - %t3_ = OpLoad %float % - %t4_ = OpCompositeConstruct %v4float %t0_ %t1_ %t2_ %t3_ - OpStore %param1 %t4_ -)"; - - *dst_source += String(text) - .ReplaceStr(U"", String::FromPrintf("%u", index)) - .ReplaceStr(U"", src0_value.value) - .ReplaceStr(U"", src1_value.value) - .ReplaceStr(U"", src2_value.value) - .ReplaceStr(U"", src3_value.value); - - return true; -} - -KYTY_RECOMPILER_FUNC(Recompile_Exp_Param2Vsrc0Vsrc1Vsrc2Vsrc3) -{ - const auto& inst = code.GetInstructions().At(index); - - EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.src[0])); - EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.src[1])); - EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.src[2])); - EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.src[3])); - - auto src0_value = operand_variable_to_str(inst.src[0]); - auto src1_value = operand_variable_to_str(inst.src[1]); - auto src2_value = operand_variable_to_str(inst.src[2]); - auto src3_value = operand_variable_to_str(inst.src[3]); - - // TODO() check VSKIP - // TODO() check EXEC - - static const char32_t* text = UR"( - %t0_ = OpLoad %float % - %t1_ = OpLoad %float % - %t2_ = OpLoad %float % - %t3_ = OpLoad %float % - %t4_ = OpCompositeConstruct %v4float %t0_ %t1_ %t2_ %t3_ - OpStore %param2 %t4_ -)"; - - *dst_source += String(text) - .ReplaceStr(U"", String::FromPrintf("%u", index)) - .ReplaceStr(U"", src0_value.value) - .ReplaceStr(U"", src1_value.value) - .ReplaceStr(U"", src2_value.value) - .ReplaceStr(U"", src3_value.value); - - return true; -} - -KYTY_RECOMPILER_FUNC(Recompile_Exp_Param3Vsrc0Vsrc1Vsrc2Vsrc3) -{ - const auto& inst = code.GetInstructions().At(index); - - EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.src[0])); - EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.src[1])); - EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.src[2])); - EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.src[3])); - - auto src0_value = operand_variable_to_str(inst.src[0]); - auto src1_value = operand_variable_to_str(inst.src[1]); - auto src2_value = operand_variable_to_str(inst.src[2]); - auto src3_value = operand_variable_to_str(inst.src[3]); - - // TODO() check VSKIP - // TODO() check EXEC - - static const char32_t* text = UR"( - %t0_ = OpLoad %float % - %t1_ = OpLoad %float % - %t2_ = OpLoad %float % - %t3_ = OpLoad %float % - %t4_ = OpCompositeConstruct %v4float %t0_ %t1_ %t2_ %t3_ - OpStore %param3 %t4_ -)"; - - *dst_source += String(text) - .ReplaceStr(U"", String::FromPrintf("%u", index)) - .ReplaceStr(U"", src0_value.value) - .ReplaceStr(U"", src1_value.value) - .ReplaceStr(U"", src2_value.value) - .ReplaceStr(U"", src3_value.value); + .ReplaceStr(U"", src3_value.value) + .ReplaceStr(U"", param[0]); return true; } @@ -1843,7 +1954,8 @@ KYTY_RECOMPILER_FUNC(Recompile_ImageSample_Vdata4Vaddr3StSsDmaskF) return false; } -KYTY_RECOMPILER_FUNC(Recompile_SAndn2B64_Sdst2Ssrc02Ssrc12) +/* XXX: Andn2, Or, Nor */ +KYTY_RECOMPILER_FUNC(Recompile_S_XXX_B64_Sdst2Ssrc02Ssrc12) { const auto& inst = code.GetInstructions().At(index); @@ -1856,8 +1968,6 @@ KYTY_RECOMPILER_FUNC(Recompile_SAndn2B64_Sdst2Ssrc02Ssrc12) EXIT_NOT_IMPLEMENTED(dst_value0.type != SpirvType::Uint); - // EXIT_NOT_IMPLEMENTED(operand_is_exec(inst.dst)); - String load0; String load1; String load2; @@ -1885,25 +1995,122 @@ KYTY_RECOMPILER_FUNC(Recompile_SAndn2B64_Sdst2Ssrc02Ssrc12) - %t192_ = OpNot %uint %t2_ - %t193_ = OpBitwiseAnd %uint %t0_ %t192_ - OpStore % %t193_ - %t196_ = OpNot %uint %t3_ - %t197_ = OpBitwiseAnd %uint %t1_ %t196_ - OpStore % %t197_ + + + + + OpStore % %tb_ + OpStore % %td_ + )"; - // TODO() set SCC - *dst_source += String(text) - .ReplaceStr(U"", dst_value0.value) - .ReplaceStr(U"", dst_value1.value) .ReplaceStr(U"", load0) .ReplaceStr(U"", load1) .ReplaceStr(U"", load2) .ReplaceStr(U"", load3) + .ReplaceStr(U"", param[0]) + .ReplaceStr(U"", param[1]) + .ReplaceStr(U"", (param[2] == nullptr ? U"" : param[2])) + .ReplaceStr(U"", (param[3] == nullptr ? U"" : param[3])) .ReplaceStr(U"", (operand_is_exec(inst.dst) ? EXECZ : U"")) + .ReplaceStr(U"", get_scc_check(scc_check, 2)) + .ReplaceStr(U"", dst_value0.value) + .ReplaceStr(U"", dst_value1.value) + .ReplaceStr(U"", index_str); + + return true; +} + +/* XXX: And, Lshl, Lshr, CSelect */ +KYTY_RECOMPILER_FUNC(Recompile_S_XXX_B32_SVdstSVsrc0SVsrc1) +{ + const auto& inst = code.GetInstructions().At(index); + + String load0; + String load1; + + String index_str = String::FromPrintf("%u", index); + + EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.dst)); + + auto dst_value = operand_variable_to_str(inst.dst); + + EXIT_NOT_IMPLEMENTED(dst_value.type != SpirvType::Uint); + EXIT_NOT_IMPLEMENTED(operand_is_exec(inst.dst)); + + if (!operand_load_uint(spirv, inst.src[0], U"t0_", index_str, &load0)) + { + return false; + } + if (!operand_load_uint(spirv, inst.src[1], U"t1_", index_str, &load1)) + { + return false; + } + + static const char32_t* text = UR"( + + + + + + OpStore % %t_ + +)"; + *dst_source += String(text) + .ReplaceStr(U"", load0) + .ReplaceStr(U"", load1) + .ReplaceStr(U"", param[0]) + .ReplaceStr(U"", (param[1] == nullptr ? U"" : param[1])) + .ReplaceStr(U"", (param[2] == nullptr ? U"" : param[2])) + .ReplaceStr(U"", get_scc_check(scc_check, 1)) + .ReplaceStr(U"", dst_value.value) + .ReplaceStr(U"", index_str); + + return true; +} + +/* XXX: Add, Mul */ +KYTY_RECOMPILER_FUNC(Recompile_S_XXX_I32_SVdstSVsrc0SVsrc1) +{ + const auto& inst = code.GetInstructions().At(index); + + String load0; + String load1; + + String index_str = String::FromPrintf("%u", index); + + EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.dst)); + + auto dst_value = operand_variable_to_str(inst.dst); + + EXIT_NOT_IMPLEMENTED(dst_value.type != SpirvType::Uint); + EXIT_NOT_IMPLEMENTED(operand_is_exec(inst.dst)); + + if (!operand_load_int(spirv, inst.src[0], U"t0_", index_str, &load0)) + { + return false; + } + if (!operand_load_int(spirv, inst.src[1], U"t1_", index_str, &load1)) + { + return false; + } + + static const char32_t* text = UR"( + + + + %tu_ = OpBitcast %uint %t_ + OpStore % %tu_ + +)"; + *dst_source += String(text) + .ReplaceStr(U"", load0) + .ReplaceStr(U"", load1) + .ReplaceStr(U"", param[0]) + .ReplaceStr(U"", get_scc_check(scc_check, 1)) + .ReplaceStr(U"", dst_value.value) .ReplaceStr(U"", index_str); return true; @@ -1948,16 +2155,51 @@ KYTY_RECOMPILER_FUNC(Recompile_SAndSaveexecB64_Sdst2Ssrc02) %t197_ = OpBitwiseAnd %uint %t1_ %t191_ OpStore %exec_hi %t197_ + )"; - // TODO() set SCC - *dst_source += String(text) - .ReplaceStr(U"", dst_value0.value) - .ReplaceStr(U"", dst_value1.value) .ReplaceStr(U"", load0) .ReplaceStr(U"", load1) .ReplaceStr(U"", EXECZ) + .ReplaceStr(U"", get_scc_check(scc_check, 2)) + .ReplaceStr(U"", dst_value0.value) + .ReplaceStr(U"", dst_value1.value) + .ReplaceStr(U"", index_str); + + return true; +} + +/* XXX: Eq */ +KYTY_RECOMPILER_FUNC(Recompile_SCmp_XXX_U32_Ssrc0Ssrc1) +{ + const auto& inst = code.GetInstructions().At(index); + + String load0; + String load1; + + String index_str = String::FromPrintf("%u", index); + + if (!operand_load_uint(spirv, inst.src[0], U"t0_", index_str, &load0)) + { + return false; + } + if (!operand_load_uint(spirv, inst.src[1], U"t1_", index_str, &load1)) + { + return false; + } + + static const char32_t* text = UR"( + + + %t2_ = %bool %t0_ %t1_ + %t3_ = OpSelect %uint %t2_ %uint_1 %uint_0 + OpStore %scc %t3_ +)"; + *dst_source += String(text) + .ReplaceStr(U"", load0) + .ReplaceStr(U"", load1) + .ReplaceStr(U"", param[0]) .ReplaceStr(U"", index_str); return true; @@ -1978,6 +2220,7 @@ KYTY_RECOMPILER_FUNC(Recompile_SBufferLoadDword_SdstSvSoffset) EXIT_NOT_IMPLEMENTED(dst_value.type != SpirvType::Uint); EXIT_NOT_IMPLEMENTED(src0_value0.type != SpirvType::Uint); + EXIT_NOT_IMPLEMENTED(operand_is_exec(inst.dst)); static const char32_t* text = UR"( %t100_ = OpLoad %uint % @@ -1999,7 +2242,7 @@ KYTY_RECOMPILER_FUNC(Recompile_SBufferLoadDword_SdstSvSoffset) return false; } -KYTY_RECOMPILER_FUNC(Recompile_SBufferLoadDwordx4_Sdst4SvSoffset) +KYTY_RECOMPILER_FUNC(Recompile_SBufferLoadDwordx2_Sdst2SvSoffset) { const auto& inst = code.GetInstructions().At(index); const auto* bind_info = spirv->GetBindInfo(); @@ -2010,13 +2253,12 @@ KYTY_RECOMPILER_FUNC(Recompile_SBufferLoadDwordx4_Sdst4SvSoffset) auto dst_value0 = operand_variable_to_str(inst.dst, 0); auto dst_value1 = operand_variable_to_str(inst.dst, 1); - auto dst_value2 = operand_variable_to_str(inst.dst, 2); - auto dst_value3 = operand_variable_to_str(inst.dst, 3); auto src0_value0 = operand_variable_to_str(inst.src[0], 0); String offset = spirv->GetConstant(inst.src[1]); EXIT_NOT_IMPLEMENTED(dst_value0.type != SpirvType::Uint); EXIT_NOT_IMPLEMENTED(src0_value0.type != SpirvType::Uint); + EXIT_NOT_IMPLEMENTED(operand_is_exec(inst.dst)); EXIT_NOT_IMPLEMENTED(operand_is_exec(inst.dst)); @@ -2026,16 +2268,70 @@ KYTY_RECOMPILER_FUNC(Recompile_SBufferLoadDwordx4_Sdst4SvSoffset) OpStore %temp_int_2 %t101_ %t102_ = OpBitcast %int % OpStore %temp_int_1 %t102_ - %t110_ = OpFunctionCall %void %sbuffer_load_dword_4 % % % % %temp_int_1 %temp_int_2 + %t110_ = OpFunctionCall %void %sbuffer_load_dword_2 % % %temp_int_1 %temp_int_2 )"; *dst_source += String(text) .ReplaceStr(U"", String::FromPrintf("%u", index)) .ReplaceStr(U"", offset) .ReplaceStr(U"", src0_value0.value) .ReplaceStr(U"", dst_value0.value) + .ReplaceStr(U"", dst_value1.value); + + return true; + } + + return false; +} + +KYTY_RECOMPILER_FUNC(Recompile_SBufferLoadDwordx4_Sdst4SvSoffset) +{ + const auto& inst = code.GetInstructions().At(index); + const auto* bind_info = spirv->GetBindInfo(); + + if (bind_info != nullptr && bind_info->storage_buffers.buffers_num > 0) + { + // EXIT_NOT_IMPLEMENTED(!operand_is_constant(inst.src[1])); + + auto dst_value0 = operand_variable_to_str(inst.dst, 0); + auto dst_value1 = operand_variable_to_str(inst.dst, 1); + auto dst_value2 = operand_variable_to_str(inst.dst, 2); + auto dst_value3 = operand_variable_to_str(inst.dst, 3); + auto src0_value0 = operand_variable_to_str(inst.src[0], 0); + // String offset = spirv->GetConstant(inst.src[1]); + + EXIT_NOT_IMPLEMENTED(dst_value0.type != SpirvType::Uint); + EXIT_NOT_IMPLEMENTED(src0_value0.type != SpirvType::Uint); + EXIT_NOT_IMPLEMENTED(operand_is_exec(inst.dst)); + + EXIT_NOT_IMPLEMENTED(operand_is_exec(inst.dst)); + + String index_str = String::FromPrintf("%u", index); + + String load1; + + if (!operand_load_uint(spirv, inst.src[1], U"t1_", index_str, &load1)) + { + return false; + } + + static const char32_t* text = UR"( + + %t100_ = OpLoad %uint % + %t101_ = OpBitcast %int %t100_ + OpStore %temp_int_2 %t101_ + %t102_ = OpBitcast %int %t1_ + OpStore %temp_int_1 %t102_ + %t110_ = OpFunctionCall %void %sbuffer_load_dword_4 % % % % %temp_int_1 %temp_int_2 +)"; + *dst_source += String(text) + //.ReplaceStr(U"", offset) + .ReplaceStr(U"", load1) + .ReplaceStr(U"", src0_value0.value) + .ReplaceStr(U"", dst_value0.value) .ReplaceStr(U"", dst_value1.value) .ReplaceStr(U"", dst_value2.value) - .ReplaceStr(U"", dst_value3.value); + .ReplaceStr(U"", dst_value3.value) + .ReplaceStr(U"", index_str); return true; } @@ -2145,7 +2441,7 @@ KYTY_RECOMPILER_FUNC(Recompile_SCbranchExecz_Label) EXIT_NOT_IMPLEMENTED(!operand_is_constant(inst.src[0])); - String label = String::FromPrintf("label_%04" PRIx32, inst.pc + 4 + inst.src[0].constant.i); + String label = String::FromPrintf("label_%04" PRIx32 "_%04" PRIx32, inst.pc + 4 + inst.src[0].constant.i, inst.pc); static const char32_t* text = UR"( %execz_u_ = OpLoad %uint %execz @@ -2160,6 +2456,56 @@ KYTY_RECOMPILER_FUNC(Recompile_SCbranchExecz_Label) return true; } +KYTY_RECOMPILER_FUNC(Recompile_SCbranchScc0_Label) +{ + const auto& inst = code.GetInstructions().At(index); + + EXIT_NOT_IMPLEMENTED(!operand_is_constant(inst.src[0])); + + String label = String::FromPrintf("label_%04" PRIx32 "_%04" PRIx32, inst.pc + 4 + inst.src[0].constant.i, inst.pc); + + static const char32_t* text = UR"( + %scc_u_ = OpLoad %uint %scc + %scc_b_ = OpIEqual %bool %scc_u_ %uint_0 + OpSelectionMerge %