diff --git a/src/graphics/host_gpu/renderer/image/imageView.h b/src/graphics/host_gpu/renderer/image/imageView.h index 949cc6a41..101d5a2a4 100644 --- a/src/graphics/host_gpu/renderer/image/imageView.h +++ b/src/graphics/host_gpu/renderer/image/imageView.h @@ -103,11 +103,9 @@ IsSupportedSampledDepthUintResource(const ShaderRecompiler::IR::ImageResource& r inline void ValidateStorageColorView(vk::Format image_format, vk::Format view_format, uint32_t swizzle) noexcept { - const auto srgb_view = SrgbStorageViewFormat(image_format); - const bool srgb_storage_view = - srgb_view != vk::Format::eUndefined && view_format == srgb_view; - if ((image_format != view_format && !srgb_storage_view) || - !IsValidImageSwizzle(swizzle)) { + const auto srgb_view = SrgbStorageViewFormat(image_format); + const bool srgb_storage_view = srgb_view != vk::Format::eUndefined && view_format == srgb_view; + if ((image_format != view_format && !srgb_storage_view) || !IsValidImageSwizzle(swizzle)) { UnsupportedColorView("storage", image_format, view_format, swizzle); } } @@ -122,7 +120,10 @@ IsSupportedStorageImageResource(const ShaderRecompiler::IR::ImageResource& resou resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim3D || resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2DArray) && resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::None && resource.written && - !resource.atomic && !resource.depth_compare; + (!resource.atomic || + (resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint && + resource.read)) && + !resource.depth_compare; } inline void diff --git a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp index cd1bc2de7..7b90476eb 100644 --- a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp @@ -14,13 +14,13 @@ #include "graphics/guest_gpu/tile.h" #include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/hostMemory.h" -#include "graphics/host_gpu/renderer/image/textureCommon.h" #include "graphics/host_gpu/renderer/debug.h" -#include "graphics/host_gpu/renderer/pipeline/descriptorCache.h" #include "graphics/host_gpu/renderer/image/imageView.h" +#include "graphics/host_gpu/renderer/image/textureCommon.h" +#include "graphics/host_gpu/renderer/pipeline/descriptorCache.h" +#include "graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h" #include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/renderContext.h" -#include "graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h" #include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vulkanCommon.h" #include "graphics/shader/recompiler/ir/BindingLayout.h" @@ -239,11 +239,11 @@ bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, co const uint32_t field3_expected = (descriptor.Type() << 28u) | field3_common | descriptor.DstSelXYZW(); const uint32_t field4_expected = descriptor.Depth() | (descriptor.BaseArray5() << 16u); - 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; + 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)) { return false; } @@ -318,8 +318,8 @@ static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::Imag const bool valid_2d_slice = (is_color_2d && descriptor.Depth() == 0 && descriptor.BaseArray5() == 0) || (is_color_2d_array && descriptor.BaseArray5() <= descriptor.Depth()); - const bool is_2d = resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D && - valid_2d_slice; + const bool is_2d = + resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D && valid_2d_slice; const bool is_2d_array = resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2DArray && is_color_2d_array && descriptor.BaseArray5() <= descriptor.Depth(); @@ -340,13 +340,13 @@ static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::Imag const bool supported_tile = tile == Prospero::GpuEnumValue(Prospero::TileMode::kLinear) || tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) || supported_depth_tile || supported_standard_tile; + const auto swizzle = descriptor.DstSelXYZW(); const bool supported_swizzle = - IsValidImageSwizzle(descriptor.DstSelXYZW()) && - (descriptor.DstSelXYZW() == DstSel(4, 5, 6, 7) || !resource.read); + IsValidImageSwizzle(swizzle) && + (swizzle == DstSel(4, 5, 6, 7) || !resource.read || resource.atomic); const bool supported_mip_view = descriptor.BaseLevel() == 0 || is_1d || is_2d; return (is_1d || is_1d_array || is_2d || is_2d_array || is_3d) && supported_tile && - supported_mip_view && - descriptor.BaseLevel() == descriptor.LastLevel() && + supported_mip_view && descriptor.BaseLevel() == descriptor.LastLevel() && descriptor.LastLevel() <= descriptor.MaxMip() && descriptor.MinLod() == 0 && supported_swizzle && descriptor.BCSwizzle() == 0 && !descriptor.MsaaDepth(); } @@ -377,8 +377,10 @@ void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource, const bool encoding_ok = IsSupportedStorageTextureEncoding(descriptor); const bool uint_resource = resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint; - const bool format_ok = Prospero::IsSupportedTextureFormat(format) && - uint_resource == Prospero::IsUintTextureFormat(format); + const bool format_ok = + Prospero::IsSupportedTextureFormat(format) && + uint_resource == Prospero::IsUintTextureFormat(format) && + (!resource.atomic || format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt)); if (resource_ok && descriptor_ok && encoding_ok && format_ok && size != 0) { return; } @@ -618,12 +620,12 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso resource.written); } - const auto pixel_format = TextureGetFormat(format); + const auto pixel_format = TextureGetFormat(format); const auto storage_view_format = SrgbStorageViewFormat(pixel_format); - const auto view_format = - storage && storage_view_format != vk::Format::eUndefined ? storage_view_format - : pixel_format; - const auto block_bytes = Prospero::BlockCompressedBytesPerBlock(format); + const auto view_format = storage && storage_view_format != vk::Format::eUndefined + ? storage_view_format + : pixel_format; + const auto block_bytes = Prospero::BlockCompressedBytesPerBlock(format); TextureCache::ImageDesc desc {}; desc.info.data = {address, size.size}; desc.info.pixel_format = pixel_format; diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index e6e4b052b..3af576f1b 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -15220,7 +15220,7 @@ void CheckRenderTargetFormatContract() { resource.kind = ShaderRecompiler::IR::ResourceKind::Image; } else if (std::strcmp(kind, "storage-no-write") == 0) { resource.written = false; - } else if (std::strcmp(kind, "storage-atomic") == 0) { + } else if (std::strcmp(kind, "storage-nonuint-atomic") == 0) { resource.atomic = true; } else if (std::strcmp(kind, "storage-compare") == 0) { resource.depth_compare = true; @@ -15437,6 +15437,12 @@ void CheckSampledColorViews() { Require("SampledColorViews", "write-only uint 2D-array storage resource", IsSupportedStorageImageResource(storage_resource), "basic write-only uint 2D-array storage resource was rejected"); + storage_resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; + storage_resource.read = true; + storage_resource.atomic = true; + Require("SampledColorViews", "atomic uint 2D storage resource", + IsSupportedStorageImageResource(storage_resource), + "atomic uint storage resource was rejected"); char path[MAX_PATH]{}; Require("SampledColorViews", "host", @@ -15446,7 +15452,7 @@ void CheckSampledColorViews() { {"sampled-invalid-selector", "sampled-incompatible-format", "sampled-invalid-high", "sampled-depth-format", "sampled-depth-swizzle", "storage-incompatible-format", "storage-kind", "storage-no-write", - "storage-atomic", "storage-compare", "storage-mip", "storage-dimension", + "storage-nonuint-atomic", "storage-compare", "storage-mip", "storage-dimension", "volume-mip-count", "volume-slice-range"}) { std::string command = std::string("\"") + path + "\" --image-view-death " + kind; @@ -16155,6 +16161,19 @@ ShaderTextureResource BasicUintVolumeStorageTextureDescriptor() { 0x00700000u, 0x00000000u, 0x00000000u}}; } +ShaderRecompiler::IR::ImageResource AtomicStorageTextureResource() { + auto resource = BasicLinearStorageTextureResource(); + resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint; + resource.read = true; + resource.atomic = true; + return resource; +} + +ShaderTextureResource AtomicStorageTextureDescriptor() { + return {{0x304bb700u, 0xc1400000u, 0x0000001fu, 0x91b00204u, 0x00000000u, + 0x00700000u, 0x00000000u, 0x00000000u}}; +} + [[noreturn]] void RunStorageTextureDescriptorDeathCase(const char *kind) { auto resource = BasicStorageTextureResource(); auto descriptor = BasicStorageTextureDescriptor(); @@ -16216,6 +16235,12 @@ ShaderTextureResource BasicUintVolumeStorageTextureDescriptor() { } else if (std::strcmp(kind, "uint-resource-float-format") == 0) { resource = BasicUintArrayStorageTextureResource(); descriptor = BasicArrayStorageTextureDescriptor(); + } else if (std::strcmp(kind, "atomic-format") == 0) { + resource = AtomicStorageTextureResource(); + descriptor = AtomicStorageTextureDescriptor(); + descriptor.fields[1] = + (descriptor.fields[1] & ~0x1ff00000u) | + (Prospero::GpuEnumValue(Prospero::BufferFormat::k8UInt) << 20u); } else if (std::strcmp(kind, "depth-tile-read") == 0) { resource = Ppsa14053DepthTileStorageTextureResource(); descriptor = Ppsa14053DepthTileStorageTextureDescriptor(); @@ -16590,6 +16615,18 @@ void CheckBasicStorageTextureDescriptor() { IsValidImageSwizzle(DstSel(4, 4, 4, 4)), "single-channel replicated destination selection was rejected"); + const auto atomic = AtomicStorageTextureDescriptor(); + Require("BasicStorageTexture", "atomic R32_UINT descriptor", + atomic.Width5() + 1u == 128 && atomic.Height5() + 1u == 1 && + atomic.Depth() + 1u == 1 && + atomic.Type() == + Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) && + atomic.Format() == + Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) && + atomic.DstSelXYZW() == DstSel(4, 0, 0, 1), + "PPSA22102 image-atomic descriptor fixture is malformed"); + ValidateStorageTexture(AtomicStorageTextureResource(), atomic, 0x10000); + char path[MAX_PATH]{}; Require("BasicStorageTexture", "host", GetModuleFileNameA(nullptr, path, MAX_PATH) != 0, @@ -16598,7 +16635,7 @@ void CheckBasicStorageTextureDescriptor() { {"resource", "type", "tile", "mip", "swizzle", "linear-rgb1-read", "bgra-read", "r16-float-read", "r8-unorm-read", "yzwx-read", "reserved-swizzle", "array-base-out-of-range", "array-mip-view", - "reserved", "uint-format", "uint-resource-float-format", + "reserved", "uint-format", "uint-resource-float-format", "atomic-format", "depth-tile-read", "depth-tile-extent", "depth-tile-fmask"}) { std::string command = std::string("\"") + path + "\" --storage-texture-descriptor-death " + kind;