From dd97b517f711c482c7d723e64197ed425d9ad2c6 Mon Sep 17 00:00:00 2001 From: psucien <168137814+psucien@users.noreply.github.com> Date: Thu, 4 Jul 2024 23:15:57 +0200 Subject: [PATCH] Recompiler: sampler patching (#236) * recompiler: restored bfs in image instruction producers search * recompiler: added pattern check for s# anisotropy modification * added check if s# comes from constant load (e.g. EUD) --- .../ir/passes/resource_tracking_pass.cpp | 76 ++++++++++++++++--- src/shader_recompiler/runtime_info.h | 2 + .../renderer_vulkan/vk_graphics_pipeline.cpp | 14 +++- 3 files changed, 79 insertions(+), 13 deletions(-) diff --git a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp index 4c26c996..4382bff3 100644 --- a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp +++ b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp @@ -182,6 +182,51 @@ private: } // Anonymous namespace +std::pair TryDisableAnisoLod0(const IR::Inst* inst) { + std::pair not_found{inst, false}; + + // Assuming S# is in UD s[12:15] and T# is in s[4:11] + // The next pattern: + // s_bfe_u32 s0, s7, $0x0008000c + // s_and_b32 s1, s12, $0xfffff1ff + // s_cmp_eq_u32 s0, 0 + // s_cselect_b32 s0, s1, s12 + // is used to disable anisotropy in the sampler if the sampled texture doesn't have mips + + if (inst->GetOpcode() != IR::Opcode::SelectU32) { + return not_found; + } + + // Select should be based on zero check + const auto* prod0 = inst->Arg(0).InstRecursive(); + if (prod0->GetOpcode() != IR::Opcode::IEqual || + !(prod0->Arg(1).IsImmediate() && prod0->Arg(1).U32() == 0u)) { + return not_found; + } + + // The bits range is for lods + const auto* prod0_arg0 = prod0->Arg(0).InstRecursive(); + if (prod0_arg0->GetOpcode() != IR::Opcode::BitFieldUExtract || + prod0_arg0->Arg(1).InstRecursive()->Arg(0).U32() != 0x0008000cu) { + return not_found; + } + + // Make sure mask is masking out anisotropy + const auto* prod1 = inst->Arg(1).InstRecursive(); + if (prod1->GetOpcode() != IR::Opcode::BitwiseAnd32 || prod1->Arg(1).U32() != 0xfffff1ff) { + return not_found; + } + + // We're working on the first dword of s# + const auto* prod2 = inst->Arg(2).InstRecursive(); + if (prod2->GetOpcode() != IR::Opcode::GetUserData && + prod2->GetOpcode() != IR::Opcode::ReadConst) { + return not_found; + } + + return {prod2, true}; +} + SharpLocation TrackSharp(const IR::Inst* inst) { while (inst->GetOpcode() == IR::Opcode::Phi) { inst = inst->Arg(0).InstRecursive(); @@ -329,15 +374,25 @@ IR::Value PatchCubeCoord(IR::IREmitter& ir, const IR::Value& s, const IR::Value& } void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descriptors& descriptors) { - IR::Inst* producer = inst.Arg(0).InstRecursive(); - while (producer->GetOpcode() == IR::Opcode::Phi) { - producer = producer->Arg(0).InstRecursive(); + std::deque insts{&inst}; + const auto& pred = [](auto opcode) -> bool { + return (opcode == IR::Opcode::CompositeConstructU32x2 || // IMAGE_SAMPLE (image+sampler) + opcode == IR::Opcode::ReadConst || // IMAGE_LOAD (image only) + opcode == IR::Opcode::GetUserData); + }; + + IR::Inst* producer{}; + while (!insts.empty() && (producer = insts.front(), !pred(producer->GetOpcode()))) { + for (auto arg_idx = 0u; arg_idx < producer->NumArgs(); ++arg_idx) { + const auto arg = producer->Arg(arg_idx); + if (arg.TryInstRecursive()) { + insts.push_back(arg.InstRecursive()); + } + } + insts.pop_front(); } - ASSERT(producer->GetOpcode() == - IR::Opcode::CompositeConstructU32x2 || // IMAGE_SAMPLE (image+sampler) - producer->GetOpcode() == IR::Opcode::ReadConst || // IMAGE_LOAD (image only) - producer->GetOpcode() == IR::Opcode::GetUserData); - const auto [tsharp_handle, ssharp_handle] = [&] -> std::pair { + ASSERT(pred(producer->GetOpcode())); + auto [tsharp_handle, ssharp_handle] = [&] -> std::pair { if (producer->GetOpcode() == IR::Opcode::CompositeConstructU32x2) { return std::make_pair(producer->Arg(0).InstRecursive(), producer->Arg(1).InstRecursive()); @@ -360,10 +415,13 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip // Read sampler sharp. This doesn't exist for IMAGE_LOAD/IMAGE_STORE instructions if (ssharp_handle) { - const auto ssharp = TrackSharp(ssharp_handle); + const auto& [ssharp_ud, disable_aniso] = TryDisableAnisoLod0(ssharp_handle); + const auto ssharp = TrackSharp(ssharp_ud); const u32 sampler_binding = descriptors.Add(SamplerResource{ .sgpr_base = ssharp.sgpr_base, .dword_offset = ssharp.dword_offset, + .associated_image = image_binding, + .disable_aniso = disable_aniso, }); image_binding |= (sampler_binding << 16); } diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index 29841315..993207eb 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -96,6 +96,8 @@ using ImageResourceList = boost::container::static_vector; struct SamplerResource { u32 sgpr_base; u32 dword_offset; + u32 associated_image : 4; + u32 disable_aniso : 1; }; using SamplerResourceList = boost::container::static_vector; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 8b9dcc0f..7b7eda44 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -348,9 +348,10 @@ void GraphicsPipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& } } + boost::container::static_vector tsharps; for (const auto& image_desc : stage.images) { - const auto tsharp = - stage.ReadUd(image_desc.sgpr_base, image_desc.dword_offset); + const auto& tsharp = tsharps.emplace_back( + stage.ReadUd(image_desc.sgpr_base, image_desc.dword_offset)); const auto& image_view = texture_cache.FindImageView(tsharp, image_desc.is_storage); const auto& image = texture_cache.GetImage(image_view.image_id); image_infos.emplace_back(VK_NULL_HANDLE, *image_view.image_view, image.layout); @@ -369,8 +370,13 @@ void GraphicsPipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& } } for (const auto& sampler : stage.samplers) { - const auto ssharp = - stage.ReadUd(sampler.sgpr_base, sampler.dword_offset); + auto ssharp = stage.ReadUd(sampler.sgpr_base, sampler.dword_offset); + if (sampler.disable_aniso) { + const auto& tsharp = tsharps[sampler.associated_image]; + if (tsharp.base_level == 0 && tsharp.last_level == 0) { + ssharp.max_aniso.Assign(AmdGpu::AnisoRatio::One); + } + } const auto vk_sampler = texture_cache.GetSampler(ssharp); image_infos.emplace_back(vk_sampler, VK_NULL_HANDLE, vk::ImageLayout::eGeneral); set_writes.push_back({