From 037431589f1bece152b1228afa4d50e5425b1aa3 Mon Sep 17 00:00:00 2001 From: InoriRus Date: Mon, 20 Dec 2021 18:00:10 +1000 Subject: [PATCH] Improve shader recompiler --- source/CMakeLists.txt | 2 +- source/emulator/include/Emulator/Config.h | 2 + .../include/Emulator/Graphics/Shader.h | 67 +- source/emulator/src/Config.cpp | 7 + .../emulator/src/Graphics/GraphicsRender.cpp | 4 +- source/emulator/src/Graphics/Shader.cpp | 174 +++++- source/emulator/src/Graphics/ShaderSpirv.cpp | 578 ++++++++++++++++-- .../emulator/src/Graphics/VideoOutBuffer.cpp | 2 +- source/emulator/src/Graphics/Window.cpp | 46 +- source/emulator/src/Kyty.cpp | 78 +++ 10 files changed, 881 insertions(+), 79 deletions(-) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 9648237..a54cb10 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -79,7 +79,7 @@ if (KYTY_LINKER STREQUAL LD) set(KYTY_LD_OPTIONS "-Wl,--image-base=0x100000000000") endif() -project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.0.3) +project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.0.4) include(src_script.cmake) diff --git a/source/emulator/include/Emulator/Config.h b/source/emulator/include/Emulator/Config.h index cd09fad..f0bfef6 100644 --- a/source/emulator/include/Emulator/Config.h +++ b/source/emulator/include/Emulator/Config.h @@ -60,6 +60,8 @@ String GetPrintfOutputFile(); ProfilerDirection GetProfilerDirection(); String GetProfilerOutputFile(); +bool SpirvDebugPrintfEnabled(); + } // namespace Kyty::Config #endif diff --git a/source/emulator/include/Emulator/Graphics/Shader.h b/source/emulator/include/Emulator/Graphics/Shader.h index e2c5db9..1476a3c 100644 --- a/source/emulator/include/Emulator/Graphics/Shader.h +++ b/source/emulator/include/Emulator/Graphics/Shader.h @@ -41,7 +41,9 @@ enum class ShaderInstructionType DsConsume, Exp, ImageSample, + SAddcU32, SAddI32, + SAddU32, SAndB32, SAndn2B64, SAndSaveexecB64, @@ -53,11 +55,18 @@ enum class ShaderInstructionType SBufferLoadDwordx8, SCbranchExecz, SCbranchScc0, + SCmpEqI32, SCmpEqU32, - SCmpGeU32, SCmpGeI32, + SCmpGeU32, + SCmpGtI32, + SCmpGtU32, + SCmpLeI32, SCmpLeU32, + SCmpLgI32, SCmpLgU32, + SCmpLtI32, + SCmpLtU32, SCselectB32, SCselectB64, SEndpgm, @@ -77,25 +86,52 @@ enum class ShaderInstructionType TBufferLoadFormatXyzw, VAddI32, VAndB32, + VOrB32, + VXorB32, VAshrI32, VAshrrevI32, VBcntU32B32, VBfeU32, + VBfrevB32, + VCvtF32I32, + VBfmB32, VCmpEqF32, VCmpEqI32, VCmpEqU32, + VCmpFF32, + VCmpFI32, + VCmpFU32, VCmpGeF32, + VCmpGeI32, VCmpGeU32, + VCmpGtF32, VCmpGtI32, + VCmpGtU32, VCmpLeF32, + VCmpLeI32, VCmpLeU32, + VCmpLgF32, + VCmpLtF32, + VCmpLtI32, + VCmpLtU32, VCmpNeI32, VCmpNeqF32, VCmpNeU32, + VCmpNgeF32, + VCmpNgtF32, + VCmpNleF32, + VCmpNlgF32, + VCmpNltF32, + VCmpOF32, + VCmpTI32, + VCmpTruF32, + VCmpTU32, + VCmpUF32, VCmpxEqU32, VCmpxGtU32, VCmpxNeU32, VCndmaskB32, + VCvtF32F16, VCvtF32U32, VCvtF32Ubyte0, VCvtF32Ubyte1, @@ -127,6 +163,13 @@ enum class ShaderInstructionType VNotB32, VRcpF32, VRsqF32, + VCeilF32, + VFractF32, + VRndneF32, + VTruncF32, + VExpF32, + VCosF32, + VFloorF32, VSadU32, VSqrtF32, VSubF32, @@ -297,6 +340,20 @@ struct ShaderLabel uint32_t src; }; +struct ShaderDebugPrintf +{ + enum class Type + { + Uint, + Int, + Float + }; + uint32_t pc = 0; + String format; + Vector types; + Vector args; +}; + class ShaderCode { public: @@ -308,6 +365,8 @@ public: Vector& GetInstructions() { return m_instructions; } [[nodiscard]] const Vector& GetLabels() const { return m_labels; } Vector& GetLabels() { return m_labels; } + [[nodiscard]] const Vector& GetDebugPrintfs() const { return m_debug_printfs; } + Vector& GetDebugPrintfs() { return m_debug_printfs; } [[nodiscard]] String DbgDump() const; @@ -327,6 +386,7 @@ private: Vector m_instructions; Vector m_labels; ShaderType m_type = ShaderType::Unknown; + Vector m_debug_printfs; }; struct ShaderId @@ -581,7 +641,9 @@ struct ShaderVertexInputInfo struct ShaderComputeInputInfo { - uint32_t threads_num[3] = {}; + uint32_t threads_num[3] = {0, 0, 0}; + bool group_id[3] = {false, false, false}; + int thread_ids_num = 0; int workgroup_register = 0; ShaderResources bind; }; @@ -610,6 +672,7 @@ Vector ShaderRecompilePS(const PixelShaderInfo* regs, const ShaderPixe Vector ShaderRecompileCS(const ComputeShaderInfo* regs, const ShaderComputeInputInfo* input_info); bool ShaderIsDisabled(uint64_t addr); void ShaderDisable(uint64_t id); +void ShaderInjectDebugPrintf(uint64_t id, const ShaderDebugPrintf& cmd); } // namespace Kyty::Libs::Graphics diff --git a/source/emulator/src/Config.cpp b/source/emulator/src/Config.cpp index 1b0f2d4..8e32508 100644 --- a/source/emulator/src/Config.cpp +++ b/source/emulator/src/Config.cpp @@ -24,6 +24,7 @@ struct Config String printf_output_file = U"_kyty.txt"; ProfilerDirection profiler_direction = ProfilerDirection::None; String profiler_output_file = U"_profile.prof"; + bool spirv_debug_printf_enabled = false; }; static Config* g_config = nullptr; @@ -93,6 +94,7 @@ void Load(const Scripts::ScriptVar& cfg) LoadStr(g_config->printf_output_file, cfg, U"PrintfOutputFile"); LoadEnum(g_config->profiler_direction, cfg, U"ProfilerDirection"); LoadStr(g_config->profiler_output_file, cfg, U"ProfilerOutputFile"); + LoadBool(g_config->spirv_debug_printf_enabled, cfg, U"SpirvDebugPrintfEnabled"); } uint32_t GetScreenWidth() @@ -165,6 +167,11 @@ String GetProfilerOutputFile() return g_config->profiler_output_file; } +bool SpirvDebugPrintfEnabled() +{ + return g_config->spirv_debug_printf_enabled; +} + } // namespace Kyty::Config #endif // KYTY_EMU_ENABLED diff --git a/source/emulator/src/Graphics/GraphicsRender.cpp b/source/emulator/src/Graphics/GraphicsRender.cpp index 0a6c077..3d87bbc 100644 --- a/source/emulator/src/Graphics/GraphicsRender.cpp +++ b/source/emulator/src/Graphics/GraphicsRender.cpp @@ -3221,8 +3221,8 @@ void GraphicsRenderDispatchDirect(CommandBuffer* buffer, HardwareContext* ctx, u EXIT_NOT_IMPLEMENTED(mode != 0); // EXIT_NOT_IMPLEMENTED(thread_group_x != 2); - EXIT_NOT_IMPLEMENTED(thread_group_y != 1); - EXIT_NOT_IMPLEMENTED(thread_group_z != 1); + // EXIT_NOT_IMPLEMENTED(thread_group_y != 1); + // EXIT_NOT_IMPLEMENTED(thread_group_z != 1); const auto& cs_regs = ctx->GetCs(); diff --git a/source/emulator/src/Graphics/Shader.cpp b/source/emulator/src/Graphics/Shader.cpp index 3769a43..4366ae0 100644 --- a/source/emulator/src/Graphics/Shader.cpp +++ b/source/emulator/src/Graphics/Shader.cpp @@ -73,7 +73,14 @@ struct ShaderUsageInfo int slots_num = 0; }; -static Vector* g_disabled_shaders = nullptr; +struct ShaderDebugPrintfCmds +{ + uint64_t id = 0; + Vector cmds; +}; + +static Vector* g_disabled_shaders = nullptr; +static Vector* g_debug_printfs = nullptr; static String operand_to_str(ShaderOperand op) { @@ -144,6 +151,12 @@ static String operand_array_to_str(ShaderOperand op, int n) break; case ShaderOperandType::Sgpr: ret = String::FromPrintf("s[%d:%d]", op.register_id, op.register_id + n - 1); break; case ShaderOperandType::Vgpr: ret = String::FromPrintf("v[%d:%d]", op.register_id, op.register_id + n - 1); break; + case ShaderOperandType::LiteralConstant: + if (n == 2) + { + ret = String::FromPrintf("%f (%u)", op.constant.f, op.constant.u); + } + break; case ShaderOperandType::IntegerInlineConstant: if (n == 2) { @@ -438,10 +451,17 @@ KYTY_SHADER_PARSER(shader_parse_sopc) switch (opcode) { + case 0x00: inst.type = ShaderInstructionType::SCmpEqI32; break; + case 0x01: inst.type = ShaderInstructionType::SCmpLgI32; break; + case 0x02: inst.type = ShaderInstructionType::SCmpGtI32; break; case 0x03: inst.type = ShaderInstructionType::SCmpGeI32; break; + case 0x04: inst.type = ShaderInstructionType::SCmpLtI32; break; + case 0x05: inst.type = ShaderInstructionType::SCmpLeI32; break; case 0x06: inst.type = ShaderInstructionType::SCmpEqU32; break; case 0x07: inst.type = ShaderInstructionType::SCmpLgU32; break; + case 0x08: inst.type = ShaderInstructionType::SCmpGtU32; break; case 0x09: inst.type = ShaderInstructionType::SCmpGeU32; break; + case 0x0a: inst.type = ShaderInstructionType::SCmpLtU32; break; case 0x0b: inst.type = ShaderInstructionType::SCmpLeU32; break; default: printf("%s", dst->DbgDump().C_Str()); EXIT("unknown sopc opcode: 0x%02" PRIx32 " at addr 0x%08" PRIx32 "\n", opcode, pc); @@ -627,7 +647,9 @@ KYTY_SHADER_PARSER(shader_parse_sop2) switch (opcode) { + case 0x00: inst.type = ShaderInstructionType::SAddU32; break; case 0x02: inst.type = ShaderInstructionType::SAddI32; break; + case 0x04: inst.type = ShaderInstructionType::SAddcU32; break; case 0x0a: inst.type = ShaderInstructionType::SCselectB32; break; case 0x0b: inst.type = ShaderInstructionType::SCselectB64; @@ -700,16 +722,38 @@ KYTY_SHADER_PARSER(shader_parse_vopc) switch (opcode) { + case 0x00: inst.type = ShaderInstructionType::VCmpFF32; break; + case 0x01: inst.type = ShaderInstructionType::VCmpLtF32; break; case 0x02: inst.type = ShaderInstructionType::VCmpEqF32; break; case 0x03: inst.type = ShaderInstructionType::VCmpLeF32; break; + case 0x04: inst.type = ShaderInstructionType::VCmpGtF32; break; + case 0x05: inst.type = ShaderInstructionType::VCmpLgF32; break; + case 0x06: inst.type = ShaderInstructionType::VCmpGeF32; break; + case 0x07: inst.type = ShaderInstructionType::VCmpOF32; break; + case 0x08: inst.type = ShaderInstructionType::VCmpUF32; break; + case 0x09: inst.type = ShaderInstructionType::VCmpNgeF32; break; + case 0x0a: inst.type = ShaderInstructionType::VCmpNlgF32; break; + case 0x0b: inst.type = ShaderInstructionType::VCmpNgtF32; break; + case 0x0c: inst.type = ShaderInstructionType::VCmpNleF32; break; case 0x0d: inst.type = ShaderInstructionType::VCmpNeqF32; break; + case 0x0e: inst.type = ShaderInstructionType::VCmpNltF32; break; + case 0x0f: inst.type = ShaderInstructionType::VCmpTruF32; break; + case 0x80: inst.type = ShaderInstructionType::VCmpFI32; break; + case 0x81: inst.type = ShaderInstructionType::VCmpLtI32; break; case 0x82: inst.type = ShaderInstructionType::VCmpEqI32; break; + case 0x83: inst.type = ShaderInstructionType::VCmpLeI32; break; case 0x84: inst.type = ShaderInstructionType::VCmpGtI32; break; case 0x85: inst.type = ShaderInstructionType::VCmpNeI32; break; + case 0x86: inst.type = ShaderInstructionType::VCmpGeI32; break; + case 0x87: inst.type = ShaderInstructionType::VCmpTI32; break; + case 0xc0: inst.type = ShaderInstructionType::VCmpFU32; break; + case 0xc1: inst.type = ShaderInstructionType::VCmpLtU32; break; case 0xc2: inst.type = ShaderInstructionType::VCmpEqU32; break; case 0xc3: inst.type = ShaderInstructionType::VCmpLeU32; break; + case 0xc4: inst.type = ShaderInstructionType::VCmpGtU32; break; case 0xc5: inst.type = ShaderInstructionType::VCmpNeU32; break; case 0xc6: inst.type = ShaderInstructionType::VCmpGeU32; break; + case 0xc7: inst.type = ShaderInstructionType::VCmpTU32; break; case 0xd2: inst.type = ShaderInstructionType::VCmpxEqU32; break; case 0xd4: inst.type = ShaderInstructionType::VCmpxGtU32; break; case 0xd5: inst.type = ShaderInstructionType::VCmpxNeU32; break; @@ -750,16 +794,26 @@ KYTY_SHADER_PARSER(shader_parse_vop1) switch (opcode) { case 0x01: inst.type = ShaderInstructionType::VMovB32; break; + case 0x05: inst.type = ShaderInstructionType::VCvtF32I32; break; case 0x06: inst.type = ShaderInstructionType::VCvtF32U32; break; case 0x07: inst.type = ShaderInstructionType::VCvtU32F32; break; + case 0x0b: inst.type = ShaderInstructionType::VCvtF32F16; 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 0x20: inst.type = ShaderInstructionType::VFractF32; break; + case 0x21: inst.type = ShaderInstructionType::VTruncF32; break; + case 0x22: inst.type = ShaderInstructionType::VCeilF32; break; + case 0x23: inst.type = ShaderInstructionType::VRndneF32; break; + case 0x24: inst.type = ShaderInstructionType::VFloorF32; break; + case 0x25: inst.type = ShaderInstructionType::VExpF32; break; case 0x2a: inst.type = ShaderInstructionType::VRcpF32; break; case 0x2e: inst.type = ShaderInstructionType::VRsqF32; break; case 0x33: inst.type = ShaderInstructionType::VSqrtF32; break; + case 0x36: inst.type = ShaderInstructionType::VCosF32; break; case 0x37: inst.type = ShaderInstructionType::VNotB32; break; + case 0x38: inst.type = ShaderInstructionType::VBfrevB32; break; default: printf("%s", dst->DbgDump().C_Str()); EXIT("unknown vop1 opcode: 0x%02" PRIx32 " at addr 0x%08" PRIx32 "\n", opcode, pc); } @@ -818,6 +872,9 @@ KYTY_SHADER_PARSER(shader_parse_vop2) case 0x19: inst.type = ShaderInstructionType::VLshlB32; break; case 0x1a: inst.type = ShaderInstructionType::VLshlrevB32; break; case 0x1b: inst.type = ShaderInstructionType::VAndB32; break; + case 0x1c: inst.type = ShaderInstructionType::VOrB32; break; + case 0x1d: inst.type = ShaderInstructionType::VXorB32; break; + case 0x1e: inst.type = ShaderInstructionType::VBfmB32; break; case 0x1f: inst.type = ShaderInstructionType::VMacF32; break; case 0x20: inst.type = ShaderInstructionType::VMadmkF32; @@ -958,15 +1015,38 @@ KYTY_SHADER_PARSER(shader_parse_vop3) switch (opcode) { + case 0x00: inst.type = ShaderInstructionType::VCmpFF32; break; + case 0x01: inst.type = ShaderInstructionType::VCmpLtF32; break; case 0x02: inst.type = ShaderInstructionType::VCmpEqF32; break; case 0x03: inst.type = ShaderInstructionType::VCmpLeF32; break; + case 0x04: inst.type = ShaderInstructionType::VCmpGtF32; break; + case 0x05: inst.type = ShaderInstructionType::VCmpLgF32; break; case 0x06: inst.type = ShaderInstructionType::VCmpGeF32; break; + case 0x07: inst.type = ShaderInstructionType::VCmpOF32; break; + case 0x08: inst.type = ShaderInstructionType::VCmpUF32; break; + case 0x09: inst.type = ShaderInstructionType::VCmpNgeF32; break; + case 0x0a: inst.type = ShaderInstructionType::VCmpNlgF32; break; + case 0x0b: inst.type = ShaderInstructionType::VCmpNgtF32; break; + case 0x0c: inst.type = ShaderInstructionType::VCmpNleF32; break; case 0x0d: inst.type = ShaderInstructionType::VCmpNeqF32; break; + case 0x0e: inst.type = ShaderInstructionType::VCmpNltF32; break; + case 0x0f: inst.type = ShaderInstructionType::VCmpTruF32; break; + case 0x80: inst.type = ShaderInstructionType::VCmpFI32; break; + case 0x81: inst.type = ShaderInstructionType::VCmpLtI32; break; + case 0x82: inst.type = ShaderInstructionType::VCmpEqI32; break; + case 0x83: inst.type = ShaderInstructionType::VCmpLeI32; break; case 0x84: inst.type = ShaderInstructionType::VCmpGtI32; break; + case 0x85: inst.type = ShaderInstructionType::VCmpNeI32; break; + case 0x86: inst.type = ShaderInstructionType::VCmpGeI32; break; + case 0x87: inst.type = ShaderInstructionType::VCmpTI32; break; + case 0xc0: inst.type = ShaderInstructionType::VCmpFU32; break; + case 0xc1: inst.type = ShaderInstructionType::VCmpLtU32; break; case 0xc2: inst.type = ShaderInstructionType::VCmpEqU32; break; case 0xc3: inst.type = ShaderInstructionType::VCmpLeU32; break; + case 0xc4: inst.type = ShaderInstructionType::VCmpGtU32; break; case 0xc5: inst.type = ShaderInstructionType::VCmpNeU32; break; case 0xc6: inst.type = ShaderInstructionType::VCmpGeU32; break; + case 0xc7: inst.type = ShaderInstructionType::VCmpTU32; break; case 0xd4: inst.type = ShaderInstructionType::VCmpxGtU32; break; case 0x100: inst.type = ShaderInstructionType::VCndmaskB32; @@ -987,6 +1067,9 @@ KYTY_SHADER_PARSER(shader_parse_vop3) case 0x119: inst.type = ShaderInstructionType::VLshlB32; break; case 0x11a: inst.type = ShaderInstructionType::VLshlrevB32; break; case 0x11b: inst.type = ShaderInstructionType::VAndB32; break; + case 0x11c: inst.type = ShaderInstructionType::VOrB32; break; + case 0x11d: inst.type = ShaderInstructionType::VXorB32; break; + case 0x11e: inst.type = ShaderInstructionType::VBfmB32; break; case 0x11f: inst.type = ShaderInstructionType::VMacF32; break; case 0x122: inst.type = ShaderInstructionType::VBcntU32B32; break; case 0x123: inst.type = ShaderInstructionType::VMbcntLoU32B32; break; @@ -997,6 +1080,18 @@ KYTY_SHADER_PARSER(shader_parse_vop3) inst.dst2 = operand_parse(sdst); inst.dst2.size = 2; break; + case 0x126: + inst.type = ShaderInstructionType::VSubI32; + inst.format = ShaderInstructionFormat::VdstSdst2Vsrc0Vsrc1; + inst.dst2 = operand_parse(sdst); + inst.dst2.size = 2; + break; + case 0x127: + inst.type = ShaderInstructionType::VSubrevI32; + inst.format = ShaderInstructionFormat::VdstSdst2Vsrc0Vsrc1; + inst.dst2 = operand_parse(sdst); + inst.dst2.size = 2; + break; case 0x12f: inst.type = ShaderInstructionType::VCvtPkrtzF16F32; break; case 0x141: inst.type = ShaderInstructionType::VMadF32; break; case 0x143: inst.type = ShaderInstructionType::VMadU32U24; break; @@ -1707,18 +1802,18 @@ static void ps_check(const PsStageRegisters& ps) static void cs_check(const CsStageRegisters& cs) { // EXIT_NOT_IMPLEMENTED(cs.num_thread_x != 0x00000040); - EXIT_NOT_IMPLEMENTED(cs.num_thread_y != 0x00000001); - EXIT_NOT_IMPLEMENTED(cs.num_thread_z != 0x00000001); + // EXIT_NOT_IMPLEMENTED(cs.num_thread_y != 0x00000001); + // EXIT_NOT_IMPLEMENTED(cs.num_thread_z != 0x00000001); // EXIT_NOT_IMPLEMENTED(cs.vgprs != 0x00 && cs.vgprs != 0x01); // EXIT_NOT_IMPLEMENTED(cs.sgprs != 0x01 && cs.sgprs != 0x02); EXIT_NOT_IMPLEMENTED(cs.bulky != 0x00); EXIT_NOT_IMPLEMENTED(cs.scratch_en != 0x00); // EXIT_NOT_IMPLEMENTED(cs.user_sgpr != 0x0c); EXIT_NOT_IMPLEMENTED(cs.tgid_x_en != 0x01); - EXIT_NOT_IMPLEMENTED(cs.tgid_y_en != 0x00); - EXIT_NOT_IMPLEMENTED(cs.tgid_z_en != 0x00); + // EXIT_NOT_IMPLEMENTED(cs.tgid_y_en != 0x00); + // EXIT_NOT_IMPLEMENTED(cs.tgid_z_en != 0x00); EXIT_NOT_IMPLEMENTED(cs.tg_size_en != 0x00); - EXIT_NOT_IMPLEMENTED(cs.tidig_comp_cnt != 0x00); + EXIT_NOT_IMPLEMENTED(cs.tidig_comp_cnt > 2); EXIT_NOT_IMPLEMENTED(cs.lds_size != 0x00); // EXIT_NOT_IMPLEMENTED(cs.m_computePgmRsrc1 != 0x002c0040); @@ -2319,6 +2414,10 @@ void ShaderGetInputInfoCS(const ComputeShaderInfo* regs, ShaderComputeInputInfo* info->threads_num[0] = regs->cs_regs.num_thread_x; info->threads_num[1] = regs->cs_regs.num_thread_y; info->threads_num[2] = regs->cs_regs.num_thread_z; + info->group_id[0] = regs->cs_regs.tgid_x_en != 0; + info->group_id[1] = regs->cs_regs.tgid_y_en != 0; + info->group_id[2] = regs->cs_regs.tgid_z_en != 0; + info->thread_ids_num = regs->cs_regs.tidig_comp_cnt + 1; info->workgroup_register = regs->cs_regs.user_sgpr; @@ -2580,6 +2679,10 @@ void ShaderDbgDumpInputInfo(const ShaderComputeInputInfo* info) printf("ShaderDbgDumpInputInfo()\n"); printf("\t workgroup_register = %d\n", info->workgroup_register); + printf("\t thread_ids_num = %d\n", info->thread_ids_num); + printf("\t threads_num = {%u, %u, %u}\n", info->threads_num[0], info->threads_num[1], info->threads_num[2]); + printf("\t threadgroup_id = {%s, %s, %s}\n", info->group_id[0] ? "true" : "false", info->group_id[1] ? "true" : "false", + info->group_id[2] ? "true" : "false"); ShaderDbgDumpResources(info->bind); } @@ -2771,6 +2874,15 @@ Vector ShaderRecompileVS(const VertexShaderInfo* regs, const ShaderVer log.DumpOriginalShader(code); + if (g_debug_printfs != nullptr) + { + auto id = (static_cast(header->hash0) << 32u) | header->crc32; + if (auto index = g_debug_printfs->Find(id, [](auto cmd, auto id) { return cmd.id == id; }); g_debug_printfs->IndexValid(index)) + { + code.GetDebugPrintfs() = g_debug_printfs->At(index).cmds; + } + } + source = SpirvGenerateSource(code, input_info, nullptr, nullptr); } @@ -2827,6 +2939,15 @@ Vector ShaderRecompilePS(const PixelShaderInfo* regs, const ShaderPixe log.DumpOriginalShader(code); + if (g_debug_printfs != nullptr) + { + auto id = (static_cast(header->hash0) << 32u) | header->crc32; + if (auto index = g_debug_printfs->Find(id, [](auto cmd, auto id) { return cmd.id == id; }); g_debug_printfs->IndexValid(index)) + { + code.GetDebugPrintfs() = g_debug_printfs->At(index).cmds; + } + } + auto source = SpirvGenerateSource(code, nullptr, input_info, nullptr); log.DumpRecompiledShader(source); @@ -2854,7 +2975,7 @@ Vector ShaderRecompileCS(const ComputeShaderInfo* regs, const ShaderCo cs_print("ShaderRecompileCS()", regs->cs_regs); cs_check(regs->cs_regs); - EXIT_NOT_IMPLEMENTED(regs->cs_regs.user_sgpr != regs->cs_user_sgpr.count); + EXIT_NOT_IMPLEMENTED(regs->cs_regs.user_sgpr > regs->cs_user_sgpr.count); for (int i = 0; i < input_info->bind.storage_buffers.buffers_num; i++) { @@ -2877,6 +2998,15 @@ Vector ShaderRecompileCS(const ComputeShaderInfo* regs, const ShaderCo log.DumpOriginalShader(code); + if (g_debug_printfs != nullptr) + { + auto id = (static_cast(header->hash0) << 32u) | header->crc32; + if (auto index = g_debug_printfs->Find(id, [](auto cmd, auto id) { return cmd.id == id; }); g_debug_printfs->IndexValid(index)) + { + code.GetDebugPrintfs() = g_debug_printfs->At(index).cmds; + } + } + auto source = SpirvGenerateSource(code, nullptr, nullptr, input_info); log.DumpRecompiledShader(source); @@ -3110,6 +3240,13 @@ ShaderId ShaderGetIdCS(const ComputeShaderInfo* regs, const ShaderComputeInputIn ret.ids.Add(header->crc32); ret.ids.Add(input_info->workgroup_register); + ret.ids.Add(input_info->thread_ids_num); + + for (int i = 0; i < 3; i++) + { + ret.ids.Add(input_info->threads_num[i]); + ret.ids.Add(static_cast(input_info->group_id[i])); + } ShaderGetBindIds(&ret, input_info->bind); @@ -3146,6 +3283,29 @@ void ShaderDisable(uint64_t id) } } +void ShaderInjectDebugPrintf(uint64_t id, const ShaderDebugPrintf& cmd) +{ + if (g_debug_printfs == nullptr) + { + g_debug_printfs = new Vector; + } + + for (auto& c: *g_debug_printfs) + { + if (c.id == id) + { + c.cmds.Add(cmd); + return; + } + } + + ShaderDebugPrintfCmds c; + c.id = id; + c.cmds.Add(cmd); + + g_debug_printfs->Add(c); +} + } // namespace Kyty::Libs::Graphics #endif // KYTY_EMU_ENABLED diff --git a/source/emulator/src/Graphics/ShaderSpirv.cpp b/source/emulator/src/Graphics/ShaderSpirv.cpp index d6731ab..ec097c6 100644 --- a/source/emulator/src/Graphics/ShaderSpirv.cpp +++ b/source/emulator/src/Graphics/ShaderSpirv.cpp @@ -7,6 +7,7 @@ #include "Kyty/Core/String.h" #include "Kyty/Core/Vector.h" +#include "Emulator/Config.h" #include "Emulator/Graphics/Shader.h" #ifdef KYTY_EMU_ENABLED @@ -131,6 +132,91 @@ constexpr char32_t FUNC_ABS_DIFF[] = UR"( OpFunctionEnd )"; +constexpr char32_t FUNC_WQM[] = UR"( + ; uint w(uint u, uint s, uint m) + ; { + ; return ((u >> s) & 0xF) != 0 ? m : 0; + ; } + %wqm = OpFunction %uint None %function_u_u_u + %wqm_155 = OpFunctionParameter %uint + %wqm_156 = OpFunctionParameter %uint + %wqm_161 = OpFunctionParameter %uint + %wqm_50 = OpLabel + %wqm_157 = OpShiftRightLogical %uint %wqm_155 %wqm_156 + %wqm_159 = OpBitwiseAnd %uint %wqm_157 %uint_15 + %wqm_160 = OpINotEqual %bool %wqm_159 %uint_0 + %wqm_162 = OpSelect %uint %wqm_160 %wqm_161 %uint_0 + OpReturnValue %wqm_162 + OpFunctionEnd +)"; + +constexpr char32_t FUNC_ADDC[] = UR"( + ; uvec2 addc(uint a, uint b, uint c) + ; { + ; uint cc = 0; + ; uint sum = uaddCarry(a, b, cc) + c; + ; return uvec2(sum, (cc != 0 || (c !=0 && sum == 0)) ? 1u : 0u); + ; } + %addc = OpFunction %v2uint None %function_u2_u_u_u + %addc_47 = OpFunctionParameter %uint + %addc_48 = OpFunctionParameter %uint + %addc_49 = OpFunctionParameter %uint + %addc_51 = OpLabel + %addc_156 = OpIAddCarry %ResTypeU %addc_47 %addc_48 + %addc_157 = OpCompositeExtract %uint %addc_156 1 + %addc_158 = OpCompositeExtract %uint %addc_156 0 + %addc_160 = OpIAdd %uint %addc_158 %addc_49 + %addc_163 = OpINotEqual %bool %addc_157 %uint_0 + %addc_164 = OpLogicalNot %bool %addc_163 + OpSelectionMerge %addc_166 None + OpBranchConditional %addc_164 %addc_165 %addc_166 + %addc_165 = OpLabel + %addc_168 = OpINotEqual %bool %addc_49 %uint_0 + %addc_170 = OpIEqual %bool %addc_160 %uint_0 + %addc_171 = OpLogicalAnd %bool %addc_168 %addc_170 + OpBranch %addc_166 + %addc_166 = OpLabel + %addc_172 = OpPhi %bool %addc_163 %addc_51 %addc_171 %addc_165 + %addc_173 = OpSelect %uint %addc_172 %uint_1 %uint_0 + %addc_174 = OpCompositeConstruct %v2uint %addc_160 %addc_173 + OpReturnValue %addc_174 + OpFunctionEnd +)"; + +constexpr char32_t FUNC_ORDERED[] = UR"( + ; bool unordered(float f1, float f2) + ; { + ; return (isnan(f1) || isnan(f2)); + ; } + ; bool ordered(float f1, float f2) + ; { + ; return !unordered(f1, f2); + ; } + %unordered = OpFunction %bool None %function_b_f_f + %ord_49 = OpFunctionParameter %float + %ord_50 = OpFunctionParameter %float + %ord_52 = OpLabel + %ord_156 = OpIsNan %bool %ord_49 + %ord_157 = OpLogicalNot %bool %ord_156 + OpSelectionMerge %ord_159 None + OpBranchConditional %ord_157 %ord_158 %ord_159 + %ord_158 = OpLabel + %ord_161 = OpIsNan %bool %ord_50 + OpBranch %ord_159 + %ord_159 = OpLabel + %ord_162 = OpPhi %bool %ord_156 %ord_52 %ord_161 %ord_158 + OpReturnValue %ord_162 + OpFunctionEnd + %ordered = OpFunction %bool None %function_b_f_f + %ord_53 = OpFunctionParameter %float + %ord_54 = OpFunctionParameter %float + %ord_56 = OpLabel + %ord_169 = OpFunctionCall %bool %unordered %ord_53 %ord_54 + %ord_170 = OpLogicalNot %bool %ord_169 + OpReturnValue %ord_170 + OpFunctionEnd +)"; + constexpr char32_t FUNC_MUL_EXTENDED[] = UR"( ; uint mul_lo_uint(uint u1, uint u2) ; { @@ -870,7 +956,7 @@ constexpr char32_t EMBEDDED_SHADER_VS_0[] = UR"( ; ; void main() ; { - ; float x = gl_VertexIndex == 0 || gl_VertexIndex == 2 ? -1.0 : 1.0; + ; float x = gl_VertexIndex == 0 || gl_VertexIndex == 2 ? 1.0 : -1.0; ; float y = gl_VertexIndex == 2 || gl_VertexIndex == 3 ? -1.0 : 1.0; ; ; gl_Position = vec4(x,y, 0.0, 1.0); @@ -900,8 +986,8 @@ constexpr char32_t EMBEDDED_SHADER_VS_0[] = UR"( %gl_VertexIndex = OpVariable %_ptr_Input_int Input %int_0 = OpConstant %int 0 %int_2 = OpConstant %int 2 - %float_n1 = OpConstant %float -1 %float_1 = OpConstant %float 1 + %float_n1 = OpConstant %float -1 %int_3 = OpConstant %int 3 %v4float = OpTypeVector %float 4 %uint = OpTypeInt 32 0 @@ -928,7 +1014,7 @@ constexpr char32_t EMBEDDED_SHADER_VS_0[] = UR"( OpBranch %18 %18 = OpLabel %22 = OpPhi %bool %15 %5 %21 %17 - %25 = OpSelect %float %22 %float_n1 %float_1 + %25 = OpSelect %float %22 %float_1 %float_n1 OpStore %8 %25 %28 = OpIEqual %bool %13 %int_2 %29 = OpLogicalNot %bool %28 @@ -988,6 +1074,10 @@ constexpr char32_t SCC_OVERFLOW_1[] = UR"( OpStore %scc %so1_142_ )"; +constexpr char32_t SCC_CARRY_1[] = UR"( + OpStore %scc %carry_ +)"; + constexpr char32_t CLAMP[] = UR"( %c197_ = OpLoad %float % %c200_ = OpExtInst %float %GLSL_std_450 FClamp %c197_ %float_0_000000 %float_1_000000 @@ -1007,6 +1097,7 @@ enum class SccCheck None, NonZero, Overflow, + CarryOut, }; using inst_recompile_func_t = bool (*)(KYTY_RECOMPILER_ARGS); @@ -1087,6 +1178,7 @@ private: void AddVariable(ShaderOperandType type, int register_id, int size); void WriteHeader(); + void WriteDebug(); void WriteAnnotations(); void WriteTypes(); void WriteConstants(); @@ -1289,19 +1381,35 @@ static bool operand_load_uint(Spirv* spirv, ShaderOperand op, const String& resu if (operand_is_constant(op)) { - bool u64 = (op.type == ShaderOperandType::IntegerInlineConstant && op.size == 2); - - if (u64) + if (op.size == 2) { - EXIT_NOT_IMPLEMENTED(shift < 0); - EXIT_NOT_IMPLEMENTED(op.constant.i != 0); + EXIT_NOT_IMPLEMENTED(shift < 0 || shift >= 2); - *load = String(U"% = OpBitcast %uint %uint_0").ReplaceStr(U"", index).ReplaceStr(U"", result_id); + if (shift == 0) + { + String id = spirv->GetConstant(op); + *load = String(U"% = OpBitcast %uint %") + .ReplaceStr(U"", index) + .ReplaceStr(U"", id) + .ReplaceStr(U"", result_id); + } else + { + if (op.type == ShaderOperandType::IntegerInlineConstant && op.constant.i < 0) + { + *load = String(U"% = OpBitcast %uint %uint_0xffffffff") + .ReplaceStr(U"", index) + .ReplaceStr(U"", result_id); + } else + { + *load = String(U"% = OpBitcast %uint %uint_0") + .ReplaceStr(U"", index) + .ReplaceStr(U"", result_id); + } + } } else { String id = spirv->GetConstant(op); - - *load = String(U"% = OpBitcast %uint %") + *load = String(U"% = OpBitcast %uint %") .ReplaceStr(U"", index) .ReplaceStr(U"", id) .ReplaceStr(U"", result_id); @@ -1390,6 +1498,7 @@ static String get_scc_check(SccCheck scc_check, int dst_num) { case SccCheck::NonZero: return SCC_NZ_1; break; case SccCheck::Overflow: return SCC_OVERFLOW_1; break; + case SccCheck::CarryOut: return SCC_CARRY_1; break; default: break; } } else if (dst_num == 2) @@ -1398,6 +1507,7 @@ static String get_scc_check(SccCheck scc_check, int dst_num) { case SccCheck::NonZero: return SCC_NZ_2; break; case SccCheck::Overflow: KYTY_NOT_IMPLEMENTED; break; + case SccCheck::CarryOut: KYTY_NOT_IMPLEMENTED; break; default: break; } } @@ -2285,6 +2395,56 @@ KYTY_RECOMPILER_FUNC(Recompile_S_XXX_I32_SVdstSVsrc0SVsrc1) return true; } +/* XXX: Add */ +KYTY_RECOMPILER_FUNC(Recompile_S_XXX_U32_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"", (param[3] == nullptr ? U"" : param[3])) + .ReplaceStr(U"", get_scc_check(scc_check, 1)) + .ReplaceStr(U"", dst_value.value) + .ReplaceStr(U"", index_str); + + return true; +} + KYTY_RECOMPILER_FUNC(Recompile_SAndSaveexecB64_Sdst2Ssrc02) { const auto& inst = code.GetInstructions().At(index); @@ -2339,7 +2499,42 @@ KYTY_RECOMPILER_FUNC(Recompile_SAndSaveexecB64_Sdst2Ssrc02) return true; } -/* XXX: Eq, Le, Lg */ +/* XXX: Eq, Ge, Gt, Lg, Lt, Le */ +KYTY_RECOMPILER_FUNC(Recompile_SCmp_XXX_I32_Ssrc0Ssrc1) +{ + const auto& inst = code.GetInstructions().At(index); + + String load0; + String load1; + + String index_str = String::FromPrintf("%u", index); + + 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"( + + + %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; +} + +/* XXX: Eq, Le, Lg, Gt, Lt */ KYTY_RECOMPILER_FUNC(Recompile_SCmp_XXX_U32_Ssrc0Ssrc1) { const auto& inst = code.GetInstructions().At(index); @@ -2919,7 +3114,86 @@ KYTY_RECOMPILER_FUNC(Recompile_SSwappcB64_Sdst2Ssrc02) KYTY_RECOMPILER_FUNC(Recompile_SWqmB64_Sdst2Ssrc02) { const auto& inst = code.GetInstructions().At(index); - return (inst.dst.type == ShaderOperandType::ExecLo && inst.src[0].type == ShaderOperandType::ExecLo); + + if (inst.dst.type == ShaderOperandType::ExecLo && inst.src[0].type == ShaderOperandType::ExecLo) + { + return true; + } + + String index_str = String::FromPrintf("%u", index); + + EXIT_NOT_IMPLEMENTED(!operand_is_variable(inst.dst)); + + auto dst_value0 = operand_variable_to_str(inst.dst, 0); + auto dst_value1 = operand_variable_to_str(inst.dst, 1); + + EXIT_NOT_IMPLEMENTED(dst_value0.type != SpirvType::Uint); + + EXIT_NOT_IMPLEMENTED(operand_is_exec(inst.dst)); + + String load0; + String load1; + + if (!operand_load_uint(spirv, inst.src[0], U"t0_", index_str, &load0, 0)) + { + return false; + } + if (!operand_load_uint(spirv, inst.src[0], U"t1_", index_str, &load1, 1)) + { + return false; + } + + static const char32_t* text = UR"( + + + %t170_ = OpFunctionCall %uint %wqm %t0_ %uint_0 %uint_15 + %t172_ = OpBitwiseOr %uint %uint_0 %t170_ + %t179_ = OpFunctionCall %uint %wqm %t0_ %uint_4 %uint_240 + %t181_ = OpBitwiseOr %uint %t172_ %t179_ + %t188_ = OpFunctionCall %uint %wqm %t0_ %uint_8 %uint_0x00000f00 + %t190_ = OpBitwiseOr %uint %t181_ %t188_ + %t197_ = OpFunctionCall %uint %wqm %t0_ %uint_12 %uint_0x0000f000 + %t199_ = OpBitwiseOr %uint %t190_ %t197_ + %t206_ = OpFunctionCall %uint %wqm %t0_ %uint_16 %uint_0x000f0000 + %t208_ = OpBitwiseOr %uint %t199_ %t206_ + %t215_ = OpFunctionCall %uint %wqm %t0_ %uint_20 %uint_0x00f00000 + %t217_ = OpBitwiseOr %uint %t208_ %t215_ + %t224_ = OpFunctionCall %uint %wqm %t0_ %uint_24 %uint_0x0f000000 + %t226_ = OpBitwiseOr %uint %t217_ %t224_ + %t233_ = OpFunctionCall %uint %wqm %t0_ %uint_28 %uint_0xf0000000 + %t235_ = OpBitwiseOr %uint %t226_ %t233_ + %t1701_ = OpFunctionCall %uint %wqm %t1_ %uint_0 %uint_15 + %t1721_ = OpBitwiseOr %uint %uint_0 %t1701_ + %t1791_ = OpFunctionCall %uint %wqm %t1_ %uint_4 %uint_240 + %t1811_ = OpBitwiseOr %uint %t1721_ %t1791_ + %t1881_ = OpFunctionCall %uint %wqm %t1_ %uint_8 %uint_0x00000f00 + %t1901_ = OpBitwiseOr %uint %t1811_ %t1881_ + %t1971_ = OpFunctionCall %uint %wqm %t1_ %uint_12 %uint_0x0000f000 + %t1991_ = OpBitwiseOr %uint %t1901_ %t1971_ + %t2061_ = OpFunctionCall %uint %wqm %t1_ %uint_16 %uint_0x000f0000 + %t2081_ = OpBitwiseOr %uint %t1991_ %t2061_ + %t2151_ = OpFunctionCall %uint %wqm %t1_ %uint_20 %uint_0x00f00000 + %t2171_ = OpBitwiseOr %uint %t2081_ %t2151_ + %t2241_ = OpFunctionCall %uint %wqm %t1_ %uint_24 %uint_0x0f000000 + %t2261_ = OpBitwiseOr %uint %t2171_ %t2241_ + %t2331_ = OpFunctionCall %uint %wqm %t1_ %uint_28 %uint_0xf0000000 + %t2351_ = OpBitwiseOr %uint %t2261_ %t2331_ + OpStore % %t235_ + OpStore % %t2351_ + + +)"; + + *dst_source += String(text) + .ReplaceStr(U"", load0) + .ReplaceStr(U"", load1) + .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; } KYTY_RECOMPILER_FUNC(Recompile_SWaitcnt_Imm) @@ -3051,7 +3325,7 @@ KYTY_RECOMPILER_FUNC(Recompile_TBufferLoadFormatXyzw_Vdata4Vaddr2SvSoffsOffenIdx return false; } -/* XXX: Eq, Ge, Le, Neq */ +/* XXX: F, Eq, Ge, Gt, Le, Lg, Lt, Neq, Nge, Ngt, Nlg, Nlt, O, Tru, U */ KYTY_RECOMPILER_FUNC(Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1) { const auto& inst = code.GetInstructions().At(index); @@ -3101,7 +3375,7 @@ KYTY_RECOMPILER_FUNC(Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1) return true; } -/* XXX: Eq, Ne, Gt */ +/* XXX: Eq, Ne, Gt, Ge, F, Le, T */ KYTY_RECOMPILER_FUNC(Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1) { const auto& inst = code.GetInstructions().At(index); @@ -3151,7 +3425,7 @@ KYTY_RECOMPILER_FUNC(Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1) return true; } -/* XXX: Le, Ge */ +/* XXX: Le, Ge, F, Gt, Lt, T */ KYTY_RECOMPILER_FUNC(Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1) { const auto& inst = code.GetInstructions().At(index); @@ -3393,16 +3667,26 @@ KYTY_RECOMPILER_FUNC(Recompile_VCvtPkrtzF16F32_SVdstSVsrc0SVsrc1) } // TODO() check VSKIP - // TODO() check EXEC // TODO() check DX10_CLAMP static const char32_t* text = UR"( - %t2_ = OpCompositeConstruct %v2float %t0_ %t1_ + %t0u_ = OpBitcast %uint %t0_ + %t0uu_ = OpBitwiseAnd %uint %t0u_ %uint_0xffffe000 + %t0f_ = OpBitcast %float %t0uu_ + %t1u_ = OpBitcast %uint %t1_ + %t1uu_ = OpBitwiseAnd %uint %t1u_ %uint_0xffffe000 + %t1f_ = OpBitcast %float %t1uu_ + %t2_ = OpCompositeConstruct %v2float %t0f_ %t1f_ %t3_ = OpExtInst %uint %GLSL_std_450 PackHalf2x16 %t2_ %t4_ = OpBitcast %float %t3_ - OpStore % %t4_ + %exec_lo_u_ = OpLoad %uint %exec_lo + %exec_hi_u_ = OpLoad %uint %exec_hi ; unused + %exec_lo_b_ = OpINotEqual %bool %exec_lo_u_ %uint_0 + %tdst_ = OpLoad %float % + %tval_ = OpSelect %float %exec_lo_b_ %t4_ %tdst_ + OpStore % %tval_ )"; *dst_source += String(text) .ReplaceStr(U"", dst_value.value) @@ -3589,7 +3873,7 @@ KYTY_RECOMPILER_FUNC(Recompile_VMbcntLoU32B32_SVdstSVsrc0SVsrc1) // return false; } -/* XXX: Not */ +/* XXX: Bfrev, Not */ KYTY_RECOMPILER_FUNC(Recompile_V_XXX_B32_SVdstSVsrc0) { const auto& inst = code.GetInstructions().At(index); @@ -3610,13 +3894,17 @@ KYTY_RECOMPILER_FUNC(Recompile_V_XXX_B32_SVdstSVsrc0) } // TODO() check VSKIP - // TODO() check EXEC static const char32_t* text = UR"( %tf_ = OpBitcast %float %t_ - OpStore % %tf_ + %exec_lo_u_ = OpLoad %uint %exec_lo + %exec_hi_u_ = OpLoad %uint %exec_hi ; unused + %exec_lo_b_ = OpINotEqual %bool %exec_lo_u_ %uint_0 + %tdst_ = OpLoad %float % + %tval_ = OpSelect %float %exec_lo_b_ %tf_ %tdst_ + OpStore % %tval_ )"; *dst_source += String(text) .ReplaceStr(U"", dst_value.value) @@ -3731,7 +4019,7 @@ KYTY_RECOMPILER_FUNC(Recompile_V_XXX_F32_SVdstSVsrc0SVsrc1) return true; } -/* XXX: Rcp, Rsq, Sqrt */ +/* XXX: Rcp, Rsq, Sqrt, Ceil, Floor, Fract, Rndne, Trunc */ KYTY_RECOMPILER_FUNC(Recompile_V_XXX_F32_SVdstSVsrc0) { const auto& inst = code.GetInstructions().At(index); @@ -3759,7 +4047,8 @@ KYTY_RECOMPILER_FUNC(Recompile_V_XXX_F32_SVdstSVsrc0) static const char32_t* text = UR"( - + + %exec_lo_u_ = OpLoad %uint %exec_lo %exec_hi_u_ = OpLoad %uint %exec_hi ; unused %exec_lo_b_ = OpINotEqual %bool %exec_lo_u_ %uint_0 @@ -3770,13 +4059,14 @@ KYTY_RECOMPILER_FUNC(Recompile_V_XXX_F32_SVdstSVsrc0) *dst_source += String(text) .ReplaceStr(U"", dst_value.value) .ReplaceStr(U"", load0) - .ReplaceStr(U"", param[0]) + .ReplaceStr(U"", param[0]) + .ReplaceStr(U"", (param[1] == nullptr ? U"" : param[1])) .ReplaceStr(U"", index_str); return true; } -/* XXX: And, Bcnt, Lshr, Lshl, Lshlrev, Lshrrev, MulU32U24, MulLoU32, MulHiU32 */ +/* XXX: And, Or, Bcnt, Bfm, Lshr, Lshl, Lshlrev, Lshrrev, MulU32U24, MulLoU32, MulHiU32 */ KYTY_RECOMPILER_FUNC(Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1) { const auto& inst = code.GetInstructions().At(index); @@ -3930,7 +4220,7 @@ KYTY_RECOMPILER_FUNC(Recompile_VCvt_XXX_F32_SVdstSVsrc0) return true; } -/* XXX: U32, UbyteX */ +/* XXX: U32, I32, UbyteX, F16 */ KYTY_RECOMPILER_FUNC(Recompile_VCvtF32_XXX_SVdstSVsrc0) { const auto& inst = code.GetInstructions().At(index); @@ -4102,6 +4392,57 @@ KYTY_RECOMPILER_FUNC(Recompile_V_XXX_U32_VdstSdst2Vsrc0Vsrc1) return true; } +KYTY_RECOMPILER_FUNC(Recompile_Inject_Debug) +{ + const auto& inst = code.GetInstructions().At(index); + + String index_str = String::FromPrintf("%u", index); + + bool injected = false; + int str_id = 0; + for (const auto& c: code.GetDebugPrintfs()) + { + if (c.pc == inst.pc) + { + Core::StringList loads; + Core::StringList params; + int arg_id = 0; + EXIT_IF(c.args.Size() != c.types.Size()); + for (const auto& a: c.args) + { + auto type = c.types.At(arg_id); + String load; + bool ok = false; + String result_id = String::FromPrintf("t_%d_", arg_id); + switch (type) + { + case ShaderDebugPrintf::Type::Uint: ok = operand_load_uint(spirv, a, result_id, index_str, &load); break; + case ShaderDebugPrintf::Type::Int: ok = operand_load_int(spirv, a, result_id, index_str, &load); break; + case ShaderDebugPrintf::Type::Float: ok = operand_load_float(spirv, a, result_id, index_str, &load); break; + } + EXIT_NOT_IMPLEMENTED(!ok); + loads.Add(load); + params.Add(U"%" + result_id); + arg_id++; + } + + static const char32_t* text = UR"( + + %tt_ = OpExtInst %void %NonSemantic_DebugPrintf 1 %printf_str_ + )"; + *dst_source += String(text) + .ReplaceStr(U"", loads.Concat(U"\n")) + .ReplaceStr(U"", String::FromPrintf("%d", str_id)) + .ReplaceStr(U"", params.Concat(U" ")) + .ReplaceStr(U"", index_str); + injected = true; + } + str_id++; + } + + return injected; +} + static RecompilerFunc g_recomp_func[] = { // clang-format off {Recompile_BufferLoadDword_Vdata1VaddrSvSoffsIdxen, ShaderInstructionType::BufferLoadDword, ShaderInstructionFormat::Vdata1VaddrSvSoffsIdxen, {U""}}, @@ -4155,19 +4496,26 @@ static RecompilerFunc g_recomp_func[] = { U"%td_ = OpSelect %uint %tsb_ %t1_ %t3_" }, SccCheck::None}, {Recompile_S_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SAndB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpBitwiseAnd %uint %t0_ %t1_"}, SccCheck::NonZero}, - {Recompile_S_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SBfmB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%to_ = OpBitwiseAnd %uint %t0_ %uint_31", U"%ts_ = OpBitwiseAnd %uint %t1_ %uint_31", U"%t_ = OpBitFieldInsert %uint %uint_0 %uint_0xffffffff %to_ %ts_"}, SccCheck::None}, + {Recompile_S_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SBfmB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%tcount_ = OpBitwiseAnd %uint %t0_ %uint_31", U"%toffset_ = OpBitwiseAnd %uint %t1_ %uint_31", U"%t_ = OpBitFieldInsert %uint %uint_0 %uint_0xffffffff %toffset_ %tcount_"}, SccCheck::None}, {Recompile_S_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SCselectB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t22_ = OpLoad %uint %scc", U"%t2_ = OpINotEqual %bool %t22_ %uint_0", U"%t_ = OpSelect %uint %t2_ %t0_ %t1_"}, SccCheck::None}, {Recompile_S_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SLshlB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %uint %t1_ %uint_31", U"%t_ = OpShiftLeftLogical %uint %t0_ %ts_"}, SccCheck::NonZero}, {Recompile_S_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SLshrB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %uint %t1_ %uint_31", U"%t_ = OpShiftRightLogical %uint %t0_ %ts_"}, SccCheck::NonZero}, {Recompile_S_XXX_I32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SAddI32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpIAdd %int %t0_ %t1_"}, SccCheck::Overflow}, {Recompile_S_XXX_I32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SMulI32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpIMul %int %t0_ %t1_"}, SccCheck::None}, + {Recompile_S_XXX_U32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SAddcU32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%tscc_ = OpLoad %uint %scc", U"%ts_ = OpFunctionCall %v2uint %addc %t0_ %t1_ %tscc_", U"%t_ = OpCompositeExtract %uint %ts_ 0", U"%carry_ = OpCompositeExtract %uint %ts_ 1"}, SccCheck::CarryOut}, + {Recompile_S_XXX_U32_SVdstSVsrc0SVsrc1, ShaderInstructionType::SAddU32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpIAddCarry %ResTypeU %t0_ %t1_", U"%t_ = OpCompositeExtract %uint %ts_ 0", U"%carry_ = OpCompositeExtract %uint %ts_ 1"}, SccCheck::CarryOut}, {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VAndB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpBitwiseAnd %uint %t0_ %t1_"}}, {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VBcntU32B32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%tb_ = OpBitCount %int %t0_", U"%tbu_ = OpBitcast %uint %tb_", U"%t_ = OpIAdd %uint %tbu_ %t1_"}}, {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VLshlB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %uint %t1_ %uint_31", U"%t_ = OpShiftLeftLogical %uint %t0_ %ts_"}}, {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VLshlrevB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %uint %t0_ %uint_31", U"%t_ = OpShiftLeftLogical %uint %t1_ %ts_"}}, {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VLshrB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %uint %t1_ %uint_31", U"%t_ = OpShiftRightLogical %uint %t0_ %ts_"}}, {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VLshrrevB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %uint %t0_ %uint_31", U"%t_ = OpShiftRightLogical %uint %t1_ %ts_"}}, + {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMulHiU32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpFunctionCall %uint %mul_hi_uint %t0_ %t1_"}}, + {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMulLoU32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpFunctionCall %uint %mul_lo_uint %t0_ %t1_"}}, {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMulU32U24, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%tu0_ = OpBitwiseAnd %uint %t0_ %uint_0x00ffffff", U"%tu1_ = OpBitwiseAnd %uint %t1_ %uint_0x00ffffff", U"%t_ = OpFunctionCall %uint %mul_lo_uint %tu0_ %tu1_"}}, + {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VOrB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpBitwiseOr %uint %t0_ %t1_"}}, + {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VXorB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpBitwiseXor %uint %t0_ %t1_"}}, + {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VBfmB32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%tcount_ = OpBitwiseAnd %uint %t0_ %uint_31", U"%toffset_ = OpBitwiseAnd %uint %t1_ %uint_31", U"%t_ = OpBitFieldInsert %uint %uint_0 %uint_0xffffffff %toffset_ %tcount_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMacF32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpExtInst %float %GLSL_std_450 Fma %t0_ %t1_ %tdst_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMaxF32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpExtInst %float %GLSL_std_450 FMax %t0_ %t1_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMinF32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpExtInst %float %GLSL_std_450 FMin %t0_ %t1_"}}, @@ -4177,30 +4525,38 @@ static RecompilerFunc g_recomp_func[] = { {Recompile_V_XXX_I32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VAshrI32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %int %t1_ %int_31", U"%t_ = OpShiftRightArithmetic %int %t0_ %ts_"}}, {Recompile_V_XXX_I32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VAshrrevI32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%ts_ = OpBitwiseAnd %int %t0_ %int_31", U"%t_ = OpShiftRightArithmetic %int %t1_ %ts_"}}, {Recompile_V_XXX_I32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMulLoI32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpFunctionCall %int %mul_lo_int %t0_ %t1_"}}, - {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMulLoU32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpFunctionCall %uint %mul_lo_uint %t0_ %t1_"}}, - {Recompile_V_XXX_B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMulHiU32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U"%t_ = OpFunctionCall %uint %mul_hi_uint %t0_ %t1_"}}, {Recompile_VCvtPkrtzF16F32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VCvtPkrtzF16F32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U""}}, {Recompile_VMbcntHiU32B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMbcntHiU32B32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U""}}, {Recompile_VMbcntLoU32B32_SVdstSVsrc0SVsrc1, ShaderInstructionType::VMbcntLoU32B32, ShaderInstructionFormat::SVdstSVsrc0SVsrc1, {U""}}, {Recompile_SMovB32_SVdstSVsrc0, ShaderInstructionType::SMovB32, ShaderInstructionFormat::SVdstSVsrc0, {U""}}, - {Recompile_VMovB32_SVdstSVsrc0, ShaderInstructionType::VMovB32, ShaderInstructionFormat::SVdstSVsrc0, {U""}}, + {Recompile_V_XXX_B32_SVdstSVsrc0, ShaderInstructionType::VBfrevB32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpBitReverse %uint %t0_"}}, {Recompile_V_XXX_B32_SVdstSVsrc0, ShaderInstructionType::VNotB32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpNot %uint %t0_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VRcpF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpFDiv %float %float_1_000000 %t0_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VRsqF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 InverseSqrt %t0_"}}, {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VSqrtF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Sqrt %t0_"}}, + {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VCeilF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Ceil %t0_"}}, + {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VFloorF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Floor %t0_"}}, + {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VFractF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Fract %t0_"}}, + {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VRndneF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 RoundEven %t0_"}}, + {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VTruncF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Trunc %t0_"}}, + {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VCosF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%tr_ = OpFMul %float %t0_ %float_2pi", U"%t_ = OpExtInst %float %GLSL_std_450 Cos %tr_"}}, + {Recompile_V_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VExpF32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpExtInst %float %GLSL_std_450 Exp2 %t0_"}}, {Recompile_VCvt_XXX_F32_SVdstSVsrc0, ShaderInstructionType::VCvtU32F32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t1_ = OpExtInst %float %GLSL_std_450 Trunc %t0_", U"%t2_ = OpConvertFToU %uint %t1_"}}, + {Recompile_VCvtF32_XXX_SVdstSVsrc0, ShaderInstructionType::VCvtF32F16, ShaderInstructionFormat::SVdstSVsrc0, {U"%ts_ = OpExtInst %v2float %GLSL_std_450 UnpackHalf2x16 %t0_", U"%t_ = OpCompositeExtract %float %ts_ 0"}}, + {Recompile_VCvtF32_XXX_SVdstSVsrc0, ShaderInstructionType::VCvtF32I32, ShaderInstructionFormat::SVdstSVsrc0, {U"%ti_ = OpBitcast %int %t0_", U"%t_ = OpConvertSToF %float %ti_"}}, {Recompile_VCvtF32_XXX_SVdstSVsrc0, ShaderInstructionType::VCvtF32U32, ShaderInstructionFormat::SVdstSVsrc0, {U"%t_ = OpConvertUToF %float %t0_"}}, {Recompile_VCvtF32_XXX_SVdstSVsrc0, ShaderInstructionType::VCvtF32Ubyte0, ShaderInstructionFormat::SVdstSVsrc0, {U"%tb_ = OpBitFieldUExtract %uint %t0_ %uint_0 %uint_8", U"%t_ = OpConvertUToF %float %tb_"}}, {Recompile_VCvtF32_XXX_SVdstSVsrc0, ShaderInstructionType::VCvtF32Ubyte1, ShaderInstructionFormat::SVdstSVsrc0, {U"%tb_ = OpBitFieldUExtract %uint %t0_ %uint_8 %uint_8", U"%t_ = OpConvertUToF %float %tb_"}}, {Recompile_VCvtF32_XXX_SVdstSVsrc0, ShaderInstructionType::VCvtF32Ubyte2, ShaderInstructionFormat::SVdstSVsrc0, {U"%tb_ = OpBitFieldUExtract %uint %t0_ %uint_16 %uint_8", U"%t_ = OpConvertUToF %float %tb_"}}, {Recompile_VCvtF32_XXX_SVdstSVsrc0, ShaderInstructionType::VCvtF32Ubyte3, ShaderInstructionFormat::SVdstSVsrc0, {U"%tb_ = OpBitFieldUExtract %uint %t0_ %uint_24 %uint_8", U"%t_ = OpConvertUToF %float %tb_"}}, + {Recompile_VMovB32_SVdstSVsrc0, ShaderInstructionType::VMovB32, ShaderInstructionFormat::SVdstSVsrc0, {U""}}, {Recompile_SAndSaveexecB64_Sdst2Ssrc02, ShaderInstructionType::SAndSaveexecB64, ShaderInstructionFormat::Sdst2Ssrc02, {U""}, SccCheck::NonZero}, {Recompile_SMovB64_Sdst2Ssrc02, ShaderInstructionType::SMovB64, ShaderInstructionFormat::Sdst2Ssrc02, {U""}}, {Recompile_SSwappcB64_Sdst2Ssrc02, ShaderInstructionType::SSwappcB64, ShaderInstructionFormat::Sdst2Ssrc02, {U""}}, - {Recompile_SWqmB64_Sdst2Ssrc02, ShaderInstructionType::SWqmB64, ShaderInstructionFormat::Sdst2Ssrc02, {U""}}, + {Recompile_SWqmB64_Sdst2Ssrc02, ShaderInstructionType::SWqmB64, ShaderInstructionFormat::Sdst2Ssrc02, {U""}, SccCheck::NonZero}, {Recompile_SWaitcnt_Imm, ShaderInstructionType::SWaitcnt, ShaderInstructionFormat::Imm, {U""}}, @@ -4212,23 +4568,52 @@ static RecompilerFunc g_recomp_func[] = { {Recompile_V_XXX_U32_VdstSdst2Vsrc0Vsrc1, ShaderInstructionType::VSubrevI32, ShaderInstructionFormat::VdstSdst2Vsrc0Vsrc1, {U"%t_ = OpISubBorrow %ResTypeU %t1_ %t0_"}}, {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpEqF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdEqual"}}, - {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLeF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdLessThanEqual"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpFF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_1 ; "}}, {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGeF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdGreaterThanEqual"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGtF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdGreaterThan"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLeF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdLessThanEqual"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLgF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdNotEqual"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLtF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFOrdLessThan"}}, {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNeqF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordNotEqual"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNgeF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordLessThan"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNgtF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordLessThanEqual"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNleF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordGreaterThan"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNlgF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordEqual"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNltF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFUnordGreaterThanEqual"}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpOF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFunctionCall %bool %ordered %t0_ %t1_ ; "}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpTruF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_0 ; "}}, + {Recompile_VCmp_XXX_F32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpUF32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpFunctionCall %bool %unordered %t0_ %t1_ ; "}}, {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpEqI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual"}}, {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpEqU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual"}}, + {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpFI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_1 ; "}}, + {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGeI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpSGreaterThanEqual"}}, {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGtI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpSGreaterThan"}}, + {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLeI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpSLessThanEqual"}}, + {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLtI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpSLessThan"}}, {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNeI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpINotEqual"}}, {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpNeU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpINotEqual"}}, + {Recompile_VCmp_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpTI32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_0 ; "}}, + {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpFU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_1 ; "}}, {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGeU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpUGreaterThanEqual"}}, + {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpGtU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpUGreaterThan"}}, {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLeU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpULessThanEqual"}}, + {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpLtU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpULessThan"}}, + {Recompile_VCmp_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpTU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual %bool %uint_0 %uint_0 ; "}}, {Recompile_VCmpx_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpxEqU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpIEqual"}}, {Recompile_VCmpx_XXX_I32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpxNeU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpINotEqual"}}, {Recompile_VCmpx_XXX_U32_SmaskVsrc0Vsrc1, ShaderInstructionType::VCmpxGtU32, ShaderInstructionFormat::SmaskVsrc0Vsrc1, {U"OpUGreaterThan"}}, + {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpEqI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpIEqual"}}, + {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpGeI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpSGreaterThanEqual"}}, + {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpGtI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpSGreaterThan"}}, + {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLgI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpINotEqual"}}, + {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLtI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpSLessThan"}}, + {Recompile_SCmp_XXX_I32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLeI32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpSLessThanEqual"}}, {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpEqU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpIEqual"}}, {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpGeU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpUGreaterThanEqual"}}, + {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpGtU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpUGreaterThan"}}, {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLeU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpULessThanEqual"}}, + {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLtU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpULessThan"}}, {Recompile_SCmp_XXX_U32_Ssrc0Ssrc1, ShaderInstructionType::SCmpLgU32, ShaderInstructionFormat::Ssrc0Ssrc1, {U"OpINotEqual"}}, {Recompile_VCndmaskB32_VdstVsrc0Vsrc1Smask2, ShaderInstructionType::VCndmaskB32, ShaderInstructionFormat::VdstVsrc0Vsrc1Smask2, {U""}}, @@ -4450,6 +4835,7 @@ void Spirv::GenerateSource() } WriteHeader(); + WriteDebug(); WriteAnnotations(); WriteTypes(); WriteConstants(); @@ -4465,8 +4851,9 @@ void Spirv::WriteHeader() { static const char32_t* header = UR"( ; Header - OpCapability Shader -%GLSL_std_450 = OpExtInstImport "GLSL.std.450" + OpCapability Shader + + OpMemoryModel Logical GLSL450 OpEntryPoint %main "main" @@ -4476,6 +4863,16 @@ void Spirv::WriteHeader() String execution_mode; Core::StringList vars; + Core::StringList extensions; + Core::StringList imports; + + imports.Add(U"%GLSL_std_450 = OpExtInstImport \"GLSL.std.450\""); + + if (Config::SpirvDebugPrintfEnabled()) + { + extensions.Add(U"OpExtension \"SPV_KHR_non_semantic_info\""); + imports.Add(U"%NonSemantic_DebugPrintf = OpExtInstImport \"NonSemantic.DebugPrintf\""); + } if (m_bind != nullptr) { @@ -4550,7 +4947,23 @@ void Spirv::WriteHeader() default: EXIT("unknown type: %s\n", Core::EnumName(m_code.GetType()).C_Str()); break; } - m_source += header_str.ReplaceStr(U"", vars.Concat(U' ')).ReplaceStr(U"", execution_mode); + m_source += header_str.ReplaceStr(U"", vars.Concat(U' ')) + .ReplaceStr(U"", execution_mode) + .ReplaceStr(U"", imports.Concat(U"\n" + String(U' ', 15))) + .ReplaceStr(U"", extensions.Concat(U"\n" + String(U' ', 15))); +} + +void Spirv::WriteDebug() +{ + if (Config::SpirvDebugPrintfEnabled()) + { + int index = 0; + for (const auto& p: m_code.GetDebugPrintfs()) + { + m_source += String::FromPrintf("%%printf_str_%d = OpString \"%s\"", index, p.format.C_Str()); + index++; + } + } } void Spirv::WriteAnnotations() @@ -4696,7 +5109,8 @@ void Spirv::WriteTypes() %bool = OpTypeBool %v2float = OpTypeVector %float 2 %v3float = OpTypeVector %float 3 - %v4float = OpTypeVector %float 4 + %v4float = OpTypeVector %float 4 + %v2uint = OpTypeVector %uint 2 %v3uint = OpTypeVector %uint 3 %_ptr_Input_int = OpTypePointer Input %int %_ptr_Input_uint = OpTypePointer Input %uint @@ -4717,13 +5131,16 @@ void Spirv::WriteTypes() %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint %ResTypeI = OpTypeStruct %int %int - %ResTypeU = OpTypeStruct %uint %uint + %ResTypeU = OpTypeStruct %uint %uint %function_void = OpTypeFunction %void %function_fetch1 = OpTypeFunction %void %_ptr_Function_float %_ptr_Function_float %function_fetch2 = OpTypeFunction %void %_ptr_Function_float %_ptr_Function_float %_ptr_Function_v2float %function_fetch3 = OpTypeFunction %void %_ptr_Function_float %_ptr_Function_float %_ptr_Function_float %_ptr_Function_v3float %function_fetch4 = OpTypeFunction %void %_ptr_Function_float %_ptr_Function_float %_ptr_Function_float %_ptr_Function_float %_ptr_Function_v4float %function_u_u = OpTypeFunction %uint %uint %uint + %function_u_u_u = OpTypeFunction %uint %uint %uint %uint + %function_u2_u_u_u = OpTypeFunction %v2uint %uint %uint %uint + %function_b_f_f = OpTypeFunction %bool %float %float %function_i_i = OpTypeFunction %int %int %int %function_tbuffer_load_format_xyzw = OpTypeFunction %void %_ptr_Function_float %_ptr_Function_float %_ptr_Function_float %_ptr_Function_float %_ptr_Function_int %_ptr_Function_int %_ptr_Function_int %_ptr_Function_int %_ptr_Function_int %function_buffer_load_store_float1 = OpTypeFunction %void %_ptr_Function_float %_ptr_Function_int %_ptr_Function_int %_ptr_Function_int %_ptr_Function_int @@ -4835,8 +5252,9 @@ void Spirv::WriteConstants() static const char32_t* comment = UR"( ; Constants - %true = OpConstantTrue %bool - %false = OpConstantFalse %bool + %true = OpConstantTrue %bool + %false = OpConstantFalse %bool + %float_2pi = OpConstant %float 6.283185307179586476925286766559 )"; m_source += comment; @@ -5026,18 +5444,36 @@ void Spirv::WriteLocalVariables() if (m_code.GetType() == ShaderType::Compute) { - static const char32_t* text = UR"( - %LocalInvocationID_114 = OpAccessChain %_ptr_Input_uint %gl_LocalInvocationID %uint_0 - %LocalInvocationID_115 = OpLoad %uint %LocalInvocationID_114 - %LocalInvocationID_116 = OpBitcast %float %LocalInvocationID_115 - OpStore %v0 %LocalInvocationID_116 - %WorkGroupID_120 = OpAccessChain %_ptr_Input_uint %gl_WorkGroupID %uint_0 - %WorkGroupID_121 = OpLoad %uint %WorkGroupID_120 - OpStore % %WorkGroupID_121 + static const char32_t* text_thread_id = UR"( + %LocalInvocationID_114_ = OpAccessChain %_ptr_Input_uint %gl_LocalInvocationID %uint_ + %LocalInvocationID_115_ = OpLoad %uint %LocalInvocationID_114_ + %LocalInvocationID_116_ = OpBitcast %float %LocalInvocationID_115_ + OpStore %v %LocalInvocationID_116_ +)"; + + static const char32_t* text_group_id = UR"( + %WorkGroupID_120_ = OpAccessChain %_ptr_Input_uint %gl_WorkGroupID %uint_ + %WorkGroupID_121_ = OpLoad %uint %WorkGroupID_120_ + OpStore % %WorkGroupID_121_ )"; if (m_cs_input_info != nullptr) { - m_source += String(text).ReplaceStr(U"", String::FromPrintf("s%u", m_cs_input_info->workgroup_register)); + for (int i = 0; i < m_cs_input_info->thread_ids_num; i++) + { + m_source += String(text_thread_id).ReplaceStr(U"", String::FromPrintf("%d", i)); + } + + int reg = 0; + for (int i = 0; i < 3; i++) + { + if (m_cs_input_info->group_id[i]) + { + m_source += String(text_group_id) + .ReplaceStr(U"", String::FromPrintf("s%u", m_cs_input_info->workgroup_register + reg)) + .ReplaceStr(U"", String::FromPrintf("%d", i)); + reg++; + } + } } } @@ -5192,6 +5628,7 @@ void Spirv::WriteInstructions() { int index = -1; const auto& instructions = m_code.GetInstructions(); + bool need_debug = (Config::SpirvDebugPrintfEnabled() && !m_code.GetDebugPrintfs().IsEmpty()); for (const auto& inst: instructions) { index++; @@ -5216,16 +5653,9 @@ void Spirv::WriteInstructions() } } - // if ((index == 0 && inst.type == ShaderInstructionType::SMovB32 && inst.format == ShaderInstructionFormat::SVdstSVsrc0 && - // inst.dst.type == ShaderOperandType::VccHi) || - // (inst.type == ShaderInstructionType::SEndpgm && index == instructions.Size() - 1)) - // { - // continue; - // } - String src = ShaderCode::DbgInstructionToStr(inst); - String dst; + String dst_debug; bool ok = false; for (auto& func: g_recomp_func) @@ -5245,6 +5675,11 @@ void Spirv::WriteInstructions() m_source += String::FromPrintf("; %s\n", src.C_Str()); m_source += String::FromPrintf("%s\n", dst.C_Str()); + + if (need_debug && Recompile_Inject_Debug(index, m_code, &dst_debug, this, nullptr, SccCheck::None)) + { + m_source += String::FromPrintf("%s\n", dst_debug.C_Str()); + } } } @@ -5265,6 +5700,21 @@ void Spirv::WriteFunctions() m_source += FUNC_ABS_DIFF; } + if (m_code.HasAnyOf({ShaderInstructionType::SWqmB64})) + { + m_source += FUNC_WQM; + } + + if (m_code.HasAnyOf({ShaderInstructionType::SAddcU32})) + { + m_source += FUNC_ADDC; + } + + if (m_code.HasAnyOf({ShaderInstructionType::VCmpOF32, ShaderInstructionType::VCmpUF32})) + { + m_source += FUNC_ORDERED; + } + if (m_code.HasAnyOf({ShaderInstructionType::VMulLoI32, ShaderInstructionType::VMulLoU32, ShaderInstructionType::VMulHiU32, ShaderInstructionType::VMadU32U24, ShaderInstructionType::VMulU32U24})) { @@ -5318,7 +5768,7 @@ void Spirv::FindConstants() AddConstantFloat(1.0f); AddConstantFloat(2.0f); AddConstantFloat(4.0f); - for (int i = 0; i <= 16; i++) + for (int i = 0; i <= 32; i++) { AddConstantInt(i); AddConstantUint(i); @@ -5349,7 +5799,16 @@ void Spirv::FindConstants() AddConstantUint(127); AddConstantUint(0x3fff); AddConstantUint(0xffffff); + AddConstantUint(0xffffe000); AddConstantUint(0xffffffff); + AddConstantUint(0x0000000f); + AddConstantUint(0x000000f0); + AddConstantUint(0x00000f00); + AddConstantUint(0x0000f000); + AddConstantUint(0x000f0000); + AddConstantUint(0x00f00000); + AddConstantUint(0x0f000000); + AddConstantUint(0xf0000000); } if (m_cs_input_info != nullptr) { @@ -5398,7 +5857,8 @@ void Spirv::FindVariables() if (m_cs_input_info != nullptr) { - AddVariable(ShaderOperandType::Sgpr, m_cs_input_info->workgroup_register, 1); + AddVariable(ShaderOperandType::Vgpr, 0, 3); + AddVariable(ShaderOperandType::Sgpr, m_cs_input_info->workgroup_register, 3); } if (m_bind != nullptr) diff --git a/source/emulator/src/Graphics/VideoOutBuffer.cpp b/source/emulator/src/Graphics/VideoOutBuffer.cpp index ab2b7eb..48849d3 100644 --- a/source/emulator/src/Graphics/VideoOutBuffer.cpp +++ b/source/emulator/src/Graphics/VideoOutBuffer.cpp @@ -34,7 +34,7 @@ void* VideoOutBufferObject::Create(GraphicContext* ctx, const uint64_t* vaddr, c vk_obj->extent.width = width; vk_obj->extent.height = height; - vk_obj->format = VK_FORMAT_R8G8B8A8_SRGB; + vk_obj->format = VK_FORMAT_B8G8R8A8_SRGB; // VK_FORMAT_R8G8B8A8_SRGB; vk_obj->image = nullptr; vk_obj->image_view = nullptr; diff --git a/source/emulator/src/Graphics/Window.cpp b/source/emulator/src/Graphics/Window.cpp index 0fc868b..656b5da 100644 --- a/source/emulator/src/Graphics/Window.cpp +++ b/source/emulator/src/Graphics/Window.cpp @@ -43,7 +43,7 @@ #ifdef KYTY_EMU_ENABLED //#define KYTY_ENABLE_BEST_PRACTICES -//#define KYTY_ENABLE_DEBUG_PRINTF +#define KYTY_ENABLE_DEBUG_PRINTF #define KYTY_DBG_INPUT namespace Kyty::Libs::Graphics { @@ -1617,6 +1617,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugMessengerCallback(VkDebugUtilsM const char* severity_color = FG_DEFAULT; bool skip = false; bool error = false; + bool debug_printf = false; switch (message_severity) { case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: @@ -1625,8 +1626,17 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugMessengerCallback(VkDebugUtilsM skip = true; break; case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: - severity_str = "I"; - severity_color = FG_DEFAULT; + if ((message_types & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) != 0 && Config::SpirvDebugPrintfEnabled() && + strcmp(callback_data->pMessageIdName, "UNASSIGNED-DEBUG-PRINTF") == 0) + { + debug_printf = true; + severity_color = FG_BRIGHT_YELLOW; + skip = true; + } else + { + severity_str = "I"; + severity_color = FG_DEFAULT; + } break; case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: severity_str = "W"; @@ -1652,6 +1662,15 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugMessengerCallback(VkDebugUtilsM FG_DEFAULT); } + if (debug_printf) + { + auto strs = String::FromUtf8(callback_data->pMessage).Split(U'|'); + if (!strs.IsEmpty()) + { + printf("%s%s%s\n", severity_color, strs.At(strs.Size() - 1).C_Str(), FG_DEFAULT); + } + } + return VK_FALSE; } @@ -1836,10 +1855,19 @@ static void VulkanCreate(WindowContext* ctx) #endif }; + uint32_t enabled_features_count = sizeof(enabled_features) / sizeof(VkValidationFeatureEnableEXT); + +#ifdef KYTY_ENABLE_DEBUG_PRINTF + if (!Config::SpirvDebugPrintfEnabled()) + { + enabled_features_count--; + } +#endif + VkValidationFeaturesEXT validation_features {}; validation_features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT; validation_features.pNext = nullptr; - validation_features.enabledValidationFeatureCount = sizeof(enabled_features) / sizeof(VkValidationFeatureEnableEXT); + validation_features.enabledValidationFeatureCount = enabled_features_count; validation_features.pEnabledValidationFeatures = enabled_features; validation_features.disabledValidationFeatureCount = 0; validation_features.pDisabledValidationFeatures = disabled_features; @@ -1893,11 +1921,15 @@ static void VulkanCreate(WindowContext* ctx) } Vector device_extensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME, -#ifdef KYTY_ENABLE_DEBUG_PRINTF - VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, -#endif "VK_KHR_maintenance1"}; +#ifdef KYTY_ENABLE_DEBUG_PRINTF + if (Config::SpirvDebugPrintfEnabled()) + { + device_extensions.Add(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME); + } +#endif + ctx->surface_capabilities = new SurfaceCapabilities {}; ctx->graphic_ctx.physical_device = diff --git a/source/emulator/src/Kyty.cpp b/source/emulator/src/Kyty.cpp index 6bc0f2e..8f418cc 100644 --- a/source/emulator/src/Kyty.cpp +++ b/source/emulator/src/Kyty.cpp @@ -6,6 +6,7 @@ #include "Kyty/Core/String.h" #include "Kyty/Core/Subsystems.h" #include "Kyty/Core/Threads.h" +#include "Kyty/Core/Vector.h" #include "Kyty/Scripts/Scripts.h" #include "Emulator/Common.h" @@ -240,6 +241,82 @@ KYTY_SCRIPT_FUNC(kyty_shader_disable) return 0; } +KYTY_SCRIPT_FUNC(kyty_shader_printf) +{ + if (Scripts::ArgGetVarCount() != 4) + { + EXIT("invalid args\n"); + } + + auto id = Scripts::ArgGetVar(0).ToString().ToUint64(16); + auto pc = Scripts::ArgGetVar(1).ToInteger(); + auto format = Scripts::ArgGetVar(2).ToString(); + auto args = Scripts::ArgGetVar(3); + + if (!args.IsTable()) + { + EXIT("invalid args\n"); + } + + Libs::Graphics::ShaderDebugPrintf p; + p.pc = pc; + p.format = format; + + for (const auto& t: args.GetPairs()) + { + const auto& arg_t = t.GetValue(); + + if (!arg_t.IsTable()) + { + EXIT("invalid arg\n"); + } + + auto type = arg_t.GetValue(0).ToString(); + auto arg = arg_t.GetValue(1).ToString(); + + Libs::Graphics::ShaderOperand op; + + if (arg.StartsWith('s', String::Case::Insensitive) && Core::Char::IsDecimal(arg.At(1))) + { + op.type = Libs::Graphics::ShaderOperandType::Sgpr; + op.register_id = arg.RemoveFirst(1).ToInt32(); + op.size = 1; + } else if (arg.StartsWith('v', String::Case::Insensitive) && Core::Char::IsDecimal(arg.At(1))) + { + op.type = Libs::Graphics::ShaderOperandType::Vgpr; + op.register_id = arg.RemoveFirst(1).ToInt32(); + op.size = 1; + } else + { + EXIT("unknown arg: %s\n", arg.C_Str()); + } + + p.args.Add(op); + + Libs::Graphics::ShaderDebugPrintf::Type st = Libs::Graphics::ShaderDebugPrintf::Type::Int; + + if (type.EqualNoCase(U"int")) + { + st = Libs::Graphics::ShaderDebugPrintf::Type::Int; + } else if (type.EqualNoCase(U"uint")) + { + st = Libs::Graphics::ShaderDebugPrintf::Type::Uint; + } else if (type.EqualNoCase(U"float")) + { + st = Libs::Graphics::ShaderDebugPrintf::Type::Float; + } else + { + EXIT("unknown type: %s\n", arg.C_Str()); + } + + p.types.Add(st); + } + + Libs::Graphics::ShaderInjectDebugPrintf(id, p); + + return 0; +} + void kyty_help() {} } // namespace LuaFunc @@ -253,6 +330,7 @@ void kyty_reg() Scripts::RegisterFunc("kyty_execute", LuaFunc::kyty_execute_func, LuaFunc::kyty_help); Scripts::RegisterFunc("kyty_mount", LuaFunc::kyty_mount_func, LuaFunc::kyty_help); Scripts::RegisterFunc("kyty_shader_disable", LuaFunc::kyty_shader_disable, LuaFunc::kyty_help); + Scripts::RegisterFunc("kyty_shader_printf", LuaFunc::kyty_shader_printf, LuaFunc::kyty_help); } #else