diff --git a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp index 59381436e..679b10449 100644 --- a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp +++ b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp @@ -656,6 +656,32 @@ void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descrip } ASSERT(image.GetType() != AmdGpu::ImageType::Invalid); const bool is_storage = IsImageStorageInstruction(inst); + + // Patch image instruction if image is fmask. + if (image.IsFmask()) { + // Ignore fmask writes. TODO: handle dimension queries. + if (is_storage && inst.GetOpcode() == IR::Opcode::ImageQueryDimensions) { + inst.Invalidate(); + return; + } + + IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; + switch (inst.GetOpcode()) { + case IR::Opcode::ImageFetch: + case IR::Opcode::ImageSampleRaw: { + IR::F32 fmaskx = ir.BitCast(ir.Imm32(0x76543210)); + IR::F32 fmasky = ir.BitCast(ir.Imm32(0xfedcba98)); + inst.ReplaceUsesWith(ir.CompositeConstruct(fmaskx, fmasky)); + return; + } + case IR::Opcode::ImageQueryLod: + inst.ReplaceUsesWith(ir.Imm32(1)); + return; + default: + UNREACHABLE_MSG("Can't patch fmask instruction {}", inst.GetOpcode()); + } + } + const auto type = image.IsPartialCubemap() ? AmdGpu::ImageType::Color2DArray : image.GetType(); u32 image_binding = descriptors.Add(ImageResource{ .sgpr_base = tsharp.sgpr_base, diff --git a/src/video_core/amdgpu/resource.h b/src/video_core/amdgpu/resource.h index 83be0b0a4..cbbd08fa4 100644 --- a/src/video_core/amdgpu/resource.h +++ b/src/video_core/amdgpu/resource.h @@ -295,6 +295,10 @@ struct Image { return GetTilingMode() != TilingMode::Display_Linear; } + bool IsFmask() const noexcept { + return GetDataFmt() >= DataFormat::FormatFmask8_1 && GetDataFmt() <= DataFormat::FormatFmask64_8; + } + bool IsPartialCubemap() const { const auto viewed_slice = last_array - base_array + 1; return GetType() == ImageType::Cube && viewed_slice < 6;