diff --git a/src/shader_recompiler/info.h b/src/shader_recompiler/info.h index e727c8a08..08fe06e0c 100644 --- a/src/shader_recompiler/info.h +++ b/src/shader_recompiler/info.h @@ -87,6 +87,14 @@ struct SamplerResource { }; using SamplerResourceList = boost::container::small_vector; +struct FMaskResource { + u32 sgpr_base; + u32 dword_offset; + + constexpr AmdGpu::Image GetSharp(const Info& info) const noexcept; +}; +using FMaskResourceList = boost::container::small_vector; + struct PushData { static constexpr u32 BufOffsetIndex = 2; static constexpr u32 UdRegsIndex = 4; @@ -179,6 +187,7 @@ struct Info { TextureBufferResourceList texture_buffers; ImageResourceList images; SamplerResourceList samplers; + FMaskResourceList fmasks; std::span user_data; Stage stage; @@ -263,6 +272,10 @@ constexpr AmdGpu::Sampler SamplerResource::GetSharp(const Info& info) const noex return inline_sampler ? inline_sampler : info.ReadUd(sgpr_base, dword_offset); } +constexpr AmdGpu::Image FMaskResource::GetSharp(const Info& info) const noexcept { + return info.ReadUd(sgpr_base, dword_offset); +} + } // namespace Shader template <> diff --git a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp index cd9f9095e..c495b3c36 100644 --- a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp +++ b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp @@ -147,7 +147,7 @@ public: explicit Descriptors(Info& info_) : info{info_}, buffer_resources{info_.buffers}, texture_buffer_resources{info_.texture_buffers}, image_resources{info_.images}, - sampler_resources{info_.samplers} {} + sampler_resources{info_.samplers}, fmask_resources(info_.fmasks) {} u32 Add(const BufferResource& desc) { const u32 index{Add(buffer_resources, desc, [&desc](const auto& existing) { @@ -193,6 +193,14 @@ public: return index; } + u32 Add(const FMaskResource& desc) { + u32 index = Add(fmask_resources, desc, [&desc](const auto& existing) { + return desc.sgpr_base == existing.sgpr_base && + desc.dword_offset == existing.dword_offset; + }); + return index; + } + private: template static u32 Add(Descriptors& descriptors, const Descriptor& desc, Func&& pred) { @@ -209,6 +217,7 @@ private: TextureBufferResourceList& texture_buffer_resources; ImageResourceList& image_resources; SamplerResourceList& sampler_resources; + FMaskResourceList& fmask_resources; }; } // Anonymous namespace @@ -673,6 +682,19 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip case IR::Opcode::ImageQueryLod: inst.ReplaceUsesWith(ir.Imm32(1)); return; + case IR::Opcode::ImageQueryDimensions: { + IR::Value dims = ir.CompositeConstruct(ir.Imm32(static_cast(image.width)), // x + ir.Imm32(static_cast(image.width)), // y + ir.Imm32(1), ir.Imm32(1)); // depth, mip + inst.ReplaceUsesWith(dims); + + // Track FMask resource to do specialization. + descriptors.Add(FMaskResource{ + .sgpr_base = tsharp.sgpr_base, + .dword_offset = tsharp.dword_offset, + }); + return; + } default: UNREACHABLE_MSG("Can't patch fmask instruction {}", inst.GetOpcode()); } diff --git a/src/shader_recompiler/specialization.h b/src/shader_recompiler/specialization.h index 0a3a696bc..8bfc15641 100644 --- a/src/shader_recompiler/specialization.h +++ b/src/shader_recompiler/specialization.h @@ -31,6 +31,13 @@ struct ImageSpecialization { auto operator<=>(const ImageSpecialization&) const = default; }; +struct FMaskSpecialization { + u32 width; + u32 height; + + auto operator<=>(const FMaskSpecialization&) const = default; +}; + /** * Alongside runtime information, this structure also checks bound resources * for compatibility. Can be used as a key for storing shader permutations. @@ -46,6 +53,7 @@ struct StageSpecialization { boost::container::small_vector buffers; boost::container::small_vector tex_buffers; boost::container::small_vector images; + boost::container::small_vector fmasks; Backend::Bindings start{}; explicit StageSpecialization(const Shader::Info& info_, RuntimeInfo runtime_info_, @@ -67,6 +75,11 @@ struct StageSpecialization { : sharp.GetType(); spec.is_integer = AmdGpu::IsInteger(sharp.GetNumberFmt()); }); + ForEachSharp(binding, fmasks, info->fmasks, + [](auto& spec, const auto& desc, AmdGpu::Image sharp) { + spec.width = sharp.width; + spec.height = sharp.height; + }); } void ForEachSharp(u32& binding, auto& spec_list, auto& desc_list, auto&& func) { @@ -105,6 +118,11 @@ struct StageSpecialization { return false; } } + for (u32 i = 0; i < fmasks.size(); i++) { + if (other.bitset[binding++] && fmasks[i] != other.fmasks[i]) { + return false; + } + } return true; } };