From 0c86c54d48533e3505e56e639059d28331fe4bc3 Mon Sep 17 00:00:00 2001 From: Fire Cube Date: Mon, 21 Apr 2025 23:25:15 +0200 Subject: [PATCH 1/6] Implement SET_PC_B64 instruction (#2823) * basic impl * minor improvements * clang * more clang * improvements requested by squidbus --- .../frontend/control_flow_graph.cpp | 63 ++++++++++++++++++- .../frontend/instruction.cpp | 2 +- .../frontend/translate/scalar_flow.cpp | 1 + 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/shader_recompiler/frontend/control_flow_graph.cpp b/src/shader_recompiler/frontend/control_flow_graph.cpp index cf1882b8c..b53db9e94 100644 --- a/src/shader_recompiler/frontend/control_flow_graph.cpp +++ b/src/shader_recompiler/frontend/control_flow_graph.cpp @@ -4,6 +4,7 @@ #include #include #include "common/assert.h" +#include "common/logging/log.h" #include "shader_recompiler/frontend/control_flow_graph.h" namespace Shader::Gcn { @@ -67,6 +68,39 @@ static bool IgnoresExecMask(const GcnInst& inst) { return false; } +static std::optional ResolveSetPcTarget(std::span list, u32 setpc_index, + std::span pc_map) { + if (setpc_index < 3) { + return std::nullopt; + } + + const auto& getpc = list[setpc_index - 3]; + const auto& arith = list[setpc_index - 2]; + const auto& setpc = list[setpc_index]; + + if (getpc.opcode != Opcode::S_GETPC_B64 || + !(arith.opcode == Opcode::S_ADD_U32 || arith.opcode == Opcode::S_SUB_U32) || + setpc.opcode != Opcode::S_SETPC_B64) + return std::nullopt; + + if (getpc.dst[0].code != setpc.src[0].code || arith.dst[0].code != setpc.src[0].code) + return std::nullopt; + + if (arith.src_count < 2 || arith.src[1].field != OperandField::LiteralConst) + return std::nullopt; + + const u32 imm = arith.src[1].code; + + const s32 signed_offset = + (arith.opcode == Opcode::S_ADD_U32) ? static_cast(imm) : -static_cast(imm); + + const u32 base_pc = pc_map[setpc_index - 3] + getpc.length; + + const u32 result_pc = static_cast(static_cast(base_pc) + signed_offset); + LOG_DEBUG(Render_Recompiler, "SetPC target: {} + {} = {}", base_pc, signed_offset, result_pc); + return result_pc & ~0x3u; +} + static constexpr size_t LabelReserveSize = 32; CFG::CFG(Common::ObjectPool& block_pool_, std::span inst_list_) @@ -89,9 +123,20 @@ void CFG::EmitLabels() { index_to_pc[i] = pc; const GcnInst inst = inst_list[i]; if (inst.IsUnconditionalBranch()) { - const u32 target = inst.BranchTarget(pc); + u32 target = inst.BranchTarget(pc); + if (inst.opcode == Opcode::S_SETPC_B64) { + if (auto t = ResolveSetPcTarget(inst_list, i, index_to_pc)) { + target = *t; + } else { + ASSERT_MSG( + false, + "S_SETPC_B64 without a resolvable offset at PC {:#x} (Index {}): Involved " + "instructions not recognized or invalid pattern", + pc, i); + } + } AddLabel(target); - // Emit this label so that the block ends with s_branch instruction + // Emit this label so that the block ends with the branching instruction AddLabel(pc + inst.length); } else if (inst.IsConditionalBranch()) { const u32 true_label = inst.BranchTarget(pc); @@ -102,6 +147,7 @@ void CFG::EmitLabels() { const u32 next_label = pc + inst.length; AddLabel(next_label); } + pc += inst.length; } index_to_pc[inst_list.size()] = pc; @@ -280,7 +326,18 @@ void CFG::LinkBlocks() { // Find the branch targets from the instruction and link the blocks. // Note: Block end address is one instruction after end_inst. const u32 branch_pc = block.end - end_inst.length; - const u32 target_pc = end_inst.BranchTarget(branch_pc); + u32 target_pc = 0; + if (end_inst.opcode == Opcode::S_SETPC_B64) { + auto tgt = ResolveSetPcTarget(inst_list, block.end_index, index_to_pc); + ASSERT_MSG(tgt, + "S_SETPC_B64 without a resolvable offset at PC {:#x} (Index {}): Involved " + "instructions not recognized or invalid pattern", + branch_pc, block.end_index); + target_pc = *tgt; + } else { + target_pc = end_inst.BranchTarget(branch_pc); + } + if (end_inst.IsUnconditionalBranch()) { auto* target_block = get_block(target_pc); ++target_block->num_predecessors; diff --git a/src/shader_recompiler/frontend/instruction.cpp b/src/shader_recompiler/frontend/instruction.cpp index a0c132053..246c2b85a 100644 --- a/src/shader_recompiler/frontend/instruction.cpp +++ b/src/shader_recompiler/frontend/instruction.cpp @@ -18,7 +18,7 @@ bool GcnInst::IsTerminateInstruction() const { } bool GcnInst::IsUnconditionalBranch() const { - return opcode == Opcode::S_BRANCH; + return opcode == Opcode::S_BRANCH || opcode == Opcode::S_SETPC_B64; } bool GcnInst::IsFork() const { diff --git a/src/shader_recompiler/frontend/translate/scalar_flow.cpp b/src/shader_recompiler/frontend/translate/scalar_flow.cpp index 0e02b77a2..cd1cf51f0 100644 --- a/src/shader_recompiler/frontend/translate/scalar_flow.cpp +++ b/src/shader_recompiler/frontend/translate/scalar_flow.cpp @@ -18,6 +18,7 @@ void Translator::EmitFlowControl(u32 pc, const GcnInst& inst) { return; case Opcode::S_GETPC_B64: return S_GETPC_B64(pc, inst); + case Opcode::S_SETPC_B64: case Opcode::S_WAITCNT: case Opcode::S_NOP: case Opcode::S_ENDPGM: From cda421434bb8d040f47cfc73bafa731afba39aee Mon Sep 17 00:00:00 2001 From: Dmugetsu <168934208+diegolix29@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:49:29 -0600 Subject: [PATCH 2/6] Adding missmatch info to Texture cache assert (#2828) --- src/video_core/texture_cache/texture_cache.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index d41ee57cc..545152ec8 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -326,9 +326,13 @@ ImageId TextureCache::FindImage(BaseDesc& desc, FindFlags flags) { info.pixel_format != cache_image.info.pixel_format) { continue; } - ASSERT((cache_image.info.type == info.type || info.size == Extent3D{1, 1, 1} || - True(flags & FindFlags::RelaxFmt))); - image_id = cache_id; + if (!(cache_image.info.type == info.type || info.size == Extent3D{1, 1, 1} || + static_cast(flags & FindFlags::RelaxFmt))) { + ASSERT_MSG(false, "Image cache type mismatch: cache={}, info={}", + int(cache_image.info.type), int(info.type)); + image_id = cache_id; + break; + } } if (True(flags & FindFlags::NoCreate) && !image_id) { From 5b0205bc59f5057203a860f991fef3cb54dc8ed0 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 22 Apr 2025 14:00:08 -0700 Subject: [PATCH 3/6] fix: Texture cache image type assert. --- src/video_core/texture_cache/texture_cache.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index 545152ec8..7023dda55 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -326,13 +326,11 @@ ImageId TextureCache::FindImage(BaseDesc& desc, FindFlags flags) { info.pixel_format != cache_image.info.pixel_format) { continue; } - if (!(cache_image.info.type == info.type || info.size == Extent3D{1, 1, 1} || - static_cast(flags & FindFlags::RelaxFmt))) { - ASSERT_MSG(false, "Image cache type mismatch: cache={}, info={}", - int(cache_image.info.type), int(info.type)); - image_id = cache_id; - break; - } + ASSERT_MSG((cache_image.info.type == info.type || info.size == Extent3D{1, 1, 1} || + True(flags & FindFlags::RelaxFmt)), + "Image cache type mismatch: cache={}, info={}", + vk::to_string(cache_image.info.type), vk::to_string(info.type)); + image_id = cache_id; } if (True(flags & FindFlags::NoCreate) && !image_id) { From 0297aee3f4871704da9eef42f81ecf5ead8e7a3b Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 22 Apr 2025 15:03:43 -0700 Subject: [PATCH 4/6] texture_cache: Relax mismatched image type from assert to cache miss. (#2830) --- src/video_core/texture_cache/texture_cache.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index 7023dda55..047bb3dfe 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -319,17 +319,14 @@ ImageId TextureCache::FindImage(BaseDesc& desc, FindFlags flags) { continue; } if (False(flags & FindFlags::RelaxFmt) && - !IsVulkanFormatCompatible(info.pixel_format, cache_image.info.pixel_format)) { + (!IsVulkanFormatCompatible(info.pixel_format, cache_image.info.pixel_format) || + (cache_image.info.type != info.type && info.size != Extent3D{1, 1, 1}))) { continue; } if (True(flags & FindFlags::ExactFmt) && info.pixel_format != cache_image.info.pixel_format) { continue; } - ASSERT_MSG((cache_image.info.type == info.type || info.size == Extent3D{1, 1, 1} || - True(flags & FindFlags::RelaxFmt)), - "Image cache type mismatch: cache={}, info={}", - vk::to_string(cache_image.info.type), vk::to_string(info.type)); image_id = cache_id; } From 96bee58d0f048c44bbbf76a2fa1434c469df753e Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 22 Apr 2025 21:41:20 -0700 Subject: [PATCH 5/6] ci: Fix macOS SDL build. (#2831) --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 86ca81c38..9393380e2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -206,11 +206,11 @@ jobs: mkdir upload mv ${{github.workspace}}/build/shadps4 upload cp ${{github.workspace}}/build/externals/MoltenVK/libMoltenVK.dylib upload - tar cf shadps4-macos-sdl.tar.gz -C upload . + install_name_tool -add_rpath "@executable_path" upload/shadps4 - uses: actions/upload-artifact@v4 with: name: shadps4-macos-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }} - path: shadps4-macos-sdl.tar.gz + path: upload/ macos-qt: runs-on: macos-15 From b1ebb2fec56c25dc304d74618e2aca04671eddb1 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 22 Apr 2025 22:05:32 -0700 Subject: [PATCH 6/6] fix: Only change macOS working directory for app bundle. --- src/common/path_util.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/common/path_util.cpp b/src/common/path_util.cpp index 702d0fabc..2ff1ddaf7 100644 --- a/src/common/path_util.cpp +++ b/src/common/path_util.cpp @@ -60,7 +60,7 @@ static CFURLRef UntranslocateBundlePath(const CFURLRef bundle_path) { return nullptr; } -static std::filesystem::path GetBundleParentDirectory() { +static std::optional GetBundleParentDirectory() { if (CFBundleRef bundle_ref = CFBundleGetMainBundle()) { if (CFURLRef bundle_url_ref = CFBundleCopyBundleURL(bundle_ref)) { SCOPE_EXIT { @@ -83,14 +83,16 @@ static std::filesystem::path GetBundleParentDirectory() { } } } - return std::filesystem::current_path(); + return std::nullopt; } #endif static auto UserPaths = [] { #ifdef __APPLE__ // Set the current path to the directory containing the app bundle. - std::filesystem::current_path(GetBundleParentDirectory()); + if (const auto bundle_dir = GetBundleParentDirectory()) { + std::filesystem::current_path(*bundle_dir); + } #endif // Try the portable user directory first.