From 8843291506a3f2152d66f97a48862595c0f9d46f Mon Sep 17 00:00:00 2001 From: nmzik Date: Tue, 20 Oct 2026 10:01:11 +0200 Subject: [PATCH] gpu: accept any T# perf_mod on storage textures through a shared canonical encoding check --- .../renderer/pipeline/descriptors.cpp | 57 +++++++------------ 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp index 5c50f737a..aa7870f1f 100644 --- a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp @@ -143,7 +143,8 @@ NativeStorageBuffer(RenderContext& context, const PreparedBindings::BufferSource return result; } -bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, bool r128) { +// Reserved and unsupported T# fields must be zero; perf_mod only scales sampler state. +static bool IsCanonicalTextureEncoding(const ShaderTextureResource& descriptor, bool r128) { constexpr uint32_t field1_reserved_mask = 0x200fff00u; constexpr uint32_t field2_reserved_mask = 0xf0003000u; const uint32_t field3_expected = descriptor.DstSelXYZW() | @@ -154,17 +155,25 @@ bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, bo 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; - if (r128) { - return common && descriptor.fields[4] == 0 && descriptor.fields[5] == 0 && - descriptor.fields[6] == 0 && descriptor.fields[7] == 0; + if ((descriptor.fields[1] & field1_reserved_mask) != 0 || + (descriptor.fields[2] & field2_reserved_mask) != 0 || descriptor.fields[3] != field3_expected) { + return false; } - const bool full = common && descriptor.fields[4] == field4_expected && - descriptor.fields[5] == field5_expected; - if (!full || - (descriptor.MsaaDepth() && !IsMultisampledTexture(descriptor.Type()))) { + if (r128) { + return descriptor.fields[4] == 0 && descriptor.fields[5] == 0 && descriptor.fields[6] == 0 && + descriptor.fields[7] == 0; + } + return descriptor.fields[4] == field4_expected && descriptor.fields[5] == field5_expected; +} + +bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, bool r128) { + if (!IsCanonicalTextureEncoding(descriptor, r128)) { + return false; + } + if (r128) { + return true; + } + if (descriptor.MsaaDepth() && !IsMultisampledTexture(descriptor.Type())) { return false; } const auto metadata_control = descriptor.fields[6] & 0x00ffffffu; @@ -281,36 +290,12 @@ static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::Imag !descriptor.MsaaDepth(); } -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; - constexpr uint32_t field5_max_mip_mask = 0x000000f0u; - const uint32_t expected_field3 = descriptor.DstSelXYZW() | - (static_cast(descriptor.BaseLevel()) << 12u) | - (static_cast(descriptor.LastLevel()) << 16u) | - (static_cast(descriptor.TileMode()) << 20u) | - (static_cast(descriptor.Type()) << 28u); - const uint32_t expected_field4 = - descriptor.Depth() | (static_cast(descriptor.BaseArray5()) << 16u); - 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; -} - void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource, const ShaderTextureResource& descriptor, uint64_t size) { const auto format = descriptor.Format(); const bool resource_ok = IsSupportedStorageImageResource(resource); const bool descriptor_ok = IsSupportedStorageTextureDescriptor(resource, descriptor); - const bool encoding_ok = IsSupportedStorageTextureEncoding(resource, descriptor); + const bool encoding_ok = IsCanonicalTextureEncoding(descriptor, resource.r128); const bool uint_resource = resource.numeric_class == Prospero::TextureNumericClass::Uint; const bool raw_sint_storage = uint_resource && ShaderRecompiler::IR::RawSignedStorageFormat(resource, format) != Prospero::BufferFormat::kInvalid;