diff --git a/externals/sirit b/externals/sirit index 37090c74c..b51af1a2c 160000 --- a/externals/sirit +++ b/externals/sirit @@ -1 +1 @@ -Subproject commit 37090c74cc6e680f2bc334cac8fd182f7634a1f6 +Subproject commit b51af1a2ca01090cbcbd4855dc29adf40d3bd612 diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 3bdea9c1a..86bbeacc4 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -49,6 +49,8 @@ void EmitPrologue(EmitContext& ctx); void EmitEpilogue(EmitContext& ctx); void EmitDiscard(EmitContext& ctx); void EmitDiscardCond(EmitContext& ctx, Id condition); +void EmitVaArg(EmitContext& ctx, IR::Inst* inst, Id arg, Id next); +void EmitDebugPrint(EmitContext& ctx, IR::Inst* inst); void EmitBarrier(EmitContext& ctx); void EmitWorkgroupMemoryBarrier(EmitContext& ctx); void EmitDeviceMemoryBarrier(EmitContext& ctx); diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp index 283c9b16f..cef70b16a 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp @@ -1,8 +1,12 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include "common/assert.h" #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" #include "shader_recompiler/backend/spirv/spirv_emit_context.h" +#include "shader_recompiler/ir/debug_print.h" namespace Shader::Backend::SPIRV { @@ -49,4 +53,37 @@ void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) { throw NotImplementedException("Geometry streams"); } +void EmitVaArg(EmitContext& ctx, IR::Inst* inst, Id arg, Id next) { + IR::Value next_val = inst->Arg(1); + u32 va_arglist_idx; + if (next_val.IsEmpty()) { + va_arglist_idx = ctx.va_arg_lists.size(); + ctx.va_arg_lists.emplace_back(); + } else { + va_arglist_idx = next_val.Inst()->Flags().va_arg_idx; + } + + ctx.va_arg_lists[va_arglist_idx].push_back(arg); + VariadicArgInfo va_info; + va_info.va_arg_idx.Assign(va_arglist_idx); +} + +void EmitDebugPrint(EmitContext& ctx, IR::Inst* inst) { + const std::string& fmt = + ctx.info.debug_print_strings.at(inst->Flags().string_idx); + Id fmt_id = ctx.String(fmt); + + IR::Value va_arg_list_val = inst->Arg(0); + boost::container::small_vector fmt_arg_operands; + if (!va_arg_list_val.IsEmpty()) { + u32 va_arglist_idx = va_arg_list_val.Inst()->Flags().va_arg_idx; + const auto& va_arglist = ctx.va_arg_lists[va_arglist_idx]; + // reverse the order + std::copy(va_arglist.rbegin(), va_arglist.rend(), fmt_arg_operands.end()); + } + + ASSERT(fmt_arg_operands.size() == inst->Flags().num_args); + ctx.OpDebugPrintf(fmt_id, fmt_arg_operands); +} + } // namespace Shader::Backend::SPIRV diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index 9db019946..b43f53356 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h @@ -244,6 +244,8 @@ public: std::array output_params{}; std::array frag_outputs{}; + boost::container::small_vector, 4> va_arg_lists; + private: void DefineArithmeticTypes(); void DefineInterfaces(); diff --git a/src/shader_recompiler/info.h b/src/shader_recompiler/info.h index 739214ec9..d1ca61be6 100644 --- a/src/shader_recompiler/info.h +++ b/src/shader_recompiler/info.h @@ -179,6 +179,8 @@ struct Info { std::span user_data; Stage stage; + boost::container::small_vector debug_print_strings; + u64 pgm_hash{}; VAddr pgm_base; bool has_storage_images{}; diff --git a/src/shader_recompiler/ir/debug_print.h b/src/shader_recompiler/ir/debug_print.h new file mode 100644 index 000000000..e2b5a537f --- /dev/null +++ b/src/shader_recompiler/ir/debug_print.h @@ -0,0 +1,16 @@ +#include "common/bit_field.h" +#include "src/common/enum.h" + +#pragma once + +union VariadicArgInfo { + u32 raw; + + BitField<0, 12, u32> va_arg_idx; +}; + +union DebugPrintInfo { + u32 raw; + BitField<0, 16, u32> string_idx; + BitField<16, 16, u32> num_args; +}; \ No newline at end of file diff --git a/src/shader_recompiler/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index 412c9581f..a5430019a 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -2,9 +2,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include +#include +#include "common/assert.h" #include "shader_recompiler/exception.h" +#include "shader_recompiler/ir/debug_print.h" #include "shader_recompiler/ir/ir_emitter.h" +#include "shader_recompiler/ir/opcodes.h" #include "shader_recompiler/ir/value.h" namespace Shader::IR { @@ -1553,4 +1558,69 @@ void IREmitter::ImageWrite(const Value& handle, const Value& coords, const Value Inst(Opcode::ImageWrite, Flags{info}, handle, coords, color); } +Value IREmitter::VaArg(Value arg, Value next) { + return Inst(Opcode::VaArg, arg, next); +} + +void IREmitter::DebugPrint(std::string_view format, boost::container::small_vector args, + bool infer_specifiers) { + auto infer_specifier = [&](IR::Value arg) -> const char* { + switch (arg.Type()) { + case Shader::IR::Type::U1: + case Shader::IR::Type::U8: + case Shader::IR::Type::U16: + case Shader::IR::Type::U32: + return "%u"; + case Shader::IR::Type::U64: + return "%lu"; + case Shader::IR::Type::F16: + case Shader::IR::Type::F32: + case Shader::IR::Type::F64: + return "%lf"; + case Shader::IR::Type::U32x2: + return "%v2u"; + case Shader::IR::Type::U32x3: + return "%v3u"; + case Shader::IR::Type::U32x4: + return "%v4u"; + case Shader::IR::Type::F16x2: + case Shader::IR::Type::F32x2: + case Shader::IR::Type::F64x2: + return "%v2f"; + case Shader::IR::Type::F16x3: + case Shader::IR::Type::F32x3: + case Shader::IR::Type::F64x3: + return "%v3f"; + case Shader::IR::Type::F16x4: + case Shader::IR::Type::F32x4: + case Shader::IR::Type::F64x4: + return "%v4f"; + case Shader::IR::Type::Void: + case Shader::IR::Type::Opaque: + case Shader::IR::Type::ScalarReg: + case Shader::IR::Type::VectorReg: + case Shader::IR::Type::Attribute: + case Shader::IR::Type::SystemValue: + UNREACHABLE(); + } + }; + + if (infer_specifiers) { + UNREACHABLE(); + // need to fmt the format string with dynamic sized array of format spec strings + // could use param pack for this function, but less flexible + } + + DebugPrintInfo info{}; + info.string_idx.Assign(debug_print_strings.size()); + info.num_args.Assign(args.size()); + + Value arg_list = Inst(Opcode::Void); + for (Value arg : args) { + arg_list = VaArg(arg, arg_list); + } + + Inst(Opcode::DebugPrint, info, arg_list); +} + } // namespace Shader::IR diff --git a/src/shader_recompiler/ir/ir_emitter.h b/src/shader_recompiler/ir/ir_emitter.h index 958f2e88b..65716f0fe 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -4,7 +4,9 @@ #pragma once #include +#include #include +#include #include "shader_recompiler/ir/attribute.h" #include "shader_recompiler/ir/basic_block.h" @@ -44,6 +46,11 @@ public: void Discard(); void Discard(const U1& cond); + Value VaArg(Value arg, Value next); + + void DebugPrint(std::string_view format, boost::container::small_vector args, + bool infer_specifiers = false); + void Barrier(); void WorkgroupMemoryBarrier(); void DeviceMemoryBarrier(); @@ -312,6 +319,7 @@ public: private: IR::Block::iterator insertion_point; + boost::container::small_vector debug_print_strings; template T Inst(Opcode op, Args... args) { diff --git a/src/shader_recompiler/ir/microinstruction.cpp b/src/shader_recompiler/ir/microinstruction.cpp index 601c453d9..0e1571b6f 100644 --- a/src/shader_recompiler/ir/microinstruction.cpp +++ b/src/shader_recompiler/ir/microinstruction.cpp @@ -89,6 +89,7 @@ bool Inst::MayHaveSideEffects() const noexcept { case Opcode::ImageAtomicOr32: case Opcode::ImageAtomicXor32: case Opcode::ImageAtomicExchange32: + case Opcode::DebugPrint: return true; default: return false; diff --git a/src/shader_recompiler/ir/opcodes.inc b/src/shader_recompiler/ir/opcodes.inc index 41cc553f9..bef4943f5 100644 --- a/src/shader_recompiler/ir/opcodes.inc +++ b/src/shader_recompiler/ir/opcodes.inc @@ -14,6 +14,8 @@ OPCODE(Prologue, Void, OPCODE(Epilogue, Void, ) OPCODE(Discard, Void, ) OPCODE(DiscardCond, Void, U1, ) +OPCODE(DebugPrint, Void, Opaque, ) +OPCODE(VaArg, Opaque, Opaque, Opaque ) // Constant memory operations OPCODE(ReadConst, U32, U32x2, U32, )