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
@@ -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
@@ -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;
+40 -3
View File
@@ -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;