From 0966938dc8287e92621c2f2ccd9ed5bd9d27c7fa Mon Sep 17 00:00:00 2001 From: nmzik Date: Thu, 20 Aug 2026 21:57:10 +0200 Subject: [PATCH] shader: honor RDNA2 128-bit image descriptors --- .../renderer/pipeline/descriptors.cpp | 61 ++++++++++++------- .../host_gpu/renderer/pipeline/descriptors.h | 6 +- .../host_gpu/renderer/renderCompute.cpp | 2 +- .../recompiler/frontend/decode/ImageOps.cpp | 2 + .../frontend/decode/ShaderDecoder.cpp | 3 + .../frontend/decode/ShaderDecoder.h | 1 + .../recompiler/frontend/translate/Memory.cpp | 10 +-- .../shader/recompiler/ir/ShaderIR.cpp | 1 + src/graphics/shader/recompiler/ir/ShaderIR.h | 2 + .../shader/recompiler/ir/ShaderIRLog.cpp | 4 +- .../ir/passes/ResourceMaterialization.cpp | 11 +++- .../recompiler/ir/passes/ResourceTracking.cpp | 3 +- tests/ShaderRecompilerComputeTests.cpp | 53 +++++++++++++++- 13 files changed, 122 insertions(+), 37 deletions(-) diff --git a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp index d8c2f2650..fdcd3d51e 100644 --- a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp @@ -233,7 +233,8 @@ bool IsSupportedSampledVideoOutView(const ShaderRecompiler::IR::ImageResource& r descriptor.BaseArray5() == 0; } -bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, const Image& image) { +bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, const Image& image, + bool r128) { const auto width = static_cast(descriptor.Width5()) + 1u; const auto height = static_cast(descriptor.Height5()) + 1u; const auto type = descriptor.Type(); @@ -262,10 +263,11 @@ bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, c const bool levels_ok = multisampled ? descriptor.BaseLevel() == 0 && descriptor.LastLevel() >= 1 && - descriptor.LastLevel() <= 3 && descriptor.MaxMip() == descriptor.LastLevel() && + descriptor.LastLevel() <= 3 && + (r128 || descriptor.MaxMip() == descriptor.LastLevel()) && image.info.resources.levels == 1 && image.info.samples == samples : descriptor.BaseLevel() == 0 && descriptor.LastLevel() == 0 && - descriptor.MaxMip() == 0 && image.info.samples == 1; + (r128 || descriptor.MaxMip() == 0) && image.info.samples == 1; return image.info.IsDepth() && width == image.info.extent.width && height == image.info.extent.height && (supported_2d || supported_array || supported_cube || supported_msaa_2d || @@ -275,7 +277,8 @@ bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, c (!descriptor.MsaaDepth() || multisampled) && pitch >= width && pitch == image.info.pitch; } -bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, const Image& image) { +bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, const Image& image, + bool r128) { constexpr uint32_t field1_reserved_mask = 0x200fff00u; constexpr uint32_t field2_reserved_mask = 0xf0003000u; const uint32_t field3_expected = descriptor.DstSelXYZW() | @@ -286,12 +289,16 @@ bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, co const uint32_t field4_expected = descriptor.Depth() | (descriptor.BaseArray5() << 16u); const uint32_t field5_expected = (static_cast(descriptor.PerfMod5()) << 20u) | (static_cast(descriptor.MaxMip()) << 4u); - const bool common = (descriptor.fields[1] & field1_reserved_mask) == 0 && - (descriptor.fields[2] & field2_reserved_mask) == 0 && - descriptor.fields[3] == field3_expected && - descriptor.fields[4] == field4_expected && - descriptor.fields[5] == field5_expected; - if (!common || (descriptor.fields[6] == 0 && descriptor.fields[7] != 0)) { + const bool common = (descriptor.fields[1] & field1_reserved_mask) == 0 && + (descriptor.fields[2] & field2_reserved_mask) == 0 && + descriptor.fields[3] == field3_expected; + if (r128) { + return common && descriptor.fields[4] == 0 && descriptor.fields[5] == 0 && + descriptor.fields[6] == 0 && descriptor.fields[7] == 0; + } + const bool full = common && descriptor.fields[4] == field4_expected && + descriptor.fields[5] == field5_expected; + if (!full || (descriptor.fields[6] == 0 && descriptor.fields[7] != 0)) { return false; } if (descriptor.fields[6] == 0) { @@ -312,9 +319,9 @@ static void ValidateDepthTargetBinding(const ShaderRecompiler::IR::ImageResource vk::Format view_format, uint64_t size) { const bool resource_ok = IsSupportedSampledDepthResource(resource); const bool descriptor_ok = - image != nullptr && IsSupportedDepthTargetDescriptor(descriptor, *image); + image != nullptr && IsSupportedDepthTargetDescriptor(descriptor, *image, resource.r128); const bool encoding_ok = - image != nullptr && IsSupportedDepthTextureEncoding(descriptor, *image); + image != nullptr && IsSupportedDepthTextureEncoding(descriptor, *image, resource.r128); const bool format_ok = image != nullptr && IsSupportedSampledDepthFormat(image->info.pixel_format, view_format); if (resource_ok && descriptor_ok && encoding_ok && format_ok && size != 0) { @@ -404,17 +411,20 @@ static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::Imag const bool supported_swizzle = IsValidImageSwizzle(swizzle) && (swizzle == DstSel(4, 5, 6, 7) || !resource.read || resource.atomic); + const auto max_mip = resource.r128 ? descriptor.LastLevel() : descriptor.MaxMip(); const auto view_last_level = resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::DynamicStorage ? descriptor.LastLevel() - : std::min(descriptor.LastLevel(), descriptor.MaxMip()); + : std::min(descriptor.LastLevel(), max_mip); return (is_1d || is_1d_array || is_2d || is_2d_array || is_3d) && supported_tile && - descriptor.BaseLevel() <= view_last_level && view_last_level <= descriptor.MaxMip() && + descriptor.BaseLevel() <= view_last_level && view_last_level <= max_mip && descriptor.MinLod() == 0 && supported_swizzle && descriptor.BCSwizzle() == 0 && !descriptor.MsaaDepth(); } -static bool IsSupportedStorageTextureEncoding(const ShaderTextureResource& descriptor) { +static bool IsSupportedStorageTextureEncoding( + const ShaderRecompiler::IR::ImageResource& resource, + const ShaderTextureResource& descriptor) { constexpr uint32_t field1_reserved_mask = 0x200fff00u; constexpr uint32_t field2_reserved_mask = 0xf0003000u; constexpr uint32_t field5_expected = 0x00700000u; @@ -426,9 +436,14 @@ static bool IsSupportedStorageTextureEncoding(const ShaderTextureResource& descr (static_cast(descriptor.Type()) << 28u); const uint32_t expected_field4 = descriptor.Depth() | (static_cast(descriptor.BaseArray5()) << 16u); - return (descriptor.fields[1] & field1_reserved_mask) == 0 && - (descriptor.fields[2] & field2_reserved_mask) == 0 && - descriptor.fields[3] == expected_field3 && descriptor.fields[4] == expected_field4 && + const bool common = (descriptor.fields[1] & field1_reserved_mask) == 0 && + (descriptor.fields[2] & field2_reserved_mask) == 0 && + descriptor.fields[3] == expected_field3; + if (resource.r128) { + return common && descriptor.fields[4] == 0 && descriptor.fields[5] == 0 && + descriptor.fields[6] == 0 && descriptor.fields[7] == 0; + } + return common && descriptor.fields[4] == expected_field4 && (descriptor.fields[5] & ~field5_max_mip_mask) == field5_expected; } @@ -437,7 +452,7 @@ void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource, const auto format = descriptor.Format(); const bool resource_ok = IsSupportedStorageImageResource(resource); const bool descriptor_ok = IsSupportedStorageTextureDescriptor(resource, descriptor); - const bool encoding_ok = IsSupportedStorageTextureEncoding(descriptor); + const bool encoding_ok = IsSupportedStorageTextureEncoding(resource, descriptor); const bool uint_resource = resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint; const bool raw_sint_storage = format == Prospero::BufferFormat::k32SInt && uint_resource && @@ -631,19 +646,19 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso const auto last_level = descriptor.LastLevel(); const auto type = TextureType(descriptor); const bool multisampled = IsMultisampledTexture(type); - const auto levels = multisampled ? 1u : static_cast(descriptor.MaxMip()) + 1u; + const auto max_mip = resource.r128 ? last_level : descriptor.MaxMip(); + const auto levels = multisampled ? 1u : static_cast(max_mip) + 1u; const bool dynamic_storage = storage && resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::DynamicStorage; const auto view_last_level = - !multisampled && !dynamic_storage ? std::min(last_level, descriptor.MaxMip()) : last_level; + !multisampled && !dynamic_storage ? std::min(last_level, max_mip) : last_level; const auto tile = descriptor.TileMode(); const bool depth_tile = tile == Prospero::TileMode::kDepth; const bool msaa_tile = depth_tile || tile == Prospero::TileMode::kRenderTarget; const bool msaa_array = type == Prospero::ImageType::kColor2DMsaaArray; if ((!multisampled && (base_level > view_last_level || view_last_level >= levels)) || (multisampled && - (base_level != 0 || last_level == 0 || last_level > 3 || - descriptor.MaxMip() != last_level || !msaa_tile || + (base_level != 0 || last_level == 0 || last_level > 3 || max_mip != last_level || !msaa_tile || (descriptor.MsaaDepth() && !depth_tile) || (!msaa_array && (descriptor.Depth() != 0 || descriptor.BaseArray5() != 0))))) { EXIT("unsupported texture mip view: base=%u last=%u levels=%u max=%u type=%u tile=%u " diff --git a/src/graphics/host_gpu/renderer/pipeline/descriptors.h b/src/graphics/host_gpu/renderer/pipeline/descriptors.h index 031434ea5..0fe9353a4 100644 --- a/src/graphics/host_gpu/renderer/pipeline/descriptors.h +++ b/src/graphics/host_gpu/renderer/pipeline/descriptors.h @@ -34,9 +34,11 @@ ResolveTargetTextureView(const ShaderRecompiler::IR::ImageResource& resource, Prospero::ImageType type, uint32_t base_layer, uint32_t image_layers); [[nodiscard]] bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, - const Image& image); + const Image& image, + bool r128 = false); [[nodiscard]] bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, - const Image& image); + const Image& image, + bool r128 = false); [[nodiscard]] bool IsSupportedSampledVideoOutView(const ShaderRecompiler::IR::ImageResource& resource, const ShaderTextureResource& descriptor, const Image& image); diff --git a/src/graphics/host_gpu/renderer/renderCompute.cpp b/src/graphics/host_gpu/renderer/renderCompute.cpp index 4cc6baa71..37731d84e 100644 --- a/src/graphics/host_gpu/renderer/renderCompute.cpp +++ b/src/graphics/host_gpu/renderer/renderCompute.cpp @@ -279,7 +279,7 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, RenderCommandBuffer& buf r.Type() == Prospero::ImageType::kColor2DMsaa || r.Type() == Prospero::ImageType::kColor2DMsaaArray ? 1u - : static_cast(r.MaxMip()) + 1u, + : static_cast(image.r128 ? r.LastLevel() : r.MaxMip()) + 1u, static_cast(r.TileMode())); } for (uint32_t i = 0; i < program.info.samplers.size(); i++) { diff --git a/src/graphics/shader/recompiler/frontend/decode/ImageOps.cpp b/src/graphics/shader/recompiler/frontend/decode/ImageOps.cpp index 894149728..d81a998d5 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ImageOps.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/ImageOps.cpp @@ -309,6 +309,7 @@ void DecodeMimg(uint32_t pc, std::span code, uint32_t word_index const uint32_t vaddr = word1 & 0xffu; const uint32_t srsrc = (word1 >> 16u) & 0x1fu; const uint32_t ssamp = (word1 >> 21u) & 0x1fu; + const bool r128 = ((word0 >> 15u) & 0x1u) != 0u; const bool a16 = ((word1 >> 30u) & 0x1u) != 0u; const bool d16 = ((word1 >> 31u) & 0x1u) != 0u; const auto* sample = LookupSample(opcode); @@ -332,6 +333,7 @@ void DecodeMimg(uint32_t pc, std::span code, uint32_t word_index inst.image_sample_flags |= ImageSampleFlagA16; } inst.image_dimension = dimension; + inst.image_r128 = r128; inst.image_nsa_dwords = nsa_dwords; for (uint32_t i = 0; i < nsa_dwords * 4u; i++) { inst.image_nsa_addr[i] = (code[word_index + 2u + i / 4u] >> ((i % 4u) * 8u)) & 0xffu; diff --git a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp index 60c37e0ce..771d6adc2 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp +++ b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.cpp @@ -157,6 +157,9 @@ std::string FormatMimg(const Instruction& inst) { if (inst.data_bits == 16u) { text += " d16=1"; } + if (inst.image_r128) { + text += " r128=1"; + } switch (inst.opcode) { case Opcode::IMAGE_SAMPLE: case Opcode::IMAGE_GATHER4_LZ: diff --git a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h index 65ed78ef2..a63607083 100644 --- a/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h +++ b/src/graphics/shader/recompiler/frontend/decode/ShaderDecoder.h @@ -667,6 +667,7 @@ struct Instruction { bool slc = false; bool idxen = false; bool offen = false; + bool image_r128 = false; int32_t branch_offset = 0; uint32_t branch_target = 0; struct { diff --git a/src/graphics/shader/recompiler/frontend/translate/Memory.cpp b/src/graphics/shader/recompiler/frontend/translate/Memory.cpp index cdbaf4b72..042f643c2 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Memory.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Memory.cpp @@ -52,11 +52,13 @@ IR::Value Translator::GetScalarAddressResource(uint32_t base) { } IR::Value Translator::GetImageResource(const IR::MemoryInfo& memory) { + const auto dword = [&](uint32_t index) { + return memory.image_r128 && index >= 4u ? IR::U32(IR::Value(0u)) + : GetResourceDword(memory.resource, index); + }; return ir.Emit(IR::ValueOpcode::GetImageResource, - {GetResourceDword(memory.resource, 0), GetResourceDword(memory.resource, 1), - GetResourceDword(memory.resource, 2), GetResourceDword(memory.resource, 3), - GetResourceDword(memory.resource, 4), GetResourceDword(memory.resource, 5), - GetResourceDword(memory.resource, 6), GetResourceDword(memory.resource, 7)}); + {dword(0), dword(1), dword(2), dword(3), dword(4), dword(5), dword(6), + dword(7)}); } IR::Value Translator::GetSamplerResource(const IR::MemoryInfo& memory) { diff --git a/src/graphics/shader/recompiler/ir/ShaderIR.cpp b/src/graphics/shader/recompiler/ir/ShaderIR.cpp index 6c3c20cc2..50dcfdbaf 100644 --- a/src/graphics/shader/recompiler/ir/ShaderIR.cpp +++ b/src/graphics/shader/recompiler/ir/ShaderIR.cpp @@ -232,6 +232,7 @@ MemoryInfo MemoryInfoFromDecoded(const Decoder::Instruction& decoded, ResourceKi mem.formatted = decoded.formatted; mem.image_has_mip = decoded.opcode == Decoder::Opcode::IMAGE_LOAD_MIP || decoded.opcode == Decoder::Opcode::IMAGE_STORE_MIP; + mem.image_r128 = decoded.image_r128; mem.glc = decoded.glc; mem.slc = decoded.slc; mem.idxen = decoded.idxen; diff --git a/src/graphics/shader/recompiler/ir/ShaderIR.h b/src/graphics/shader/recompiler/ir/ShaderIR.h index e70345022..232dcbc68 100644 --- a/src/graphics/shader/recompiler/ir/ShaderIR.h +++ b/src/graphics/shader/recompiler/ir/ShaderIR.h @@ -119,6 +119,7 @@ struct MemoryInfo { bool formatted = false; bool image_has_mip = false; bool image_cube = false; + bool image_r128 = false; bool glc = false; bool slc = false; bool idxen = false; @@ -226,6 +227,7 @@ struct ImageResource { bool atomic = false; bool depth_compare = false; bool cube = false; + bool r128 = false; uint32_t indirect_root = NoIndirectImage; uint32_t indirect_mapping_offset = 0; uint32_t indirect_mapping_capacity = 0; diff --git a/src/graphics/shader/recompiler/ir/ShaderIRLog.cpp b/src/graphics/shader/recompiler/ir/ShaderIRLog.cpp index 6e29636aa..8dfb2b74b 100644 --- a/src/graphics/shader/recompiler/ir/ShaderIRLog.cpp +++ b/src/graphics/shader/recompiler/ir/ShaderIRLog.cpp @@ -98,14 +98,14 @@ std::string MemoryInfoToString(const MemoryInfo& mem) { " ; {} resource={} sampler={} offset={} offset2={} dmask=0x{:x} data_dwords={} " "data_bits={} component={}/{} dfmt={} nfmt={} signed={} typed={} formatted={} segment={} " "glc={} slc={} idxen={} offen={} image_flags=0x{:x} image_dim={} image_addr={} " - "image_mip={}", + "image_mip={} image_r128={}", ResourceKindToString(mem.kind).c_str(), mem.resource, mem.sampler, mem.offset, mem.secondary_offset, mem.dmask, mem.data_dwords, mem.data_bits, mem.component_index, mem.component_count, mem.data_format, mem.number_format, mem.data_signed ? 1u : 0u, mem.typed ? 1u : 0u, mem.formatted ? 1u : 0u, mem.memory_segment, mem.glc ? 1u : 0u, mem.slc ? 1u : 0u, mem.idxen ? 1u : 0u, mem.offen ? 1u : 0u, mem.image_sample_flags, Decoder::ImageDimensionToString(mem.image_dimension), mem.image_address_components, - mem.image_has_mip ? 1u : 0u); + mem.image_has_mip ? 1u : 0u, mem.image_r128 ? 1u : 0u); if (mem.image_nsa_dwords != 0) { text += fmt::format(" image_nsa_dwords={} image_nsa_addr=", mem.image_nsa_dwords); const auto count = diff --git a/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp b/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp index 5f9033f2b..7ee465d3b 100644 --- a/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp +++ b/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp @@ -52,18 +52,23 @@ bool NullImageDescriptor(const DescriptorValue& descriptor) { return descriptor.dwords[0] == 0 && (descriptor.dwords[1] & 0xffu) == 0; } -bool ValidImageDescriptor(const DescriptorValue& descriptor) { +bool ValidImageDescriptor(const DescriptorValue& descriptor, bool r128 = false) { const auto type = static_cast((descriptor.dwords[3] >> 28u) & 0xfu); const auto format = static_cast((descriptor.dwords[1] >> 20u) & 0x1ffu); if (type < Prospero::ImageType::kColor1D || format == Prospero::BufferFormat::kInvalid) { return false; } + if (r128 && type != Prospero::ImageType::kColor1D && + type != Prospero::ImageType::kColor2D && type != Prospero::ImageType::kColor2DMsaa) { + return false; + } if (type == Prospero::ImageType::kColor2DMsaa || type == Prospero::ImageType::kColor2DMsaaArray) { const auto base_level = (descriptor.dwords[3] >> 12u) & 0xfu; const auto fragments = (descriptor.dwords[3] >> 16u) & 0xfu; const auto max_mip = (descriptor.dwords[5] >> 4u) & 0xfu; - return base_level == 0 && fragments >= 1 && fragments <= 3 && max_mip == fragments; + return base_level == 0 && fragments >= 1 && fragments <= 3 && + (r128 || max_mip == fragments); } return true; } @@ -644,7 +649,7 @@ bool MaterializeResources(const Program& program, const SrtRuntime& runtime, } } else { auto descriptor = *cursor++; - if (!ValidImageDescriptor(descriptor)) { + if (!ValidImageDescriptor(descriptor, image.r128)) { descriptor.dwords.fill(0); } next.images[image_index] = descriptor; diff --git a/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp b/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp index 45be7fa66..70835bdb3 100644 --- a/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp +++ b/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp @@ -652,7 +652,7 @@ private: auto& image = m_info.images[i]; if (image.source == source && image.kind == memory.kind && image.dimension == memory.image_dimension && image.mip_mode == mip && - image.depth_compare == depth) { + image.depth_compare == depth && image.r128 == memory.image_r128) { Merge(image, op, pc); return i; } @@ -667,6 +667,7 @@ private: image.dimension = memory.image_dimension; image.mip_mode = mip; image.depth_compare = depth; + image.r128 = memory.image_r128; Merge(image, op, pc); m_info.images.push_back(image); return static_cast(m_info.images.size() - 1); diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 63d48e024..139f18758 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -570,10 +570,11 @@ constexpr u32 EncodeSmem1(u32 offset, u32 soffset = 0) { } constexpr u32 EncodeMimg0(u32 opcode, u32 dmask, u32 nsa_dwords = 0, - bool glc = false, u32 dim = 1) { + bool glc = false, u32 dim = 1, bool r128 = false) { return (0x3cu << 26u) | ((opcode >> 7u) & 0x1u) | ((nsa_dwords & 0x3u) << 1u) | ((dim & 0x7u) << 3u) | ((dmask & 0xfu) << 8u) | (glc ? (1u << 13u) : 0u) | + (r128 ? (1u << 15u) : 0u) | ((opcode & 0x7fu) << 18u); } @@ -17625,6 +17626,35 @@ TestCase ImageLoadR32UintUsesIntegerSampledImage() { return test; } +TestCase ImageLoadR128IgnoresAdjacentMaskSgprs() { + using O = ShaderOpcode; + + std::vector code; + AppendVMovU32(&code, 20, 2); + AppendVMovU32(&code, 21, 1); + code.push_back(EncodeSop1(0x04, 4, 126)); // s_mov_b64 s[4:5], exec + code.push_back(EncodeMimg0(0x00, 0x1, 0, false, 1, true)); + code.push_back(EncodeMimg1(0, 20)); + AppendStoreVgpr(&code, 0, 0); + AppendEnd(&code); + + TestCase test; + test.name = "ImageLoadR128IgnoresAdjacentMaskSgprs"; + test.code = code; + test.expected = {0xdeadbeefu}; + test.opcodes = {O::V_MOV_B32, O::S_MOV_B64, O::IMAGE_LOAD, + O::BUFFER_STORE_DWORD, O::S_ENDPGM}; + test.sampled_image_rgba.resize(16); + test.sampled_image_rgba[6] = 0xdeadbeefu; + test.sampled_image_format = vk::Format::eR32Uint; + test.sampled_image_dwords_per_pixel = 1; + test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k32UInt); + test.has_user_data = true; + test.decoded_counts = {{"r128=1", 1}}; + test.native_ir_counts = {{"image_r128=1", 1}}; + return test; +} + TestCase ImageLoad1DUsesScalarCoordinate() { using O = ShaderOpcode; @@ -19095,6 +19125,7 @@ std::vector MakeCases() { AddCase(BufferAtomicFMaxContendedWorkgroup); AddCase(ImageLoadVariants); AddCase(ImageLoadR32UintUsesIntegerSampledImage); + AddCase(ImageLoadR128IgnoresAdjacentMaskSgprs); AddCase(ImageLoad1DUsesScalarCoordinate); AddCase(ImageLoad1DArrayUsesLayerCoordinate); AddCase(ImageLoad1DArrayDescriptorUsesSelectedLayer); @@ -20278,6 +20309,13 @@ void CheckSampledDepthDescriptor(RenderContext &renderer) { "valid uncompressed MSAA depth descriptor required an HTILE " "compatibility flag"); + auto r128_msaa = uncompressed_msaa; + std::fill(r128_msaa.fields + 4, r128_msaa.fields + 8, 0u); + Require("SampledDepthDescriptor", "R128 uncompressed 2x MSAA depth", + IsSupportedDepthTargetDescriptor(r128_msaa, msaa_image, true) && + IsSupportedDepthTextureEncoding(r128_msaa, msaa_image, true), + "valid R128 MSAA depth descriptor required omitted dwords"); + descriptor.fields[3] = (descriptor.fields[3] & ~(0xfu << 28u)) | (static_cast(Prospero::ImageType::kColor2DArray) << 28u); @@ -20670,6 +20708,19 @@ void CheckBasicStorageTextureDescriptor() { "PPSA02604 BGRA 2D storage descriptor fixture is malformed"); ValidateStorageTexture(BasicBgraStorageTextureResource(), bgra, 0x870000); + const ShaderTextureResource r128{{0x0202e500u, 0xc8200000u, 0x010dc1dfu, + 0x91b00facu, 0, 0, 0, 0}}; + auto r128_resource = BasicBgraStorageTextureResource(); + r128_resource.r128 = true; + Require("BasicStorageTexture", "PPSA01736 R128 descriptor", + r128.Base40() == 0x202e50000ull && r128.Width5() + 1u == 1920 && + r128.Height5() + 1u == 1080 && r128.Depth() + 1u == 1 && + r128.Format() == Prospero::BufferFormat::k8_8_8_8Srgb && + r128.TileMode() == Prospero::TileMode::kRenderTarget && + r128.DstSelXYZW() == DstSel(4, 5, 6, 7), + "PPSA01736 R128 storage descriptor fixture is malformed"); + ValidateStorageTexture(r128_resource, r128, 0x870000); + const auto r11g11b10 = Ppsa06228R11G11B10StorageTextureDescriptor(); Require("BasicStorageTexture", "PPSA06228 R11G11B10 descriptor", r11g11b10.Base40() == 0x10c6b50000ull &&