graphics: broaden storage image atomic compatibility

This commit is contained in:
nmzik
2026-07-29 17:35:15 +02:00
parent 8a244677d7
commit 0b9edaa721
3 changed files with 70 additions and 30 deletions
@@ -104,10 +104,8 @@ IsSupportedSampledDepthUintResource(const ShaderRecompiler::IR::ImageResource& r
inline void ValidateStorageColorView(vk::Format image_format, vk::Format view_format, inline void ValidateStorageColorView(vk::Format image_format, vk::Format view_format,
uint32_t swizzle) noexcept { uint32_t swizzle) noexcept {
const auto srgb_view = SrgbStorageViewFormat(image_format); const auto srgb_view = SrgbStorageViewFormat(image_format);
const bool srgb_storage_view = const bool srgb_storage_view = srgb_view != vk::Format::eUndefined && view_format == srgb_view;
srgb_view != vk::Format::eUndefined && view_format == srgb_view; if ((image_format != view_format && !srgb_storage_view) || !IsValidImageSwizzle(swizzle)) {
if ((image_format != view_format && !srgb_storage_view) ||
!IsValidImageSwizzle(swizzle)) {
UnsupportedColorView("storage", image_format, view_format, 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::Dim3D ||
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2DArray) && resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2DArray) &&
resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::None && resource.written && 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 inline void
@@ -14,13 +14,13 @@
#include "graphics/guest_gpu/tile.h" #include "graphics/guest_gpu/tile.h"
#include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/hostMemory.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/debug.h"
#include "graphics/host_gpu/renderer/pipeline/descriptorCache.h"
#include "graphics/host_gpu/renderer/image/imageView.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/render.h"
#include "graphics/host_gpu/renderer/renderContext.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/vma.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/shader/recompiler/ir/BindingLayout.h" #include "graphics/shader/recompiler/ir/BindingLayout.h"
@@ -318,8 +318,8 @@ static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::Imag
const bool valid_2d_slice = const bool valid_2d_slice =
(is_color_2d && descriptor.Depth() == 0 && descriptor.BaseArray5() == 0) || (is_color_2d && descriptor.Depth() == 0 && descriptor.BaseArray5() == 0) ||
(is_color_2d_array && descriptor.BaseArray5() <= descriptor.Depth()); (is_color_2d_array && descriptor.BaseArray5() <= descriptor.Depth());
const bool is_2d = resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D && const bool is_2d =
valid_2d_slice; resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D && valid_2d_slice;
const bool is_2d_array = const bool is_2d_array =
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2DArray && resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2DArray &&
is_color_2d_array && descriptor.BaseArray5() <= descriptor.Depth(); 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) || const bool supported_tile = tile == Prospero::GpuEnumValue(Prospero::TileMode::kLinear) ||
tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) || tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) ||
supported_depth_tile || supported_standard_tile; supported_depth_tile || supported_standard_tile;
const auto swizzle = descriptor.DstSelXYZW();
const bool supported_swizzle = const bool supported_swizzle =
IsValidImageSwizzle(descriptor.DstSelXYZW()) && IsValidImageSwizzle(swizzle) &&
(descriptor.DstSelXYZW() == DstSel(4, 5, 6, 7) || !resource.read); (swizzle == DstSel(4, 5, 6, 7) || !resource.read || resource.atomic);
const bool supported_mip_view = descriptor.BaseLevel() == 0 || is_1d || is_2d; 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 && return (is_1d || is_1d_array || is_2d || is_2d_array || is_3d) && supported_tile &&
supported_mip_view && supported_mip_view && descriptor.BaseLevel() == descriptor.LastLevel() &&
descriptor.BaseLevel() == descriptor.LastLevel() &&
descriptor.LastLevel() <= descriptor.MaxMip() && descriptor.MinLod() == 0 && descriptor.LastLevel() <= descriptor.MaxMip() && descriptor.MinLod() == 0 &&
supported_swizzle && descriptor.BCSwizzle() == 0 && !descriptor.MsaaDepth(); 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 encoding_ok = IsSupportedStorageTextureEncoding(descriptor);
const bool uint_resource = const bool uint_resource =
resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint; resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint;
const bool format_ok = Prospero::IsSupportedTextureFormat(format) && const bool format_ok =
uint_resource == Prospero::IsUintTextureFormat(format); 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) { if (resource_ok && descriptor_ok && encoding_ok && format_ok && size != 0) {
return; return;
} }
@@ -620,8 +622,8 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso
const auto pixel_format = TextureGetFormat(format); const auto pixel_format = TextureGetFormat(format);
const auto storage_view_format = SrgbStorageViewFormat(pixel_format); const auto storage_view_format = SrgbStorageViewFormat(pixel_format);
const auto view_format = const auto view_format = storage && storage_view_format != vk::Format::eUndefined
storage && storage_view_format != vk::Format::eUndefined ? storage_view_format ? storage_view_format
: pixel_format; : pixel_format;
const auto block_bytes = Prospero::BlockCompressedBytesPerBlock(format); const auto block_bytes = Prospero::BlockCompressedBytesPerBlock(format);
TextureCache::ImageDesc desc {}; TextureCache::ImageDesc desc {};
+40 -3
View File
@@ -15220,7 +15220,7 @@ void CheckRenderTargetFormatContract() {
resource.kind = ShaderRecompiler::IR::ResourceKind::Image; resource.kind = ShaderRecompiler::IR::ResourceKind::Image;
} else if (std::strcmp(kind, "storage-no-write") == 0) { } else if (std::strcmp(kind, "storage-no-write") == 0) {
resource.written = false; resource.written = false;
} else if (std::strcmp(kind, "storage-atomic") == 0) { } else if (std::strcmp(kind, "storage-nonuint-atomic") == 0) {
resource.atomic = true; resource.atomic = true;
} else if (std::strcmp(kind, "storage-compare") == 0) { } else if (std::strcmp(kind, "storage-compare") == 0) {
resource.depth_compare = true; resource.depth_compare = true;
@@ -15437,6 +15437,12 @@ void CheckSampledColorViews() {
Require("SampledColorViews", "write-only uint 2D-array storage resource", Require("SampledColorViews", "write-only uint 2D-array storage resource",
IsSupportedStorageImageResource(storage_resource), IsSupportedStorageImageResource(storage_resource),
"basic write-only uint 2D-array storage resource was rejected"); "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]{}; char path[MAX_PATH]{};
Require("SampledColorViews", "host", Require("SampledColorViews", "host",
@@ -15446,7 +15452,7 @@ void CheckSampledColorViews() {
{"sampled-invalid-selector", "sampled-incompatible-format", {"sampled-invalid-selector", "sampled-incompatible-format",
"sampled-invalid-high", "sampled-depth-format", "sampled-depth-swizzle", "sampled-invalid-high", "sampled-depth-format", "sampled-depth-swizzle",
"storage-incompatible-format", "storage-kind", "storage-no-write", "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"}) { "volume-mip-count", "volume-slice-range"}) {
std::string command = std::string command =
std::string("\"") + path + "\" --image-view-death " + kind; std::string("\"") + path + "\" --image-view-death " + kind;
@@ -16155,6 +16161,19 @@ ShaderTextureResource BasicUintVolumeStorageTextureDescriptor() {
0x00700000u, 0x00000000u, 0x00000000u}}; 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) { [[noreturn]] void RunStorageTextureDescriptorDeathCase(const char *kind) {
auto resource = BasicStorageTextureResource(); auto resource = BasicStorageTextureResource();
auto descriptor = BasicStorageTextureDescriptor(); auto descriptor = BasicStorageTextureDescriptor();
@@ -16216,6 +16235,12 @@ ShaderTextureResource BasicUintVolumeStorageTextureDescriptor() {
} else if (std::strcmp(kind, "uint-resource-float-format") == 0) { } else if (std::strcmp(kind, "uint-resource-float-format") == 0) {
resource = BasicUintArrayStorageTextureResource(); resource = BasicUintArrayStorageTextureResource();
descriptor = BasicArrayStorageTextureDescriptor(); 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) { } else if (std::strcmp(kind, "depth-tile-read") == 0) {
resource = Ppsa14053DepthTileStorageTextureResource(); resource = Ppsa14053DepthTileStorageTextureResource();
descriptor = Ppsa14053DepthTileStorageTextureDescriptor(); descriptor = Ppsa14053DepthTileStorageTextureDescriptor();
@@ -16590,6 +16615,18 @@ void CheckBasicStorageTextureDescriptor() {
IsValidImageSwizzle(DstSel(4, 4, 4, 4)), IsValidImageSwizzle(DstSel(4, 4, 4, 4)),
"single-channel replicated destination selection was rejected"); "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]{}; char path[MAX_PATH]{};
Require("BasicStorageTexture", "host", Require("BasicStorageTexture", "host",
GetModuleFileNameA(nullptr, path, MAX_PATH) != 0, GetModuleFileNameA(nullptr, path, MAX_PATH) != 0,
@@ -16598,7 +16635,7 @@ void CheckBasicStorageTextureDescriptor() {
{"resource", "type", "tile", "mip", "swizzle", "linear-rgb1-read", {"resource", "type", "tile", "mip", "swizzle", "linear-rgb1-read",
"bgra-read", "r16-float-read", "r8-unorm-read", "yzwx-read", "bgra-read", "r16-float-read", "r8-unorm-read", "yzwx-read",
"reserved-swizzle", "array-base-out-of-range", "array-mip-view", "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"}) { "depth-tile-read", "depth-tile-extent", "depth-tile-fmask"}) {
std::string command = std::string("\"") + path + std::string command = std::string("\"") + path +
"\" --storage-texture-descriptor-death " + kind; "\" --storage-texture-descriptor-death " + kind;