From 86e3c90e32ce7585f135032b335ee6e6da22f0b1 Mon Sep 17 00:00:00 2001 From: nmzik Date: Wed, 2 Sep 2026 11:37:39 +0400 Subject: [PATCH] shader: simplify image resource semantics --- .../host_gpu/renderer/image/imageView.h | 25 +-- .../renderer/pipeline/descriptors.cpp | 90 ++++----- .../host_gpu/renderer/renderCompute.cpp | 10 +- src/graphics/host_gpu/renderer/renderDraw.cpp | 3 +- .../backend/spirv/spirvEmitterAnalysis.cpp | 83 ++++---- .../backend/spirv/spirvEmitterImage.cpp | 51 ++--- .../backend/spirv/spirvEmitterInternal.h | 37 ++-- .../recompiler/frontend/translate/Memory.cpp | 22 +-- src/graphics/shader/recompiler/ir/Program.cpp | 3 +- src/graphics/shader/recompiler/ir/ShaderIR.h | 183 ++++++++---------- .../recompiler/ir/opcodes/ValueOpcodes.cpp | 2 +- .../recompiler/ir/opcodes/ValueOpcodes.h | 2 +- .../ir/passes/ResourceMaterialization.cpp | 153 ++++++--------- .../recompiler/ir/passes/ResourceTracking.cpp | 42 ++-- tests/ResourceTrackingTests.cpp | 40 +--- tests/ShaderRecompilerComputeTests.cpp | 102 ++++++---- tests/shaderCfgTests.cpp | 46 +---- 17 files changed, 381 insertions(+), 513 deletions(-) diff --git a/src/graphics/host_gpu/renderer/image/imageView.h b/src/graphics/host_gpu/renderer/image/imageView.h index ddd9e79c7..a77322595 100644 --- a/src/graphics/host_gpu/renderer/image/imageView.h +++ b/src/graphics/host_gpu/renderer/image/imageView.h @@ -103,11 +103,13 @@ SelectSampledDepthView(vk::Format image_format, vk::Format view_format, uint32_t [[nodiscard]] inline bool IsSupportedSampledDepthResource(const ShaderRecompiler::IR::ImageResource& resource) noexcept { - if (!ShaderRecompiler::IR::ImageResourceKindMatches( - resource.kind, ShaderRecompiler::IR::ImageResourceClass::Sampled)) { + if (resource.resource_class != ShaderRecompiler::IR::ImageResourceClass::Sampled) { return false; } - if (resource.kind != ShaderRecompiler::IR::ResourceKind::Image && resource.depth_compare) { + if (resource.numeric_class == Prospero::TextureNumericClass::Unsupported) { + return false; + } + if (resource.numeric_class != Prospero::TextureNumericClass::Float && resource.depth_compare) { return false; } return (resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D || @@ -128,8 +130,9 @@ inline void ValidateStorageColorView(vk::Format image_format, vk::Format view_fo [[nodiscard]] inline bool IsSupportedStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource) noexcept { - return (resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImage || - resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint) && + return resource.resource_class == ShaderRecompiler::IR::ImageResourceClass::Storage && + (resource.numeric_class == Prospero::TextureNumericClass::Float || + resource.numeric_class == Prospero::TextureNumericClass::Uint) && (resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim1D || resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim1DArray || resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D || @@ -141,19 +144,19 @@ IsSupportedStorageImageResource(const ShaderRecompiler::IR::ImageResource& resou resource.mip_count != 0u)) && resource.written && (!resource.atomic || - (resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint && - resource.read)) && + (resource.numeric_class == Prospero::TextureNumericClass::Uint && resource.read)) && !resource.depth_compare; } inline void ValidateStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource) noexcept { if (!IsSupportedStorageImageResource(resource)) { - EXIT("unsupported storage color image resource: kind=%u dimension=%u mip=%u " + EXIT("unsupported storage color image resource: class=%u numeric=%u dimension=%u mip=%u " "read=%d written=%d atomic=%d depth_compare=%d\n", - static_cast(resource.kind), static_cast(resource.dimension), - static_cast(resource.mip_mode), resource.read, resource.written, - resource.atomic, resource.depth_compare); + static_cast(resource.resource_class), + static_cast(resource.numeric_class), + static_cast(resource.dimension), static_cast(resource.mip_mode), + resource.read, resource.written, resource.atomic, resource.depth_compare); } } diff --git a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp index e8c9c7011..71be0ed8b 100644 --- a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp @@ -236,11 +236,10 @@ static bool IsSupportedSampledColorResource(const ShaderRecompiler::IR::ImageRes break; default: break; } - const bool sampled_kind = ShaderRecompiler::IR::ImageResourceKindMatches( - resource.kind, ShaderRecompiler::IR::ImageResourceClass::Sampled); - return sampled_kind && supported_dimension && - resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::None && resource.read && - !resource.written && !resource.atomic && !resource.depth_compare; + return resource.resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled && + resource.numeric_class != Prospero::TextureNumericClass::Unsupported && + supported_dimension && resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::None && + resource.read && !resource.written && !resource.atomic && !resource.depth_compare; } TargetTextureViewInfo ResolveTargetTextureView(const ShaderRecompiler::IR::ImageResource& resource, @@ -394,15 +393,17 @@ static void ValidateDepthTargetBinding(const ShaderRecompiler::IR::ImageResource TileGetTexturePitch(descriptor.Format(), static_cast(descriptor.Width5()) + 1u, descriptor.TileMode()); EXIT("unsupported sampled depth target: resource=%d descriptor=%d encoding=%d format=%d " - "kind=%u dimension=%u mip_mode=%u read=%d written=%d atomic=%d compare=%d " + "class=%u numeric=%u dimension=%u mip_mode=%u read=%d written=%d atomic=%d compare=%d " "guest_format=%u swizzle=0x%03x image_format=%d view_format=%d image_layers=%u " "descriptor_type=%u base_array=%u depth=%u descriptor_pitch=%u target_pitch=%u " "addr=0x%016" PRIx64 " size=0x%016" PRIx64 " dwords=%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x\n", - resource_ok, descriptor_ok, encoding_ok, format_ok, static_cast(resource.kind), - static_cast(resource.dimension), static_cast(resource.mip_mode), - resource.read, resource.written, resource.atomic, resource.depth_compare, - static_cast(descriptor.Format()), descriptor.DstSelXYZW(), + resource_ok, descriptor_ok, encoding_ok, format_ok, + static_cast(resource.resource_class), + static_cast(resource.numeric_class), static_cast(resource.dimension), + static_cast(resource.mip_mode), resource.read, resource.written, resource.atomic, + resource.depth_compare, static_cast(descriptor.Format()), + descriptor.DstSelXYZW(), image == nullptr ? static_cast(vk::Format::eUndefined) : static_cast(image->info.pixel_format), static_cast(view_format), image == nullptr ? 0u : image->info.resources.layers, @@ -515,8 +516,7 @@ void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource, const bool resource_ok = IsSupportedStorageImageResource(resource); const bool descriptor_ok = IsSupportedStorageTextureDescriptor(resource, descriptor); const bool encoding_ok = IsSupportedStorageTextureEncoding(resource, descriptor); - const bool uint_resource = - resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint; + const bool uint_resource = resource.numeric_class == Prospero::TextureNumericClass::Uint; const bool raw_sint_storage = format == Prospero::BufferFormat::k32SInt && uint_resource && resource.written && !resource.read && !resource.atomic; const auto numeric_class = Prospero::SampledTextureNumericClass(format); @@ -530,17 +530,19 @@ void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource, return; } EXIT("unsupported storage texture: resource=%d descriptor=%d encoding=%d format=%d " - "kind=%u dimension=%u mip_mode=%u atomic=%d compare=%d " + "class=%u numeric=%u dimension=%u mip_mode=%u atomic=%d compare=%d " "base_level=%u last_level=%u max_mip=%u min_lod=%u base_array=%u bc=%u msaa=%d " "depth_tile_bpe=%u swizzle_ok=%d " "addr=0x%016" PRIx64 " size=0x%016" PRIx64 " extent=%ux%ux%u type=%u format=%u tile=%u swizzle=0x%03x read=%d written=%d " "dwords=%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x\n", - resource_ok, descriptor_ok, encoding_ok, format_ok, static_cast(resource.kind), - static_cast(resource.dimension), static_cast(resource.mip_mode), - resource.atomic, resource.depth_compare, descriptor.BaseLevel(), descriptor.LastLevel(), - descriptor.MaxMip(), descriptor.MinLod(), descriptor.BaseArray5(), descriptor.BCSwizzle(), - descriptor.MsaaDepth(), Prospero::RenderTargetBytesPerElement(format), + resource_ok, descriptor_ok, encoding_ok, format_ok, + static_cast(resource.resource_class), + static_cast(resource.numeric_class), static_cast(resource.dimension), + static_cast(resource.mip_mode), resource.atomic, resource.depth_compare, + descriptor.BaseLevel(), descriptor.LastLevel(), descriptor.MaxMip(), descriptor.MinLod(), + descriptor.BaseArray5(), descriptor.BCSwizzle(), descriptor.MsaaDepth(), + Prospero::RenderTargetBytesPerElement(format), IsValidImageSwizzle(descriptor.DstSelXYZW()), descriptor.Base40(), size, static_cast(descriptor.Width5()) + 1u, static_cast(descriptor.Height5()) + 1u, @@ -557,13 +559,16 @@ struct NullImageSpec { }; static NullImageSpec NullTextureSpec(const ShaderRecompiler::IR::ImageResource& resource) { - if (resource.kind == ShaderRecompiler::IR::ResourceKind::ImageSint) { - return {vk::Format::eR32Sint, Prospero::BufferFormat::k32SInt}; + switch (resource.numeric_class) { + case Prospero::TextureNumericClass::Float: + return {vk::Format::eR32Sfloat, Prospero::BufferFormat::k32Float}; + case Prospero::TextureNumericClass::Uint: + return {vk::Format::eR32Uint, Prospero::BufferFormat::k32UInt}; + case Prospero::TextureNumericClass::Sint: + return {vk::Format::eR32Sint, Prospero::BufferFormat::k32SInt}; + case Prospero::TextureNumericClass::Unsupported: break; } - const bool uint_image = resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint || - resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint; - return uint_image ? NullImageSpec {vk::Format::eR32Uint, Prospero::BufferFormat::k32UInt} - : NullImageSpec {vk::Format::eR32Sfloat, Prospero::BufferFormat::k32Float}; + EXIT("null image has unsupported numeric class\n"); } static TextureCache::ImageDesc NullTextureDesc(const ShaderRecompiler::IR::ImageResource& resource, @@ -731,15 +736,16 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR !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 " - "kind=%u dimension=%u mip_mode=%u read=%d written=%d " + "class=%u numeric=%u dimension=%u mip_mode=%u read=%d written=%d " "dwords=%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x\n", base_level, last_level, levels, descriptor.MaxMip(), static_cast(descriptor.Type()), static_cast(tile), - static_cast(resource.kind), static_cast(resource.dimension), - static_cast(resource.mip_mode), resource.read, resource.written, - descriptor.fields[0], descriptor.fields[1], descriptor.fields[2], descriptor.fields[3], - descriptor.fields[4], descriptor.fields[5], descriptor.fields[6], - descriptor.fields[7]); + static_cast(resource.resource_class), + static_cast(resource.numeric_class), + static_cast(resource.dimension), static_cast(resource.mip_mode), + resource.read, resource.written, descriptor.fields[0], descriptor.fields[1], + descriptor.fields[2], descriptor.fields[3], descriptor.fields[4], descriptor.fields[5], + descriptor.fields[6], descriptor.fields[7]); } const auto samples = multisampled ? 1u << last_level : 1u; const auto view_levels = @@ -749,28 +755,12 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR const auto surface_format = TextureGetSurfaceFormatInfo(format); const bool shader_conversion = surface_format.conversion_format != Prospero::BufferFormat::kInvalid; - Prospero::TextureNumericClass resource_numeric_class = - Prospero::TextureNumericClass::Unsupported; - switch (resource.kind) { - case ShaderRecompiler::IR::ResourceKind::Image: - resource_numeric_class = Prospero::TextureNumericClass::Float; - break; - case ShaderRecompiler::IR::ResourceKind::ImageUint: - resource_numeric_class = Prospero::TextureNumericClass::Uint; - break; - case ShaderRecompiler::IR::ResourceKind::ImageSint: - resource_numeric_class = Prospero::TextureNumericClass::Sint; - break; - default: break; - } const bool sampled_numeric_class = - storage || resource_numeric_class == Prospero::SampledTextureNumericClass(format); - if (!storage && - ShaderRecompiler::IR::ImageResourceKindMatches( - resource.kind, ShaderRecompiler::IR::ImageResourceClass::Sampled) && + storage || resource.numeric_class == Prospero::SampledTextureNumericClass(format); + if (!storage && resource.resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled && !sampled_numeric_class) { - EXIT("sampled image numeric class mismatch: kind=%u format=%u addr=0x%016" PRIx64 "\n", - static_cast(resource.kind), static_cast(format), address); + EXIT("sampled image numeric class mismatch: numeric=%u format=%u addr=0x%016" PRIx64 "\n", + static_cast(resource.numeric_class), static_cast(format), address); } const bool volume = type == Prospero::ImageType::kColor3D; diff --git a/src/graphics/host_gpu/renderer/renderCompute.cpp b/src/graphics/host_gpu/renderer/renderCompute.cpp index 97b48f67f..5ac238d02 100644 --- a/src/graphics/host_gpu/renderer/renderCompute.cpp +++ b/src/graphics/host_gpu/renderer/renderCompute.cpp @@ -236,8 +236,7 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer, } const auto sampled_images = std::count_if( program.info.images.begin(), program.info.images.end(), [](const auto& image) { - return ShaderRecompiler::IR::ImageResourceKindMatches( - image.kind, ShaderRecompiler::IR::ImageResourceClass::Sampled); + return image.resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled; }); const bool has_sampler = !program.info.samplers.empty(); static std::atomic dispatch_log_count {0}; @@ -265,8 +264,7 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer, LOGF(" CS texture[%u]: source=%u usage=%s sampled=%s addr=0x%010" PRIx64 " type=%u fmt=%u extent=%ux%u depth=%u levels=%u tile=%u\n", i, image.source, image.written ? "read-write" : "read-only", - ShaderRecompiler::IR::ImageResourceKindMatches( - image.kind, ShaderRecompiler::IR::ImageResourceClass::Sampled) + image.resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled ? "true" : "false", r.Base40(), static_cast(r.Type()), static_cast(r.Format()), @@ -347,8 +345,8 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer, std::any_of(program.info.images.begin(), program.info.images.end(), [](const auto& image) { return image.written && - (image.kind == ShaderRecompiler::IR::ResourceKind::StorageImage || - image.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint); + image.resource_class == + ShaderRecompiler::IR::ImageResourceClass::Storage; }) || has_storage_writes; if (has_storage_writes) { diff --git a/src/graphics/host_gpu/renderer/renderDraw.cpp b/src/graphics/host_gpu/renderer/renderDraw.cpp index 017af78ff..acd6e6f2f 100644 --- a/src/graphics/host_gpu/renderer/renderDraw.cpp +++ b/src/graphics/host_gpu/renderer/renderDraw.cpp @@ -199,8 +199,7 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col const auto& ps_resources = ps_input_info.stage.program->info; const auto sampled_images = std::count_if( ps_resources.images.begin(), ps_resources.images.end(), [](const auto& image) { - return ShaderRecompiler::IR::ImageResourceKindMatches( - image.kind, ShaderRecompiler::IR::ImageResourceClass::Sampled); + return image.resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled; }); vk::Extent2D extent = color.image_id ? color.extent : vk::Extent2D {}; diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAnalysis.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAnalysis.cpp index 80bc52ccd..f039c8a59 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAnalysis.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAnalysis.cpp @@ -185,29 +185,36 @@ uint32_t StorageImagePointerType(EmitterState& state, StorageImageClass image_cl } StorageImageClass StorageImageClassForResource(const EmitterState& state, uint32_t resource) { - const auto& image = state.program.info.images.at(resource); - const bool uint_image = image.kind == IR::ResourceKind::StorageImageUint; - EXIT_IF(image.kind != IR::ResourceKind::StorageImage && !uint_image); - EXIT_IF(image.atomic && !uint_image); - return StorageImageClassFor(uint_image, image.atomic); + const auto& image = state.program.info.images.at(resource); + EXIT_IF(image.resource_class != IR::ImageResourceClass::Storage); + if (image.atomic) { + EXIT_IF(image.numeric_class != Prospero::TextureNumericClass::Uint); + return StorageImageClass::AtomicUint; + } + switch (image.numeric_class) { + case Prospero::TextureNumericClass::Float: return StorageImageClass::FormatlessFloat; + case Prospero::TextureNumericClass::Uint: return StorageImageClass::FormatlessUint; + case Prospero::TextureNumericClass::Sint: + case Prospero::TextureNumericClass::Unsupported: + EXIT("invalid storage image numeric class"); + } + EXIT("invalid storage image numeric class"); } -uint32_t StorageImageVariable(const EmitterState& state, StorageImageClass image_class, - ImageDimension dimension) { - return state.storage_image_variables[StorageImageIndex(image_class, dimension)]; -} - -uint32_t LoadSampledImageDescriptor(EmitterState& state, const IR::MemoryInfo& mem, - ImageDimension dimension) { - const auto image_class = SampledImageClassFor(mem.kind); +uint32_t LoadSampledImageDescriptor(EmitterState& state, uint32_t resource) { + const auto& image_resource = state.program.info.images.at(resource); + EXIT_IF(image_resource.resource_class != IR::ImageResourceClass::Sampled); + const auto dimension = image_resource.dimension; + const auto image_class = SampledImageClassFor(image_resource.numeric_class); + EXIT_IF(image_class == SampledImageClass::Count); const auto kind = SampledBindingKind(image_class, dimension); - const auto array_index = ResourceForDescriptor(state, kind, mem.resource); + const auto array_index = ResourceForDescriptor(state, kind, resource); const auto variable = state.sampled_image_variables[SampledImageIndex(image_class, dimension)]; const auto pointer_type = state.builder.Type(OpTypePointer, {StorageClassUniformConstant, ImageViewImageType(state, dimension, image_class)}); const auto pointer = - DescriptorElementPointer(state, pointer_type, variable, array_index, kind, mem.resource, + DescriptorElementPointer(state, pointer_type, variable, array_index, kind, resource, "sampled image descriptor array was not emitted"); const auto image = state.builder.AllocateId(); state.builder.AddFunction( @@ -229,43 +236,37 @@ uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler) { return sampler_id; } -uint32_t MakeSampledImage(EmitterState& state, const IR::MemoryInfo& mem, - ImageDimension dimension) { - const auto image = LoadSampledImageDescriptor(state, mem, dimension); - const auto sampler = LoadSamplerDescriptor(state, mem.sampler); - if (image == 0 || sampler == 0) { - ExitDescriptorBindingFailure( - state, SampledBindingKind(SampledImageClassFor(mem.kind), dimension), mem.resource, - "sampled image or sampler descriptor load failed"); +uint32_t MakeSampledImage(EmitterState& state, uint32_t resource, uint32_t sampler) { + const auto& image_resource = state.program.info.images.at(resource); + const auto dimension = image_resource.dimension; + const auto image_class = SampledImageClassFor(image_resource.numeric_class); + const auto image = LoadSampledImageDescriptor(state, resource); + const auto sampler_id = LoadSamplerDescriptor(state, sampler); + if (image == 0 || sampler_id == 0) { + ExitDescriptorBindingFailure(state, SampledBindingKind(image_class, dimension), resource, + "sampled image or sampler descriptor load failed"); } const auto sampled_image = state.builder.AllocateId(); - state.builder.AddFunction( - {OpSampledImage, - ImageViewSampledImageType(state, dimension, SampledImageClassFor(mem.kind)), sampled_image, - image, sampler}); + state.builder.AddFunction({OpSampledImage, + ImageViewSampledImageType(state, dimension, image_class), + sampled_image, image, sampler_id}); return sampled_image; } -uint32_t MakeSampledImage(EmitterState& state, const IR::MemoryInfo& mem, ImageDimension dimension, - uint32_t image_resource) { - auto selected = mem; - selected.resource = image_resource; - return MakeSampledImage(state, selected, dimension); -} - -uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource, - ImageDimension dimension) { +uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource) { + const auto dimension = state.program.info.images.at(resource).dimension; const auto image_class = StorageImageClassForResource(state, resource); const auto kind = StorageBindingKind(image_class, dimension); const auto array_index = ResourceForDescriptor(state, kind, resource); const auto ptr_type = StorageImagePointerType(state, image_class, dimension); - const auto variable = StorageImageVariable(state, image_class, dimension); + const auto variable = state.storage_image_variables[StorageImageIndex(image_class, dimension)]; return DescriptorElementPointer(state, ptr_type, variable, array_index, kind, resource, "storage image descriptor array was not emitted"); } -void EmitStorageImageWrite(EmitterState& state, uint32_t resource, ImageDimension dimension, - uint32_t mip_lod, uint32_t coord, uint32_t texel) { +void EmitStorageImageWrite(EmitterState& state, uint32_t resource, uint32_t mip_lod, uint32_t coord, + uint32_t texel) { + const auto dimension = state.program.info.images.at(resource).dimension; const auto image_class = StorageImageClassForResource(state, resource); if (image_class != StorageImageClass::AtomicUint) { state.builder.RequireCapability(CapabilityStorageImageWriteWithoutFormat); @@ -276,8 +277,8 @@ void EmitStorageImageWrite(EmitterState& state, uint32_t resource, ImageDimensio const auto LoadAt = [&](uint32_t array_index) { const auto pointer = DescriptorElementPointer( state, StorageImagePointerType(state, image_class, dimension), - StorageImageVariable(state, image_class, dimension), array_index, kind, resource, - "storage image descriptor array was not emitted"); + state.storage_image_variables[StorageImageIndex(image_class, dimension)], array_index, + kind, resource, "storage image descriptor array was not emitted"); const auto descriptor = state.builder.AllocateId(); state.builder.AddFunction( {OpLoad, StorageImageType(state, image_class, dimension), descriptor, pointer}); diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp index 2ca9aff83..a6f4718ad 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp @@ -145,11 +145,12 @@ uint32_t CubeLayer(EmitterState& state, uint32_t value) { uint32_t CoordF32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::Inst& address, uint32_t first, uint32_t components) { + const bool cube = ctx.state.program.info.images.at(mem.resource).cube; auto x = AddressF32(ctx, mem, address, first); if (components == 1u) return x; auto y = mem.image_address_components > first + 1u ? AddressF32(ctx, mem, address, first + 1u) : ZeroF32(ctx.state); - if (mem.image_cube) { + if (cube) { x = CubeAxis(ctx.state, x); y = CubeAxis(ctx.state, y); } @@ -158,7 +159,7 @@ uint32_t CoordF32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::In auto z = mem.image_address_components > first + 2u ? AddressF32(ctx, mem, address, first + 2u) : ZeroF32(ctx.state); - if (mem.image_cube) z = CubeLayer(ctx.state, z); + if (cube) z = CubeLayer(ctx.state, z); ctx.state.builder.AddFunction( {OpCompositeConstruct, TypeF32Vector(ctx.state, 3), result, x, y, z}); } else { @@ -284,9 +285,9 @@ uint32_t ResultVector(ValueEmitContext& ctx, uint32_t value, SampledImageClass i uint32_t QueryDimensions(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::Inst& address) { - const auto dimension = mem.image_dimension; + const auto dimension = ctx.state.program.info.images.at(mem.resource).dimension; const auto& info = ImageDimensionInfoFor(dimension); - const auto image = LoadSampledImageDescriptor(ctx.state, mem, dimension); + const auto image = LoadSampledImageDescriptor(ctx.state, mem.resource); const auto size = ctx.state.builder.AllocateId(); if (info.multisampled != 0u) { ctx.state.builder.AddFunction( @@ -464,7 +465,7 @@ uint32_t EmitOneDimensionalGatherLz(ValueEmitContext& ctx, const IR::MemoryInfo& uint32_t coord, SampledImageClass image_class) { auto& state = ctx.state; state.builder.RequireCapability(CapabilityImageQuery); - const auto image = LoadSampledImageDescriptor(state, mem, ImageDimension::Dim1D); + const auto image = LoadSampledImageDescriptor(state, mem.resource); const auto width = state.builder.AllocateId(); state.builder.AddFunction( {OpImageQuerySizeLod, TypeU32(state), width, image, ConstantU32(state, 0)}); @@ -476,7 +477,7 @@ uint32_t EmitOneDimensionalGatherLz(ValueEmitContext& ctx, const IR::MemoryInfo& Binary(state, OpFMul, TypeF32(state), coord, width_f32), ConstantF32(state, 0x3f000000u))}); - const auto sampled = MakeSampledImage(state, mem, ImageDimension::Dim1D); + const auto sampled = MakeSampledImage(state, mem.resource, mem.sampler); const auto vector_type = SampledImageVectorType(state, image_class, 4); const auto scalar_type = SampledImageScalarType(state, image_class); const auto component = @@ -592,6 +593,7 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { const auto& mem = ctx.Memory(inst); const auto image_arg = inst.Arg(0); ctx.ResourceIndex(image_arg, IR::ValueOpcode::GetImageResource); + const auto& image = state.program.info.images.at(mem.resource); const auto* address = ctx.ImageAddress(inst.Arg(image_info.needs_sampler ? 2 : 1)); if (address == nullptr) return true; if (op == IR::ValueOpcode::ImageQueryDimensions) { @@ -601,8 +603,8 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { } if (op == IR::ValueOpcode::ImageQueryLod) { state.builder.RequireCapability(CapabilityImageQuery); - const auto dimension = mem.image_dimension; - const auto sampled = MakeSampledImage(state, mem, dimension); + const auto dimension = image.dimension; + const auto sampled = MakeSampledImage(state, mem.resource, mem.sampler); const auto lod = state.builder.AllocateId(); state.builder.AddFunction( {OpImageQueryLod, TypeF32Vector(state, 2), lod, sampled, @@ -621,27 +623,27 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { return true; } if (op == IR::ValueOpcode::ImageRead) { - const auto dimension = mem.image_dimension; + const auto dimension = image.dimension; const auto& dimension_info = ImageDimensionInfoFor(dimension); - const auto image_class = SampledImageClassFor(mem.kind); + const auto image_class = SampledImageClassFor(image.numeric_class); const auto condition = ctx.Arg(inst, 2); ctx.Define( inst, EmitValueOrDefaultIfCondition( state, condition, TypeU32Vector(state, 4), ConstantU32CompositeZero(state, 4), [&]() { - const auto image = LoadSampledImageDescriptor(state, mem, dimension); - const auto color = state.builder.AllocateId(); - const auto coord = CoordU32(ctx, mem, *address, dimension); + const auto descriptor = LoadSampledImageDescriptor(state, mem.resource); + const auto color = state.builder.AllocateId(); + const auto coord = CoordU32(ctx, mem, *address, dimension); if (dimension_info.multisampled != 0u) { state.builder.AddFunction( {OpImageFetch, SampledImageVectorType(state, image_class, 4), color, - image, coord, ImageOperandsSampleMask, + descriptor, coord, ImageOperandsSampleMask, AddressU32(ctx, mem, *address, dimension_info.coordinate_components)}); } else { state.builder.AddFunction({OpImageFetch, SampledImageVectorType(state, image_class, 4), - color, image, coord, ImageOperandsLodMask, + color, descriptor, coord, ImageOperandsLodMask, LodU32(ctx, mem, *address, dimension)}); } return ResultVector(ctx, UnpackImageTexel(ctx, mem, color), image_class, false, @@ -650,8 +652,8 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { return true; } if (op == IR::ValueOpcode::ImageWrite) { - const auto uint_image = mem.kind == IR::ResourceKind::StorageImageUint; - const auto dimension = mem.image_dimension; + const bool uint_image = image.numeric_class == Prospero::TextureNumericClass::Uint; + const auto dimension = image.dimension; EmitIfCondition(state, ctx.Arg(inst, 3), [&]() { const auto mip_lod = state.program.info.images[mem.resource].mip_mode == IR::ImageMipMode::DynamicStorage @@ -659,15 +661,15 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { : 0u; const auto coord = CoordU32(ctx, mem, *address, dimension); const auto texel = StoreTexel(ctx, mem, ctx.Arg(inst, 2), uint_image); - EmitStorageImageWrite(state, mem.resource, dimension, mip_lod, coord, texel); + EmitStorageImageWrite(state, mem.resource, mip_lod, coord, texel); }); return true; } if (op == IR::ValueOpcode::ImageSampleRaw || op == IR::ValueOpcode::ImageGatherRaw) { - const auto dimension = mem.image_dimension; + const auto dimension = image.dimension; const auto& dimension_info = ImageDimensionInfoFor(dimension); const auto layout = Layout(mem, dimension); - const auto image_class = SampledImageClassFor(mem.kind); + const auto image_class = SampledImageClassFor(image.numeric_class); const bool dref = HasFlag(mem, Decoder::ImageSampleFlagCompare); if (dref && state.program.info.images[mem.resource].conversion_format != Prospero::BufferFormat::kInvalid) { @@ -693,7 +695,7 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { ctx.Fail(inst, "has an unsupported 1D-array gather"); return true; } - const auto sampled = MakeSampledImage(state, mem, dimension); + const auto sampled = MakeSampledImage(state, mem.resource, mem.sampler); const auto sample = state.builder.AllocateId(); std::vector words = dref ? std::vector {OpImageDrefGather, @@ -759,7 +761,7 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { operands.push_back(AddressF32(ctx, mem, *address, layout.bias)); } const auto EmitSample = [&](uint32_t resource) { - const auto sampled = MakeSampledImage(state, mem, dimension, resource); + const auto sampled = MakeSampledImage(state, resource, mem.sampler); const auto sample = state.builder.AllocateId(); std::vector words {opcode, result_type, sample, sampled, coord}; if (dref) { @@ -772,7 +774,6 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { state.builder.AddFunction(words); return sample; }; - const auto& image = state.program.info.images[mem.resource]; if (image.indirect_root != mem.resource) { const auto sample = EmitSample(mem.resource); ctx.Define(inst, ResultVector(ctx, dref ? sample : UnpackImageTexel(ctx, mem, sample), @@ -874,14 +875,14 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { } const auto atomic_opcode = ImageAtomicOpcode(op); if (atomic_opcode != 0u) { - const auto dimension = mem.image_dimension; + const auto dimension = image.dimension; ctx.Define(inst, EmitValueOrZeroIfCondition(state, ctx.Arg(inst, 3), [&]() { const auto pointer = state.builder.AllocateId(); const auto pointer_type = state.builder.Type(OpTypePointer, {StorageClassImage, TypeU32(state)}); state.builder.AddFunction( {OpImageTexelPointer, pointer_type, pointer, - StorageImageDescriptorPointer(state, mem.resource, dimension), + StorageImageDescriptorPointer(state, mem.resource), CoordU32(ctx, mem, *address, dimension), ConstantU32(state, 0)}); const auto old = state.builder.AllocateId(); state.builder.AddFunction({atomic_opcode, TypeU32(state), old, pointer, diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h index d850f72ab..0baa67bbd 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h @@ -482,13 +482,14 @@ struct ImageSampleLayout { uint32_t grad_y = NoImageComponent; }; -constexpr SampledImageClass SampledImageClassFor(IR::ResourceKind kind) { - switch (kind) { - case IR::ResourceKind::Image: return SampledImageClass::Float; - case IR::ResourceKind::ImageUint: return SampledImageClass::Uint; - case IR::ResourceKind::ImageSint: return SampledImageClass::Sint; - default: return SampledImageClass::Count; +constexpr SampledImageClass SampledImageClassFor(Prospero::TextureNumericClass numeric_class) { + switch (numeric_class) { + case Prospero::TextureNumericClass::Float: return SampledImageClass::Float; + case Prospero::TextureNumericClass::Uint: return SampledImageClass::Uint; + case Prospero::TextureNumericClass::Sint: return SampledImageClass::Sint; + case Prospero::TextureNumericClass::Unsupported: return SampledImageClass::Count; } + return SampledImageClass::Count; } constexpr bool IsIntegerSampledImage(SampledImageClass image_class) { @@ -500,16 +501,6 @@ inline uint32_t SampledImageIndex(SampledImageClass image_class, ImageDimension static_cast(image_class) * SampledImageDimensionCount; } -constexpr StorageImageClass StorageImageClassFor(bool uint_image, bool atomic) { - if (atomic) { - return StorageImageClass::AtomicUint; - } - if (uint_image) { - return StorageImageClass::FormatlessUint; - } - return StorageImageClass::FormatlessFloat; -} - inline uint32_t StorageImageIndex(StorageImageClass image_class, ImageDimension dimension) { return ImageDimensionInfoFor(dimension).ordinal + static_cast(image_class) * StorageImageDimensionCount; @@ -667,20 +658,16 @@ uint32_t StorageImageType(EmitterState& state, StorageImageClass image_class, uint32_t StorageImagePointerType(EmitterState& state, StorageImageClass image_class, ImageDimension dimension); -uint32_t LoadSampledImageDescriptor(EmitterState& state, const IR::MemoryInfo& mem, - ImageDimension dimension); +uint32_t LoadSampledImageDescriptor(EmitterState& state, uint32_t resource); uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler); -uint32_t MakeSampledImage(EmitterState& state, const IR::MemoryInfo& mem, ImageDimension dimension); -uint32_t MakeSampledImage(EmitterState& state, const IR::MemoryInfo& mem, ImageDimension dimension, - uint32_t image_resource); +uint32_t MakeSampledImage(EmitterState& state, uint32_t resource, uint32_t sampler); -uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource, - ImageDimension dimension); +uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource); -void EmitStorageImageWrite(EmitterState& state, uint32_t resource, ImageDimension dimension, - uint32_t mip_lod, uint32_t coord, uint32_t texel); +void EmitStorageImageWrite(EmitterState& state, uint32_t resource, uint32_t mip_lod, uint32_t coord, + uint32_t texel); uint32_t ExecutionModelForStage(ShaderType stage); diff --git a/src/graphics/shader/recompiler/frontend/translate/Memory.cpp b/src/graphics/shader/recompiler/frontend/translate/Memory.cpp index 907120a14..e4d2686d2 100644 --- a/src/graphics/shader/recompiler/frontend/translate/Memory.cpp +++ b/src/graphics/shader/recompiler/frontend/translate/Memory.cpp @@ -84,18 +84,7 @@ ResourceKind MemoryKind(const Decoder::Instruction& decoded) { case Decoder::Family::MTBUF: return ResourceKind::Buffer; case Decoder::Family::FLAT: return FlatSegmentResourceKind(decoded.memory_segment); case Decoder::Family::DS: return decoded.gds ? ResourceKind::Gds : ResourceKind::Lds; - case Decoder::Family::MIMG: - switch (decoded.opcode) { - case Decoder::Opcode::IMAGE_STORE: - case Decoder::Opcode::IMAGE_STORE_MIP: return ResourceKind::StorageImage; - case Decoder::Opcode::IMAGE_ATOMIC_ADD: - case Decoder::Opcode::IMAGE_ATOMIC_UMIN: - case Decoder::Opcode::IMAGE_ATOMIC_UMAX: - case Decoder::Opcode::IMAGE_ATOMIC_AND: - case Decoder::Opcode::IMAGE_ATOMIC_OR: - case Decoder::Opcode::IMAGE_ATOMIC_XOR: return ResourceKind::StorageImageUint; - default: return ResourceKind::Image; - } + case Decoder::Family::MIMG: return ResourceKind::Image; default: return ResourceKind::None; } } @@ -153,10 +142,6 @@ IR::MemoryInfo MemoryInfoFromDecoded(const Decoder::Instruction& decoded) { decoded.opcode == Decoder::Opcode::DS_WRITE2ST64_B32) { memory.data_dwords = 2u; } - if (memory.kind == ResourceKind::StorageImage || - memory.kind == ResourceKind::StorageImageUint) { - memory.sampler = 0; - } return memory; } @@ -240,7 +225,10 @@ Decoder::Operand MemorySourceAt(const Decoder::Instruction& decoded, uint32_t in decoded.opcode == Decoder::Opcode::IMAGE_STORE_MIP || (decoded.opcode >= Decoder::Opcode::IMAGE_ATOMIC_ADD && decoded.opcode <= Decoder::Opcode::IMAGE_ATOMIC_XOR); - return store_or_atomic ? (index == 0u ? decoded.dst : decoded.src0) : decoded.src0; + if (store_or_atomic) { + return index == 0u ? decoded.dst : decoded.src0; + } + return decoded.src0; } if (decoded.family == Decoder::Family::DS) { switch (decoded.opcode) { diff --git a/src/graphics/shader/recompiler/ir/Program.cpp b/src/graphics/shader/recompiler/ir/Program.cpp index 27461db47..f1445e017 100644 --- a/src/graphics/shader/recompiler/ir/Program.cpp +++ b/src/graphics/shader/recompiler/ir/Program.cpp @@ -450,7 +450,8 @@ void ValidateProgram(const Program& program, bool require_ssa) { ValueOpcodeName(inst.GetOpcode()))); } const auto& memory = program.memory_info[memory_index]; - if (!ImageResourceKindMatches(memory.kind, image_info.resource_class)) { + if (memory.kind != ResourceKind::Image || + image_info.resource_class == ImageResourceClass::None) { return Fail(fmt::format("{} has invalid image-memory metadata", ValueOpcodeName(inst.GetOpcode()))); } diff --git a/src/graphics/shader/recompiler/ir/ShaderIR.h b/src/graphics/shader/recompiler/ir/ShaderIR.h index 3aa391a59..6a3883773 100644 --- a/src/graphics/shader/recompiler/ir/ShaderIR.h +++ b/src/graphics/shader/recompiler/ir/ShaderIR.h @@ -4,6 +4,7 @@ #include "common/common.h" #include "common/stringUtils.h" #include "graphics/guest_gpu/gpu_defs.h" +#include "graphics/guest_gpu/gpu_format.h" #include "graphics/shader/recompiler/frontend/cfg/ShaderCFG.h" #include "graphics/shader/recompiler/frontend/decode/ShaderDecoder.h" #include "graphics/shader/recompiler/ir/Block.h" @@ -30,10 +31,6 @@ enum class ResourceKind { Lds, Gds, Image, - ImageUint, - ImageSint, - StorageImage, - StorageImageUint, Sampler }; @@ -42,20 +39,6 @@ enum class ResourceKind { kind == ResourceKind::Global || kind == ResourceKind::Scratch; } -[[nodiscard]] constexpr bool ImageResourceKindMatches(ResourceKind kind, - ImageResourceClass resource_class) { - switch (resource_class) { - case ImageResourceClass::Sampled: - return kind == ResourceKind::Image || kind == ResourceKind::ImageUint || - kind == ResourceKind::ImageSint; - case ImageResourceClass::Storage: - return kind == ResourceKind::StorageImage || kind == ResourceKind::StorageImageUint; - case ImageResourceClass::StorageUint: return kind == ResourceKind::StorageImageUint; - case ImageResourceClass::None: return false; - } - return false; -} - struct MemoryInfo { ResourceKind kind = ResourceKind::None; uint32_t resource = 0; @@ -80,7 +63,6 @@ struct MemoryInfo { bool typed = false; bool formatted = false; bool image_has_mip = false; - bool image_cube = false; bool image_r128 = false; bool glc = false; bool slc = false; @@ -140,24 +122,25 @@ constexpr uint32_t ShaderImageIdentitySwizzle = 0x00000facu; struct ImageResource { static constexpr uint32_t NoIndirectImage = UINT32_MAX; - uint32_t source = 0; - uint32_t first_use_pc = 0; - ResourceKind kind = ResourceKind::None; - Decoder::ImageDimension dimension = Decoder::ImageDimension::Unknown; - ImageMipMode mip_mode = ImageMipMode::None; - uint32_t mip_count = 1; - Prospero::BufferFormat conversion_format = Prospero::BufferFormat::kInvalid; - uint32_t shader_swizzle = ShaderImageIdentitySwizzle; - bool read = false; - bool written = false; - 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; - std::vector indirect_resources; + uint32_t source = 0; + uint32_t first_use_pc = 0; + ImageResourceClass resource_class = ImageResourceClass::None; + Prospero::TextureNumericClass numeric_class = Prospero::TextureNumericClass::Unsupported; + Decoder::ImageDimension dimension = Decoder::ImageDimension::Unknown; + ImageMipMode mip_mode = ImageMipMode::None; + uint32_t mip_count = 1; + Prospero::BufferFormat conversion_format = Prospero::BufferFormat::kInvalid; + uint32_t shader_swizzle = ShaderImageIdentitySwizzle; + bool read = false; + bool written = false; + 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; + std::vector indirect_resources; bool operator==(const ImageResource& other) const = default; }; @@ -335,8 +318,34 @@ DescriptorBindingForImage(const ImageResource& image) { using Dimension = Decoder::ImageDimension; using Kind = DescriptorBindingKind; - switch (image.kind) { - case ResourceKind::Image: + switch (image.resource_class) { + case ImageResourceClass::Sampled: + switch (image.numeric_class) { + case Prospero::TextureNumericClass::Float: break; + case Prospero::TextureNumericClass::Uint: + switch (image.dimension) { + case Dimension::Dim1D: return Kind::SampledUint1D; + case Dimension::Dim1DArray: return Kind::SampledUint1DArray; + case Dimension::Dim2D: return Kind::SampledUint2D; + case Dimension::Dim2DArray: return Kind::SampledUint2DArray; + case Dimension::Dim2DMsaa: return Kind::SampledUint2DMsaa; + case Dimension::Dim2DMsaaArray: return Kind::SampledUint2DMsaaArray; + case Dimension::Dim3D: return Kind::SampledUint3D; + default: return std::nullopt; + } + case Prospero::TextureNumericClass::Sint: + switch (image.dimension) { + case Dimension::Dim1D: return Kind::SampledSint1D; + case Dimension::Dim1DArray: return Kind::SampledSint1DArray; + case Dimension::Dim2D: return Kind::SampledSint2D; + case Dimension::Dim2DArray: return Kind::SampledSint2DArray; + case Dimension::Dim2DMsaa: return Kind::SampledSint2DMsaa; + case Dimension::Dim2DMsaaArray: return Kind::SampledSint2DMsaaArray; + case Dimension::Dim3D: return Kind::SampledSint3D; + default: return std::nullopt; + } + case Prospero::TextureNumericClass::Unsupported: return std::nullopt; + } switch (image.dimension) { case Dimension::Dim1D: return Kind::Sampled1D; case Dimension::Dim1DArray: return Kind::Sampled1DArray; @@ -347,71 +356,45 @@ DescriptorBindingForImage(const ImageResource& image) { case Dimension::Dim3D: return Kind::Sampled3D; default: return std::nullopt; } - case ResourceKind::ImageUint: - switch (image.dimension) { - case Dimension::Dim1D: return Kind::SampledUint1D; - case Dimension::Dim1DArray: return Kind::SampledUint1DArray; - case Dimension::Dim2D: return Kind::SampledUint2D; - case Dimension::Dim2DArray: return Kind::SampledUint2DArray; - case Dimension::Dim2DMsaa: return Kind::SampledUint2DMsaa; - case Dimension::Dim2DMsaaArray: return Kind::SampledUint2DMsaaArray; - case Dimension::Dim3D: return Kind::SampledUint3D; - default: return std::nullopt; - } - case ResourceKind::ImageSint: - switch (image.dimension) { - case Dimension::Dim1D: return Kind::SampledSint1D; - case Dimension::Dim1DArray: return Kind::SampledSint1DArray; - case Dimension::Dim2D: return Kind::SampledSint2D; - case Dimension::Dim2DArray: return Kind::SampledSint2DArray; - case Dimension::Dim2DMsaa: return Kind::SampledSint2DMsaa; - case Dimension::Dim2DMsaaArray: return Kind::SampledSint2DMsaaArray; - case Dimension::Dim3D: return Kind::SampledSint3D; - default: return std::nullopt; - } - case ResourceKind::StorageImage: + case ImageResourceClass::Storage: if (image.atomic) { - return std::nullopt; + if (image.numeric_class != Prospero::TextureNumericClass::Uint) { + return std::nullopt; + } + switch (image.dimension) { + case Dimension::Dim1D: return Kind::StorageAtomic1D; + case Dimension::Dim1DArray: return Kind::StorageAtomic1DArray; + case Dimension::Dim2D: return Kind::StorageAtomic2D; + case Dimension::Dim2DArray: return Kind::StorageAtomic2DArray; + case Dimension::Dim3D: return Kind::StorageAtomic3D; + default: return std::nullopt; + } } - switch (image.dimension) { - case Dimension::Dim1D: return Kind::Storage1D; - case Dimension::Dim1DArray: return Kind::Storage1DArray; - case Dimension::Dim2D: return Kind::Storage2D; - case Dimension::Dim2DArray: return Kind::Storage2DArray; - case Dimension::Dim3D: return Kind::Storage3D; - default: return std::nullopt; + switch (image.numeric_class) { + case Prospero::TextureNumericClass::Float: + switch (image.dimension) { + case Dimension::Dim1D: return Kind::Storage1D; + case Dimension::Dim1DArray: return Kind::Storage1DArray; + case Dimension::Dim2D: return Kind::Storage2D; + case Dimension::Dim2DArray: return Kind::Storage2DArray; + case Dimension::Dim3D: return Kind::Storage3D; + default: return std::nullopt; + } + case Prospero::TextureNumericClass::Uint: + switch (image.dimension) { + case Dimension::Dim1D: return Kind::StorageUint1D; + case Dimension::Dim1DArray: return Kind::StorageUint1DArray; + case Dimension::Dim2D: return Kind::StorageUint2D; + case Dimension::Dim2DArray: return Kind::StorageUint2DArray; + case Dimension::Dim3D: return Kind::StorageUint3D; + default: return std::nullopt; + } + case Prospero::TextureNumericClass::Sint: + case Prospero::TextureNumericClass::Unsupported: return std::nullopt; } - case ResourceKind::StorageImageUint: - switch (image.dimension) { - case Dimension::Dim1D: - if (image.atomic) { - return Kind::StorageAtomic1D; - } - return Kind::StorageUint1D; - case Dimension::Dim1DArray: - if (image.atomic) { - return Kind::StorageAtomic1DArray; - } - return Kind::StorageUint1DArray; - case Dimension::Dim2D: - if (image.atomic) { - return Kind::StorageAtomic2D; - } - return Kind::StorageUint2D; - case Dimension::Dim2DArray: - if (image.atomic) { - return Kind::StorageAtomic2DArray; - } - return Kind::StorageUint2DArray; - case Dimension::Dim3D: - if (image.atomic) { - return Kind::StorageAtomic3D; - } - return Kind::StorageUint3D; - default: return std::nullopt; - } - default: return std::nullopt; + case ImageResourceClass::None: return std::nullopt; } + return std::nullopt; } struct DescriptorBinding { diff --git a/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.cpp b/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.cpp index 17676803f..877f194c0 100644 --- a/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.cpp +++ b/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.cpp @@ -210,7 +210,7 @@ ImageOpcodeInfo ImageOpcodeInfoOf(ValueOpcode opcode) { case ValueOpcode::ImageAtomicAnd32: case ValueOpcode::ImageAtomicOr32: case ValueOpcode::ImageAtomicXor32: - return {ImageAccess::Atomic, ImageResourceClass::StorageUint, false}; + return {ImageAccess::Atomic, ImageResourceClass::Storage, false}; default: return {}; } } diff --git a/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.h b/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.h index c6045f8ae..ae3c1dbc7 100644 --- a/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.h +++ b/src/graphics/shader/recompiler/ir/opcodes/ValueOpcodes.h @@ -20,7 +20,7 @@ enum class BufferAccess { None, Read, Write, Atomic }; enum class SharedAccess { None, Read, Write, Atomic, Append, Consume }; enum class AddressAccess { None, Read, Write }; enum class ImageAccess { None, Read, Write, Atomic }; -enum class ImageResourceClass { None, Sampled, Storage, StorageUint }; +enum class ImageResourceClass { None, Sampled, Storage }; struct AddressOpcodeInfo { AddressAccess access = AddressAccess::None; diff --git a/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp b/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp index 1af9b0691..11a494c30 100644 --- a/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp +++ b/src/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp @@ -89,17 +89,8 @@ Prospero::BufferFormat ImageConversionFormat(Prospero::BufferFormat format) { : Prospero::BufferFormat::kInvalid; } -Prospero::TextureNumericClass SampledResourceNumericClass(ResourceKind kind) { - switch (kind) { - case ResourceKind::Image: return Prospero::TextureNumericClass::Float; - case ResourceKind::ImageUint: return Prospero::TextureNumericClass::Uint; - case ResourceKind::ImageSint: return Prospero::TextureNumericClass::Sint; - default: return Prospero::TextureNumericClass::Unsupported; - } -} - bool RequiresPointSampler(const ImageResource& image) { - return image.kind == ResourceKind::ImageSint || + return image.numeric_class == Prospero::TextureNumericClass::Sint || image.conversion_format != Prospero::BufferFormat::kInvalid; } @@ -365,7 +356,8 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh if (image.indirect_root != ImageResource::NoIndirectImage) { const auto root = image.indirect_root; if (root >= program.info.images.size() || - program.info.images[root].kind != image.kind || + program.info.images[root].resource_class != image.resource_class || + program.info.images[root].numeric_class != image.numeric_class || program.info.images[root].dimension != image.dimension || program.info.images[root].mip_mode != image.mip_mode || program.info.images[root].mip_count != image.mip_count || @@ -376,13 +368,11 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh } continue; } - bool canonical_kind = - image.kind == ResourceKind::Image || image.kind == ResourceKind::StorageImage; - if (image.atomic) { - canonical_kind = image.kind == ResourceKind::StorageImageUint; - } + const auto canonical_numeric = image.atomic ? Prospero::TextureNumericClass::Uint + : Prospero::TextureNumericClass::Float; if (image.dimension != Decoder::ImageDimension::Dim2D || image.cube || - !canonical_kind) { + image.resource_class == ImageResourceClass::None || + image.numeric_class != canonical_numeric) { return false; } continue; @@ -392,45 +382,39 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh DescriptorIsCube(descriptor) != image.cube) { return false; } - if (ImageResourceKindMatches(image.kind, ImageResourceClass::Sampled) || - ImageResourceKindMatches(image.kind, ImageResourceClass::Storage)) { - const bool storage = image.kind == ResourceKind::StorageImage || - image.kind == ResourceKind::StorageImageUint; - const auto format = - static_cast((descriptor.dwords[1] >> 20u) & 0x1ffu); - if (image.atomic && format != Prospero::BufferFormat::k32UInt) { + if (image.resource_class == ImageResourceClass::None) { + return false; + } + const bool storage = image.resource_class == ImageResourceClass::Storage; + const auto format = + static_cast((descriptor.dwords[1] >> 20u) & 0x1ffu); + if (image.atomic && format != Prospero::BufferFormat::k32UInt) { + return false; + } + const auto conversion_format = ImageConversionFormat(format); + if (image.conversion_format != conversion_format) { + return false; + } + if ((storage || conversion_format != Prospero::BufferFormat::kInvalid) && + image.shader_swizzle != DescriptorImageSwizzle(descriptor)) { + return false; + } + auto numeric_class = Prospero::SampledTextureNumericClass(format); + if (storage) { + const bool raw_sint = format == Prospero::BufferFormat::k32SInt && image.written && + !image.read && !image.atomic; + if ((!raw_sint && numeric_class == Prospero::TextureNumericClass::Sint) || + numeric_class == Prospero::TextureNumericClass::Unsupported) { return false; } - const auto conversion_format = ImageConversionFormat(format); - if (image.conversion_format != conversion_format) { - return false; - } - if ((storage || conversion_format != Prospero::BufferFormat::kInvalid) && - image.shader_swizzle != DescriptorImageSwizzle(descriptor)) { - return false; - } - if (storage) { - const bool raw_sint = format == Prospero::BufferFormat::k32SInt && image.written && - !image.read && !image.atomic; - const auto numeric_class = Prospero::SampledTextureNumericClass(format); - if ((!raw_sint && numeric_class == Prospero::TextureNumericClass::Sint) || - numeric_class == Prospero::TextureNumericClass::Unsupported) { - return false; - } - const bool uint_descriptor = - numeric_class == Prospero::TextureNumericClass::Uint || raw_sint; - const bool uint_program = image.kind == ResourceKind::StorageImageUint; - if (uint_descriptor != uint_program && !(image.atomic && uint_program)) { - return false; - } - } else { - const auto numeric_class = SampledResourceNumericClass(image.kind); - if (numeric_class != Prospero::SampledTextureNumericClass(format) || - (image.depth_compare && - numeric_class != Prospero::TextureNumericClass::Float)) { - return false; - } + if (raw_sint) { + numeric_class = Prospero::TextureNumericClass::Uint; } + } else if (image.depth_compare && numeric_class != Prospero::TextureNumericClass::Float) { + return false; + } + if (image.numeric_class != numeric_class) { + return false; } } return true; @@ -628,24 +612,20 @@ void SpecializeResources(Program& program, ResourceSnapshot& snapshot) { for (uint32_t i = 0; i < next.images.size(); i++) { const auto& descriptor = next_snapshot.images[i]; auto& image = next.images[i]; + if (image.resource_class == ImageResourceClass::None || + (image.atomic && image.resource_class != ImageResourceClass::Storage)) { + return SpecializationFail(fmt::format("image resource {} has an invalid class", i)); + } image.mip_count = StorageMipCount(image, descriptor); if (image.mip_count == 0u) { return SpecializationFail( fmt::format("storage image descriptor {} has an invalid mip range", i)); } if (NullImageDescriptor(descriptor)) { - image.dimension = Decoder::ImageDimension::Dim2D; - image.cube = false; - switch (image.kind) { - case ResourceKind::ImageUint: image.kind = ResourceKind::Image; break; - case ResourceKind::ImageSint: image.kind = ResourceKind::Image; break; - case ResourceKind::StorageImageUint: - if (!image.atomic) { - image.kind = ResourceKind::StorageImage; - } - break; - default: break; - } + image.numeric_class = image.atomic ? Prospero::TextureNumericClass::Uint + : Prospero::TextureNumericClass::Float; + image.dimension = Decoder::ImageDimension::Dim2D; + image.cube = false; continue; } const auto descriptor_dimension = DescriptorDimension(descriptor, image.dimension); @@ -666,39 +646,30 @@ void SpecializeResources(Program& program, ResourceSnapshot& snapshot) { fmt::format("atomic image descriptor {} uses unsupported format {}", i, static_cast(format))); } - const bool storage = image.kind == ResourceKind::StorageImage || - image.kind == ResourceKind::StorageImageUint; + const bool storage = image.resource_class == ImageResourceClass::Storage; image.conversion_format = ImageConversionFormat(format); if (storage || image.conversion_format != Prospero::BufferFormat::kInvalid) { image.shader_swizzle = DescriptorImageSwizzle(descriptor); } const bool raw_sint_storage = storage && format == Prospero::BufferFormat::k32SInt && image.written && !image.read && !image.atomic; - const auto numeric_class = Prospero::SampledTextureNumericClass(format); + image.numeric_class = Prospero::SampledTextureNumericClass(format); if (storage) { - if ((!raw_sint_storage && numeric_class == Prospero::TextureNumericClass::Sint) || - numeric_class == Prospero::TextureNumericClass::Unsupported) { + if ((!raw_sint_storage && image.numeric_class == Prospero::TextureNumericClass::Sint) || + image.numeric_class == Prospero::TextureNumericClass::Unsupported) { return SpecializationFail( fmt::format("storage image descriptor {} uses unsupported format {}", i, static_cast(format))); } - if (numeric_class == Prospero::TextureNumericClass::Uint || raw_sint_storage) { - image.kind = ResourceKind::StorageImageUint; - } - } else { - switch (numeric_class) { - case Prospero::TextureNumericClass::Uint: - image.kind = ResourceKind::ImageUint; - break; - case Prospero::TextureNumericClass::Sint: - image.kind = ResourceKind::ImageSint; - break; - case Prospero::TextureNumericClass::Float: break; - case Prospero::TextureNumericClass::Unsupported: - return SpecializationFail( - fmt::format("sampled image descriptor {} uses unsupported format {}", i, - static_cast(format))); + if (raw_sint_storage) { + image.numeric_class = Prospero::TextureNumericClass::Uint; } + } else if (image.numeric_class == Prospero::TextureNumericClass::Unsupported || + (image.depth_compare && + image.numeric_class != Prospero::TextureNumericClass::Float)) { + return SpecializationFail( + fmt::format("sampled image descriptor {} uses unsupported format {}", i, + static_cast(format))); } } for (uint32_t root_index = 0; root_index < next.images.size(); root_index++) { @@ -733,14 +704,17 @@ void SpecializeResources(Program& program, ResourceSnapshot& snapshot) { continue; } if (NullImageDescriptor(next_snapshot.images[candidate])) { - image.kind = image_class.kind; + image.resource_class = image_class.resource_class; + image.numeric_class = image_class.numeric_class; image.dimension = image_class.dimension; image.mip_count = image_class.mip_count; image.conversion_format = image_class.conversion_format; image.shader_swizzle = image_class.shader_swizzle; image.cube = image_class.cube; } - if (image.kind != image_class.kind || image.dimension != image_class.dimension || + if (image.resource_class != image_class.resource_class || + image.numeric_class != image_class.numeric_class || + image.dimension != image_class.dimension || image.mip_mode != image_class.mip_mode || image.mip_count != image_class.mip_count || image.conversion_format != image_class.conversion_format || @@ -824,9 +798,6 @@ void SpecializeResources(Program& program, ResourceSnapshot& snapshot) { fmt::format("indirect image table at pc 0x{:08x} is used by unsupported {}", inst.Flags().pc, ValueOpcodeName(inst.GetOpcode()))); } - memory.kind = image.kind; - memory.image_dimension = image.dimension; - memory.image_cube = image.cube; } } program.info = std::move(next); diff --git a/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp b/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp index eb0275ef7..e70462b81 100644 --- a/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp +++ b/src/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp @@ -80,17 +80,6 @@ uint32_t ByteExtent(const MemoryInfo& memory) { return end > UINT32_MAX ? UINT32_MAX : static_cast(end); } -bool IsStorageImage(ResourceKind kind) { - return kind == ResourceKind::StorageImage || kind == ResourceKind::StorageImageUint; -} - -ImageMipMode MipMode(const MemoryInfo& memory) { - if (IsStorageImage(memory.kind) && memory.image_has_mip) { - return ImageMipMode::DynamicStorage; - } - return ImageMipMode::None; -} - class Tracker { public: explicit Tracker(Program& program): m_program(program), m_info(program.info) { @@ -526,18 +515,16 @@ private: } uint32_t AddImage(uint32_t source, const MemoryInfo& memory, ValueOpcode op, uint32_t pc) { - const auto mip = MipMode(memory); + const auto resource_class = ImageOpcodeInfoOf(op).resource_class; + const auto mip = resource_class == ImageResourceClass::Storage && memory.image_has_mip + ? ImageMipMode::DynamicStorage + : ImageMipMode::None; const bool depth = (memory.image_sample_flags & Decoder::ImageSampleFlagCompare) != 0; for (uint32_t i = 0; i < m_info.images.size(); i++) { - auto& image = m_info.images[i]; - const bool compatible_kind = image.kind == memory.kind || (IsStorageImage(image.kind) && - IsStorageImage(memory.kind)); - if (image.source == source && compatible_kind && + auto& image = m_info.images[i]; + if (image.source == source && image.resource_class == resource_class && image.dimension == memory.image_dimension && image.mip_mode == mip && image.depth_compare == depth && image.r128 == memory.image_r128) { - if (memory.kind == ResourceKind::StorageImageUint) { - image.kind = ResourceKind::StorageImageUint; - } Merge(image, op, pc); return i; } @@ -546,13 +533,13 @@ private: return UINT32_MAX; } ImageResource image; - image.source = source; - image.first_use_pc = pc; - image.kind = memory.kind; - image.dimension = memory.image_dimension; - image.mip_mode = mip; - image.depth_compare = depth; - image.r128 = memory.image_r128; + image.source = source; + image.first_use_pc = pc; + image.resource_class = resource_class; + 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); @@ -681,7 +668,8 @@ private: return; } - if (!ImageResourceKindMatches(memory.kind, image_info.resource_class)) { + if (memory.kind != ResourceKind::Image || + image_info.resource_class == ImageResourceClass::None) { Fail(flags.pc, "image operation has invalid resource kind"); } handle = inst.Arg(0).Resolve().TryInstruction(); diff --git a/tests/ResourceTrackingTests.cpp b/tests/ResourceTrackingTests.cpp index 7518592a0..7eaac0947 100644 --- a/tests/ResourceTrackingTests.cpp +++ b/tests/ResourceTrackingTests.cpp @@ -584,7 +584,7 @@ void TestImagesSamplersAndAliases() { const auto storage = fixture.Image(image_words, 16); MemoryInfo storage_memory; - storage_memory.kind = ResourceKind::StorageImageUint; + storage_memory.kind = ResourceKind::Image; storage_memory.image_dimension = Decoder::ImageDimension::Dim2D; fixture.Emit(ValueOpcode::ImageAtomicIAdd32, {storage, image_address, Value(1u), Value(true)}, @@ -713,7 +713,7 @@ void TestDynamicStorageMipTracking() { {Value(0u), Value(0u), lod, Value(0u), Value(0u), Value(0u), Value(0u), Value(0u), Value(0u), Value(0u), Value(0u), Value(0u), Value(0u)}); MemoryInfo memory; - memory.kind = ResourceKind::StorageImage; + memory.kind = ResourceKind::Image; memory.image_dimension = Decoder::ImageDimension::Dim2D; memory.image_address_components = has_mip ? 3u : 2u; memory.image_has_mip = has_mip; @@ -776,7 +776,7 @@ void TestDynamicStorageMipTracking() { Program null_program; null_program.resource_tracking_complete = true; ImageResource null_image; - null_image.kind = ResourceKind::StorageImage; + null_image.resource_class = ImageResourceClass::Storage; null_image.dimension = Decoder::ImageDimension::Dim2D; null_image.mip_mode = ImageMipMode::DynamicStorage; null_image.written = true; @@ -1283,40 +1283,6 @@ void TestMalformedMemoryKindsRejected() { "image operation has invalid resource kind", "resource tracking accepted an image opcode with address metadata"); } - { - Fixture fixture; - const auto image = - fixture.Image({Value(0u), Value(0u), Value(0u), Value(0u), Value(0u), - Value(0u), Value(0u), Value(0u)}, - 12); - MemoryInfo memory; - memory.kind = ResourceKind::StorageImage; - fixture.Emit(ValueOpcode::ImageRead, - {image, fixture.ImageAddress(), Value(true)}, - fixture.AddMemory(memory, 12)); - BuildSrtPlan(fixture.program); - CheckFatal( - [&] { TrackResources(fixture.program); }, - "image operation has invalid resource kind", - "resource tracking accepted a sampled read with storage metadata"); - } - { - Fixture fixture; - const auto image = - fixture.Image({Value(0u), Value(0u), Value(0u), Value(0u), Value(0u), - Value(0u), Value(0u), Value(0u)}, - 16); - MemoryInfo memory; - memory.kind = ResourceKind::StorageImage; - fixture.Emit(ValueOpcode::ImageAtomicIAdd32, - {image, fixture.ImageAddress(), Value(1u), Value(true)}, - fixture.AddMemory(memory, 16)); - BuildSrtPlan(fixture.program); - CheckFatal( - [&] { TrackResources(fixture.program); }, - "image operation has invalid resource kind", - "resource tracking accepted a uint atomic with float storage metadata"); - } } } // namespace diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 2850deee0..289ab407d 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -7721,7 +7721,9 @@ public: null_program.stage = ShaderType::Compute; null_program.resource_tracking_complete = true; ShaderRecompiler::IR::ImageResource null_resource{}; - null_resource.kind = ShaderRecompiler::IR::ResourceKind::ImageUint; + null_resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Sampled; + null_resource.numeric_class = Prospero::TextureNumericClass::Uint; null_resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; null_resource.read = true; @@ -7730,7 +7732,8 @@ public: null_volume.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim3D; null_program.info.images.push_back(null_volume); auto null_storage = null_resource; - null_storage.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint; + null_storage.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Storage; null_storage.read = false; null_storage.written = true; null_program.info.images.push_back(null_storage); @@ -7826,8 +7829,9 @@ public: storage_program.stage = ShaderType::Vertex; storage_program.resource_tracking_complete = true; ShaderRecompiler::IR::ImageResource storage_resource{}; - storage_resource.kind = - ShaderRecompiler::IR::ResourceKind::StorageImageUint; + storage_resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Storage; + storage_resource.numeric_class = Prospero::TextureNumericClass::Uint; storage_resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; storage_resource.written = true; @@ -7870,8 +7874,10 @@ public: ShaderRecompiler::IR::ImageMipMode::DynamicStorage; mipped_storage_resource.mip_count = 3; auto sampled_overwide_resource = storage_resource; - sampled_overwide_resource.kind = - ShaderRecompiler::IR::ResourceKind::ImageUint; + sampled_overwide_resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Sampled; + sampled_overwide_resource.numeric_class = + Prospero::TextureNumericClass::Uint; sampled_overwide_resource.read = true; sampled_overwide_resource.written = false; auto plain_mipped_storage_binding = @@ -7979,8 +7985,10 @@ public: srgb_storage_descriptor.dwords.begin()); srgb_storage_descriptor.dword_count = 8; auto srgb_storage_resource = storage_resource; - srgb_storage_resource.kind = - ShaderRecompiler::IR::ResourceKind::StorageImage; + srgb_storage_resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Storage; + srgb_storage_resource.numeric_class = + Prospero::TextureNumericClass::Float; const auto srgb_storage_binding = RenderExecutorTestAccess::ResolveTexture( executor, srgb_storage_resource, srgb_storage_descriptor); @@ -8023,8 +8031,9 @@ public: sint_storage_descriptor.dwords.begin()); sint_storage_descriptor.dword_count = 8; auto sint_storage_resource = srgb_storage_resource; - sint_storage_resource.kind = - ShaderRecompiler::IR::ResourceKind::StorageImageUint; + sint_storage_resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Storage; + sint_storage_resource.numeric_class = Prospero::TextureNumericClass::Uint; const auto sint_storage_binding = RenderExecutorTestAccess::ResolveTexture( executor, sint_storage_resource, sint_storage_descriptor); @@ -8105,7 +8114,9 @@ public: sampled_program.stage = ShaderType::Pixel; sampled_program.resource_tracking_complete = true; ShaderRecompiler::IR::ImageResource sampled_resource{}; - sampled_resource.kind = ShaderRecompiler::IR::ResourceKind::ImageUint; + sampled_resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Sampled; + sampled_resource.numeric_class = Prospero::TextureNumericClass::Uint; sampled_resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; sampled_resource.read = true; @@ -8551,8 +8562,10 @@ public: sampled_depth_value.dwords.begin()); sampled_depth_value.dword_count = 8; ShaderRecompiler::IR::ImageResource sampled_depth_resource{}; - sampled_depth_resource.kind = - ShaderRecompiler::IR::ResourceKind::ImageUint; + sampled_depth_resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Sampled; + sampled_depth_resource.numeric_class = + Prospero::TextureNumericClass::Uint; sampled_depth_resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; sampled_depth_resource.read = true; @@ -8661,7 +8674,9 @@ public: array_program.stage = ShaderType::Compute; array_program.resource_tracking_complete = true; ShaderRecompiler::IR::ImageResource array_resource{}; - array_resource.kind = ShaderRecompiler::IR::ResourceKind::ImageUint; + array_resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Sampled; + array_resource.numeric_class = Prospero::TextureNumericClass::Uint; array_resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2DArray; array_resource.read = true; @@ -9078,7 +9093,9 @@ public: program.stage = ShaderType::Compute; program.resource_tracking_complete = true; ShaderRecompiler::IR::ImageResource stencil_resource{}; - stencil_resource.kind = ShaderRecompiler::IR::ResourceKind::ImageUint; + stencil_resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Sampled; + stencil_resource.numeric_class = Prospero::TextureNumericClass::Uint; stencil_resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; stencil_resource.read = true; @@ -9151,8 +9168,8 @@ public: stencil_storage_program->stage = ShaderType::Compute; stencil_storage_program->resource_tracking_complete = true; auto stencil_storage_resource = stencil_resource; - stencil_storage_resource.kind = - ShaderRecompiler::IR::ResourceKind::StorageImageUint; + stencil_storage_resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Storage; stencil_storage_resource.read = false; stencil_storage_resource.written = true; stencil_storage_program->info.images.push_back(stencil_storage_resource); @@ -20509,7 +20526,8 @@ void CheckIndirectImageKeySwitch() { ImageResource root{}; root.source = 0; root.first_use_pc = 0x10f0u; - root.kind = ResourceKind::Image; + root.resource_class = ImageResourceClass::Sampled; + root.numeric_class = Prospero::TextureNumericClass::Float; root.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; root.read = true; root.indirect_root = 0; @@ -21963,11 +21981,13 @@ void CheckRenderTargetFormatContract() { (void)volume.FindView(view); } else { ShaderRecompiler::IR::ImageResource resource{}; - resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImage; + resource.resource_class = ShaderRecompiler::IR::ImageResourceClass::Storage; + resource.numeric_class = Prospero::TextureNumericClass::Float; resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; resource.written = true; if (std::strcmp(kind, "storage-kind") == 0) { - resource.kind = ShaderRecompiler::IR::ResourceKind::Image; + resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Sampled; } else if (std::strcmp(kind, "storage-no-write") == 0) { resource.written = false; } else if (std::strcmp(kind, "storage-nonuint-atomic") == 0) { @@ -21992,7 +22012,9 @@ void CheckSampledColorViews() { DstSel(4, 5, 6, 7)) == DstSel(4, 5, 6, 7), "RGBA did not select the identity view"); ShaderRecompiler::IR::ImageResource cube_resource{}; - cube_resource.kind = ShaderRecompiler::IR::ResourceKind::Image; + cube_resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Sampled; + cube_resource.numeric_class = Prospero::TextureNumericClass::Float; cube_resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2DArray; cube_resource.read = true; @@ -22164,7 +22186,9 @@ void CheckSampledColorViews() { DstSel(4, 0, 0, 1)) == DstSel(4, 0, 0, 1), "D32S8 depth target did not select its R001 depth-aspect view"); ShaderRecompiler::IR::ImageResource storage_resource{}; - storage_resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImage; + storage_resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Storage; + storage_resource.numeric_class = Prospero::TextureNumericClass::Float; storage_resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; storage_resource.written = true; Require("SampledColorViews", "storage resource", @@ -22181,7 +22205,7 @@ void CheckSampledColorViews() { Require("SampledColorViews", "write-only 2D-array storage resource", IsSupportedStorageImageResource(storage_resource), "basic write-only 2D-array storage resource was rejected"); - storage_resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint; + storage_resource.numeric_class = Prospero::TextureNumericClass::Uint; Require("SampledColorViews", "write-only uint 2D-array storage resource", IsSupportedStorageImageResource(storage_resource), "basic write-only uint 2D-array storage resource was rejected"); @@ -22237,7 +22261,8 @@ void CheckSampledColorViews() { void CheckSampledDepthResource() { ShaderRecompiler::IR::ImageResource resource{}; - resource.kind = ShaderRecompiler::IR::ResourceKind::Image; + resource.resource_class = ShaderRecompiler::IR::ImageResourceClass::Sampled; + resource.numeric_class = Prospero::TextureNumericClass::Float; resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; resource.read = true; resource.depth_compare = true; @@ -22289,7 +22314,7 @@ void CheckSampledDepthResource() { static_cast(VK_IMAGE_VIEW_TYPE_MAX_ENUM), "array shader resource accepted a non-array descriptor view"); resource = basic; - resource.kind = ShaderRecompiler::IR::ResourceKind::ImageUint; + resource.numeric_class = Prospero::TextureNumericClass::Uint; Require("SampledDepthResource", "integer read", IsSupportedSampledDepthResource(resource), "read-only uint depth resource was rejected"); @@ -22310,7 +22335,8 @@ void CheckSampledVideoOutView(RenderContext &renderer) { auto &context = renderer.GetGraphics(); CommandScheduler scheduler(renderer, context); ShaderRecompiler::IR::ImageResource resource{}; - resource.kind = ShaderRecompiler::IR::ResourceKind::Image; + resource.resource_class = ShaderRecompiler::IR::ImageResourceClass::Sampled; + resource.numeric_class = Prospero::TextureNumericClass::Float; resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; resource.read = true; @@ -22758,7 +22784,9 @@ void CheckSampledDepthDescriptor(RenderContext &renderer) { Prospero::ImageType::kColor2D)); cube_image.usage.depth_target = true; ShaderRecompiler::IR::ImageResource cube_resource{}; - cube_resource.kind = ShaderRecompiler::IR::ResourceKind::Image; + cube_resource.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Sampled; + cube_resource.numeric_class = Prospero::TextureNumericClass::Float; cube_resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2DArray; cube_resource.read = true; @@ -22845,7 +22873,8 @@ void CheckSampledDepthDescriptor(RenderContext &renderer) { ShaderRecompiler::IR::ImageResource BasicStorageTextureResource() { ShaderRecompiler::IR::ImageResource resource{}; - resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImage; + resource.resource_class = ShaderRecompiler::IR::ImageResourceClass::Storage; + resource.numeric_class = Prospero::TextureNumericClass::Float; resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim3D; resource.read = true; resource.written = true; @@ -22903,7 +22932,7 @@ ShaderTextureResource Ppsa01340OverwideMipStorageTextureDescriptor() { ShaderRecompiler::IR::ImageResource Ppsa01530MaxMipStorageTextureResource() { auto resource = BasicBgraStorageTextureResource(); - resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint; + resource.numeric_class = Prospero::TextureNumericClass::Uint; return resource; } @@ -22940,7 +22969,7 @@ ShaderTextureResource BasicArrayStorageTextureDescriptor() { ShaderRecompiler::IR::ImageResource BasicUintArrayStorageTextureResource() { auto resource = BasicArrayStorageTextureResource(); - resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint; + resource.numeric_class = Prospero::TextureNumericClass::Uint; return resource; } @@ -22975,7 +23004,7 @@ ShaderTextureResource Ppsa10112D16StorageTextureDescriptor() { ShaderRecompiler::IR::ImageResource BasicUintVolumeStorageTextureResource() { auto resource = BasicStorageTextureResource(); - resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint; + resource.numeric_class = Prospero::TextureNumericClass::Uint; resource.read = false; return resource; } @@ -22987,7 +23016,7 @@ ShaderTextureResource BasicUintVolumeStorageTextureDescriptor() { ShaderRecompiler::IR::ImageResource AtomicStorageTextureResource() { auto resource = BasicLinearStorageTextureResource(); - resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint; + resource.numeric_class = Prospero::TextureNumericClass::Uint; resource.read = true; resource.atomic = true; return resource; @@ -23346,8 +23375,7 @@ void CheckBasicStorageTextureDescriptor() { 0x00000000u, }}; auto standard256b_resource = BasicBgraStorageTextureResource(); - standard256b_resource.kind = - ShaderRecompiler::IR::ResourceKind::StorageImageUint; + standard256b_resource.numeric_class = Prospero::TextureNumericClass::Uint; TileSizeAlign standard256b_size{}; TileGetTextureTotalSize(standard256b.Format(), standard256b.Width5() + 1u, standard256b.Height5() + 1u, @@ -23645,7 +23673,8 @@ void CheckImageSamplerSpecialization() { ShaderRecompiler::IR::Program mixed_sampler_program; mixed_sampler_program.resource_tracking_complete = true; ShaderRecompiler::IR::ImageResource sampled_image; - sampled_image.kind = ShaderRecompiler::IR::ResourceKind::Image; + sampled_image.resource_class = + ShaderRecompiler::IR::ImageResourceClass::Sampled; sampled_image.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; sampled_image.read = true; mixed_sampler_program.info.images = {sampled_image, sampled_image, @@ -23739,7 +23768,8 @@ void CheckShaderRecompilerFatalContracts() { program.resource_tracking_complete = true; ShaderRecompiler::IR::ImageResource image; - image.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint; + image.resource_class = ShaderRecompiler::IR::ImageResourceClass::Storage; + image.numeric_class = Prospero::TextureNumericClass::Uint; image.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; image.read = true; image.written = true; diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index c2a67b009..d0d88ace5 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -9792,46 +9792,6 @@ void TestNativeWideValueValidation() { append_image(program, ValueOpcode::ImageRead, {}); check_rejected(program, "buffer kind for image read was accepted"); } - { - auto program = make_program(); - MemoryInfo memory; - memory.kind = ResourceKind::StorageImage; - program.memory_info.push_back(memory); - append_image(program, ValueOpcode::ImageRead, {}); - check_rejected(program, "storage kind for image read was accepted"); - } - { - auto program = make_program(); - MemoryInfo memory; - memory.kind = ResourceKind::StorageImageUint; - program.memory_info.push_back(memory); - append_image(program, ValueOpcode::ImageQueryDimensions, {}); - check_rejected(program, "storage uint kind for image query was accepted"); - } - { - auto program = make_program(); - MemoryInfo memory; - memory.kind = ResourceKind::Image; - program.memory_info.push_back(memory); - append_image(program, ValueOpcode::ImageWrite, {}); - check_rejected(program, "sampled image kind for image write was accepted"); - } - { - auto program = make_program(); - MemoryInfo memory; - memory.kind = ResourceKind::StorageImage; - program.memory_info.push_back(memory); - append_image(program, ValueOpcode::ImageSampleRaw, {}); - check_rejected(program, "storage kind for image sample was accepted"); - } - { - auto program = make_program(); - MemoryInfo memory; - memory.kind = ResourceKind::StorageImage; - program.memory_info.push_back(memory); - append_image(program, ValueOpcode::ImageAtomicIAdd32, {}); - check_rejected(program, "untyped storage kind for image atomic was accepted"); - } { auto program = make_program(); IREmitter ir(program.blocks.front()); @@ -10435,8 +10395,10 @@ void TestNewShaderRecompilerNativeBindingPlan() { uint32_t float_storage = UINT32_MAX; for (uint32_t i = 0; i < result.program.info.images.size(); i++) { - if (result.program.info.images[i].kind == - ShaderRecompiler::IR::ResourceKind::StorageImage) { + const auto &image = result.program.info.images[i]; + if (image.resource_class == + ShaderRecompiler::IR::ImageResourceClass::Storage && + image.numeric_class == Prospero::TextureNumericClass::Float) { float_storage = i; break; }