From 93be8c201b14c588290f4a53c9ee8a431d751383 Mon Sep 17 00:00:00 2001 From: nmzik Date: Wed, 2 Sep 2026 10:51:13 +0400 Subject: [PATCH] shader: unify SPIR-V image dimension --- .../backend/spirv/spirvEmitterAnalysis.cpp | 181 ++++++------- .../backend/spirv/spirvEmitterImage.cpp | 161 +++++------ .../backend/spirv/spirvEmitterInternal.h | 251 ++++++++---------- .../spirv/spirvEmitterMemoryHelpers.cpp | 10 +- .../backend/spirv/spirvEmitterModule.cpp | 32 +-- 5 files changed, 290 insertions(+), 345 deletions(-) diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAnalysis.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAnalysis.cpp index 8d0af795c..80bc52ccd 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAnalysis.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterAnalysis.cpp @@ -86,8 +86,8 @@ uint32_t ConstantU32(EmitterState& state, uint32_t value); std::abort(); } -DescriptorResourceBinding ResourceForDescriptor(const EmitterState& state, - IR::DescriptorBindingKind kind, uint32_t resource) { +uint32_t ResourceForDescriptor(const EmitterState& state, IR::DescriptorBindingKind kind, + uint32_t resource) { const auto* descriptor = IR::FindBinding(state.program.bindings, kind); if (descriptor == nullptr) { ExitDescriptorBindingFailure(state, kind, resource, "descriptor group was not allocated"); @@ -98,7 +98,7 @@ DescriptorResourceBinding ResourceForDescriptor(const EmitterState& state, ExitDescriptorBindingFailure(state, kind, resource, "resource is absent from descriptor group"); } - return {descriptor, static_cast(found - descriptor->resources.begin())}; + return static_cast(found - descriptor->resources.begin()); } uint32_t DescriptorElementPointer(EmitterState& state, uint32_t result_ptr_type, @@ -114,53 +114,14 @@ uint32_t DescriptorElementPointer(EmitterState& state, uint32_t result_ptr_type, return pointer; } -ImageViewKind ImageViewKindFromDimension(Decoder::ImageDimension dimension) { - switch (dimension) { - case Decoder::ImageDimension::Dim1D: return ImageViewKind::Dim1D; - case Decoder::ImageDimension::Dim1DArray: return ImageViewKind::Dim1DArray; - case Decoder::ImageDimension::Dim2DArray: return ImageViewKind::Dim2DArray; - case Decoder::ImageDimension::Dim3D: return ImageViewKind::Dim3D; - case Decoder::ImageDimension::Dim2DMsaa: return ImageViewKind::Dim2DMsaa; - case Decoder::ImageDimension::Dim2DMsaaArray: return ImageViewKind::Dim2DMsaaArray; - default: return ImageViewKind::Dim2D; - } -} - -ImageViewKind SampledImageViewKind(const EmitterState& state, const IR::MemoryInfo& mem, - uint32_t use_pc) { - (void)state; - (void)use_pc; - return ImageViewKindFromDimension(mem.image_dimension); -} - -ImageViewKind StorageImageViewKind(const IR::MemoryInfo& mem) { - return ImageViewKindFromDimension(mem.image_dimension); -} - -uint32_t ImageViewCoordinateComponents(ImageViewKind view) { - switch (view) { - case ImageViewKind::Dim1D: return 1u; - case ImageViewKind::Dim1DArray: - case ImageViewKind::Dim2D: return 2u; - case ImageViewKind::Dim2DArray: - case ImageViewKind::Dim2DMsaaArray: - case ImageViewKind::Dim3D: return 3u; - case ImageViewKind::Dim2DMsaa: return 2u; - default: return 0u; - } -} - -uint32_t ImageViewSpatialComponents(ImageViewKind view) { - switch (view) { - case ImageViewKind::Dim1D: - case ImageViewKind::Dim1DArray: return 1u; - case ImageViewKind::Dim2D: - case ImageViewKind::Dim2DArray: - case ImageViewKind::Dim2DMsaa: - case ImageViewKind::Dim2DMsaaArray: return 2u; - case ImageViewKind::Dim3D: return 3u; - default: return 0u; +const ImageDimensionInfo& ImageDimensionInfoFor(ImageDimension dimension) { + for (const auto& info: ImageDimensions) { + if (info.dimension == dimension) { + return info; + } } + EXIT("SPIR-V image dimension %u is invalid\n", static_cast(dimension)); + std::abort(); } uint32_t SampledImageScalarType(EmitterState& state, SampledImageClass image_class) { @@ -179,20 +140,22 @@ uint32_t SampledImageVectorType(EmitterState& state, SampledImageClass image_cla {SampledImageScalarType(state, image_class), components}); } -uint32_t ImageViewImageType(EmitterState& state, ImageViewKind view, +uint32_t ImageViewImageType(EmitterState& state, ImageDimension dimension, SampledImageClass image_class) { - return state.builder.Type(OpTypeImage, {SampledImageScalarType(state, image_class), - ImageSpirvDimension(view), 0, ImageSpirvArrayed(view), - ImageSpirvMultisampled(view), 1, ImageFormatUnknown}); + const auto& info = ImageDimensionInfoFor(dimension); + return state.builder.Type(OpTypeImage, + {SampledImageScalarType(state, image_class), info.spirv_dimension, 0, + info.arrayed, info.multisampled, 1, ImageFormatUnknown}); } -uint32_t ImageViewSampledImageType(EmitterState& state, ImageViewKind view, +uint32_t ImageViewSampledImageType(EmitterState& state, ImageDimension dimension, SampledImageClass image_class) { - return state.builder.Type(OpTypeSampledImage, {ImageViewImageType(state, view, image_class)}); + return state.builder.Type(OpTypeSampledImage, + {ImageViewImageType(state, dimension, image_class)}); } -uint32_t ImageViewSizeType(EmitterState& state, ImageViewKind view) { - switch (ImageViewCoordinateComponents(view)) { +uint32_t ImageViewSizeType(EmitterState& state, ImageDimension dimension) { + switch (ImageDimensionInfoFor(dimension).coordinate_components) { case 1u: return TypeU32(state); case 2u: return TypeU32Vector(state, 2); case 3u: return TypeU32Vector(state, 3); @@ -200,7 +163,8 @@ uint32_t ImageViewSizeType(EmitterState& state, ImageViewKind view) { } } -uint32_t StorageImageType(EmitterState& state, StorageImageClass image_class, ImageViewKind view) { +uint32_t StorageImageType(EmitterState& state, StorageImageClass image_class, + ImageDimension dimension) { uint32_t component = TypeF32(state); uint32_t format = ImageFormatUnknown; if (image_class == StorageImageClass::FormatlessUint) { @@ -209,14 +173,15 @@ uint32_t StorageImageType(EmitterState& state, StorageImageClass image_class, Im component = TypeU32(state); format = ImageFormatR32ui; } - return state.builder.Type(OpTypeImage, {component, ImageSpirvDimension(view), 0, - ImageSpirvArrayed(view), 0, 2, format}); + const auto& info = ImageDimensionInfoFor(dimension); + return state.builder.Type(OpTypeImage, + {component, info.spirv_dimension, 0, info.arrayed, 0, 2, format}); } uint32_t StorageImagePointerType(EmitterState& state, StorageImageClass image_class, - ImageViewKind view) { - return state.builder.Type( - OpTypePointer, {StorageClassUniformConstant, StorageImageType(state, image_class, view)}); + ImageDimension dimension) { + return state.builder.Type(OpTypePointer, {StorageClassUniformConstant, + StorageImageType(state, image_class, dimension)}); } StorageImageClass StorageImageClassForResource(const EmitterState& state, uint32_t resource) { @@ -228,96 +193,98 @@ StorageImageClass StorageImageClassForResource(const EmitterState& state, uint32 } uint32_t StorageImageVariable(const EmitterState& state, StorageImageClass image_class, - ImageViewKind view) { - return state.storage_image_variables[StorageImageIndex(image_class, view)]; + ImageDimension dimension) { + return state.storage_image_variables[StorageImageIndex(image_class, dimension)]; } -uint32_t LoadSampledImageDescriptor(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc, - ImageViewKind view) { - (void)use_pc; - const auto image_class = SampledImageClassFor(mem.kind); - const auto kind = SampledBindingKind(image_class, view); - const auto binding = ResourceForDescriptor(state, kind, mem.resource); - const auto variable = state.sampled_image_variables[SampledImageIndex(image_class, view)]; - const auto pointer_type = state.builder.Type( - OpTypePointer, {StorageClassUniformConstant, ImageViewImageType(state, view, image_class)}); +uint32_t LoadSampledImageDescriptor(EmitterState& state, const IR::MemoryInfo& mem, + ImageDimension dimension) { + const auto image_class = SampledImageClassFor(mem.kind); + const auto kind = SampledBindingKind(image_class, dimension); + const auto array_index = ResourceForDescriptor(state, kind, mem.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, binding.array_index, kind, - mem.resource, "sampled image descriptor array was not emitted"); + DescriptorElementPointer(state, pointer_type, variable, array_index, kind, mem.resource, + "sampled image descriptor array was not emitted"); const auto image = state.builder.AllocateId(); state.builder.AddFunction( - {OpLoad, ImageViewImageType(state, view, image_class), image, pointer}); + {OpLoad, ImageViewImageType(state, dimension, image_class), image, pointer}); return image; } -uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler, uint32_t use_pc) { - (void)use_pc; - const auto binding = ResourceForDescriptor(state, IR::DescriptorBindingKind::Samplers, sampler); +uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler) { + const auto array_index = + ResourceForDescriptor(state, IR::DescriptorBindingKind::Samplers, sampler); const auto sampler_type = state.builder.Type(OpTypeSampler); const auto pointer_type = state.builder.Type(OpTypePointer, {StorageClassUniformConstant, sampler_type}); const auto pointer = DescriptorElementPointer( - state, pointer_type, state.sampler_variable, binding.array_index, + state, pointer_type, state.sampler_variable, array_index, IR::DescriptorBindingKind::Samplers, sampler, "sampler descriptor array was not emitted"); const auto sampler_id = state.builder.AllocateId(); state.builder.AddFunction({OpLoad, sampler_type, sampler_id, pointer}); return sampler_id; } -uint32_t MakeSampledImage(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc, - ImageViewKind view) { - const auto image = LoadSampledImageDescriptor(state, mem, use_pc, view); - const auto sampler = LoadSamplerDescriptor(state, mem.sampler, use_pc); +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), view), mem.resource, + state, SampledBindingKind(SampledImageClassFor(mem.kind), dimension), mem.resource, "sampled image or sampler descriptor load failed"); } const auto sampled_image = state.builder.AllocateId(); state.builder.AddFunction( - {OpSampledImage, ImageViewSampledImageType(state, view, SampledImageClassFor(mem.kind)), - sampled_image, image, sampler}); + {OpSampledImage, + ImageViewSampledImageType(state, dimension, SampledImageClassFor(mem.kind)), sampled_image, + image, sampler}); return sampled_image; } -uint32_t MakeSampledImage(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc, - ImageViewKind view, uint32_t image_resource) { +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, use_pc, view); + return MakeSampledImage(state, selected, dimension); } -uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource, ImageViewKind view) { +uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource, + ImageDimension dimension) { const auto image_class = StorageImageClassForResource(state, resource); - const auto kind = StorageBindingKind(image_class, view); - const auto binding = ResourceForDescriptor(state, kind, resource); - const auto ptr_type = StorageImagePointerType(state, image_class, view); - const auto variable = StorageImageVariable(state, image_class, view); - return DescriptorElementPointer(state, ptr_type, variable, binding.array_index, kind, 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); + return DescriptorElementPointer(state, ptr_type, variable, array_index, kind, resource, "storage image descriptor array was not emitted"); } -void EmitStorageImageWrite(EmitterState& state, uint32_t resource, ImageViewKind view, +void EmitStorageImageWrite(EmitterState& state, uint32_t resource, ImageDimension dimension, uint32_t mip_lod, uint32_t coord, uint32_t texel) { const auto image_class = StorageImageClassForResource(state, resource); if (image_class != StorageImageClass::AtomicUint) { state.builder.RequireCapability(CapabilityStorageImageWriteWithoutFormat); } - const auto kind = StorageBindingKind(image_class, view); - const auto binding = ResourceForDescriptor(state, kind, resource); - const auto& image = state.program.info.images.at(resource); - const auto LoadAt = [&](uint32_t array_index) { + const auto kind = StorageBindingKind(image_class, dimension); + const auto array_index = ResourceForDescriptor(state, kind, resource); + const auto& image = state.program.info.images.at(resource); + const auto LoadAt = [&](uint32_t array_index) { const auto pointer = DescriptorElementPointer( - state, StorageImagePointerType(state, image_class, view), - StorageImageVariable(state, image_class, view), array_index, kind, resource, + state, StorageImagePointerType(state, image_class, dimension), + StorageImageVariable(state, 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, view), descriptor, pointer}); + {OpLoad, StorageImageType(state, image_class, dimension), descriptor, pointer}); return descriptor; }; if (image.mip_mode != IR::ImageMipMode::DynamicStorage) { - state.builder.AddFunction({OpImageWrite, LoadAt(binding.array_index), coord, texel}); + state.builder.AddFunction({OpImageWrite, LoadAt(array_index), coord, texel}); return; } if (image.mip_count == 0u) { @@ -337,7 +304,7 @@ void EmitStorageImageWrite(EmitterState& state, uint32_t resource, ImageViewKind state.builder.AddFunction(words); for (uint32_t mip = 0; mip < image.mip_count; mip++) { EmitLabel(state, labels[mip]); - state.builder.AddFunction({OpImageWrite, LoadAt(binding.array_index + mip), coord, texel}); + state.builder.AddFunction({OpImageWrite, LoadAt(array_index + mip), coord, texel}); state.builder.AddFunction({OpBranch, merge_label}); } EmitLabel(state, merge_label); diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp index 3bc907920..2ca9aff83 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterImage.cpp @@ -103,20 +103,21 @@ uint32_t AddressF32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR:: : Unary(ctx.state, OpBitcast, TypeF32(ctx.state), value); } -ImageSampleLayout Layout(const IR::MemoryInfo& mem, ImageViewKind view) { +ImageSampleLayout Layout(const IR::MemoryInfo& mem, ImageDimension dimension) { ImageSampleLayout layout; uint32_t cursor = 0; + const auto& info = ImageDimensionInfoFor(dimension); if (HasFlag(mem, Decoder::ImageSampleFlagOffset)) layout.offset = cursor++; if (HasFlag(mem, Decoder::ImageSampleFlagBias)) layout.bias = cursor++; if (HasFlag(mem, Decoder::ImageSampleFlagCompare)) layout.dref = cursor++; if (HasFlag(mem, Decoder::ImageSampleFlagDerivative)) { layout.grad_x = cursor; - cursor += ImageViewSpatialComponents(view); + cursor += info.spatial_components; layout.grad_y = cursor; - cursor += ImageViewSpatialComponents(view); + cursor += info.spatial_components; } layout.coord = cursor; - cursor += ImageViewCoordinateComponents(view); + cursor += info.coordinate_components; if (HasFlag(mem, Decoder::ImageSampleFlagLod)) layout.lod = cursor++; return layout; } @@ -168,8 +169,8 @@ uint32_t CoordF32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::In } uint32_t CoordU32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::Inst& address, - ImageViewKind view) { - const auto components = ImageViewCoordinateComponents(view); + ImageDimension dimension) { + const auto components = ImageDimensionInfoFor(dimension).coordinate_components; const auto x = AddressU32(ctx, mem, address, 0); if (components == 1u) return x; const auto y = mem.image_address_components > 1u ? AddressU32(ctx, mem, address, 1) @@ -188,8 +189,8 @@ uint32_t CoordU32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::In } uint32_t LodU32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::Inst& address, - ImageViewKind view) { - const auto component = ImageViewCoordinateComponents(view); + ImageDimension dimension) { + const auto component = ImageDimensionInfoFor(dimension).coordinate_components; return mem.image_has_mip && mem.image_address_components > component ? AddressU32(ctx, mem, address, component) : ConstantU32(ctx.state, 0); @@ -281,20 +282,20 @@ uint32_t ResultVector(ValueEmitContext& ctx, uint32_t value, SampledImageClass i return result; } -uint32_t QueryDimensions(ValueEmitContext& ctx, const IR::Inst& inst, const IR::MemoryInfo& mem, +uint32_t QueryDimensions(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::Inst& address) { - const auto pc = inst.Flags().pc; - const auto view = SampledImageViewKind(ctx.state, mem, pc); - const auto image = LoadSampledImageDescriptor(ctx.state, mem, pc, view); - const auto size = ctx.state.builder.AllocateId(); - if (ImageSpirvMultisampled(view) != 0u) { + const auto dimension = mem.image_dimension; + const auto& info = ImageDimensionInfoFor(dimension); + const auto image = LoadSampledImageDescriptor(ctx.state, mem, dimension); + const auto size = ctx.state.builder.AllocateId(); + if (info.multisampled != 0u) { ctx.state.builder.AddFunction( - {OpImageQuerySize, ImageViewSizeType(ctx.state, view), size, image}); + {OpImageQuerySize, ImageViewSizeType(ctx.state, dimension), size, image}); } else { - ctx.state.builder.AddFunction({OpImageQuerySizeLod, ImageViewSizeType(ctx.state, view), + ctx.state.builder.AddFunction({OpImageQuerySizeLod, ImageViewSizeType(ctx.state, dimension), size, image, AddressU32(ctx, mem, address, 0)}); } - const auto components = ImageViewCoordinateComponents(view); + const auto components = info.coordinate_components; uint32_t result[4] = {ConstantU32(ctx.state, 0), ConstantU32(ctx.state, 0), ConstantU32(ctx.state, 0), ConstantU32(ctx.state, 0)}; if (components == 1u) { @@ -306,7 +307,7 @@ uint32_t QueryDimensions(ValueEmitContext& ctx, const IR::Inst& inst, const IR:: {OpCompositeExtract, TypeU32(ctx.state), result[index], size, index}); } } - if (ImageSpirvMultisampled(view) == 0u) { + if (info.multisampled == 0u) { result[3] = ctx.state.builder.AllocateId(); ctx.state.builder.AddFunction({OpImageQueryLevels, TypeU32(ctx.state), result[3], image}); } @@ -317,8 +318,8 @@ uint32_t QueryDimensions(ValueEmitContext& ctx, const IR::Inst& inst, const IR:: } uint32_t PackedOffset(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::Inst& address, - const ImageSampleLayout& layout, ImageViewKind view) { - const auto components = ImageViewSpatialComponents(view); + const ImageSampleLayout& layout, ImageDimension dimension) { + const auto components = ImageDimensionInfoFor(dimension).spatial_components; const auto zero = ConstantI32(ctx.state, 0); if (layout.offset == NoImageComponent || mem.image_address_components <= layout.offset) { if (components == 1u) return zero; @@ -353,8 +354,8 @@ uint32_t PackedOffset(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR return result; } -uint32_t HorizontalOffsets(EmitterState& state, ImageViewKind view) { - const auto components = ImageViewSpatialComponents(view); +uint32_t HorizontalOffsets(EmitterState& state, ImageDimension dimension) { + const auto components = ImageDimensionInfoFor(dimension).spatial_components; const auto count = ConstantU32(state, 4); const auto element_type = components == 1u ? TypeI32(state) : TypeI32Vector(state, 2); const auto array_type = state.builder.Type(OpTypeArray, {element_type, count}); @@ -459,46 +460,46 @@ uint32_t UnpackImageGather(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uin return result; } -uint32_t EmitOneDimensionalGatherLz(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint32_t pc, +uint32_t EmitOneDimensionalGatherLz(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint32_t coord, SampledImageClass image_class) { auto& state = ctx.state; state.builder.RequireCapability(CapabilityImageQuery); - const auto image = LoadSampledImageDescriptor(state, mem, pc, ImageViewKind::Dim1D); + const auto image = LoadSampledImageDescriptor(state, mem, ImageDimension::Dim1D); const auto width = state.builder.AllocateId(); state.builder.AddFunction( {OpImageQuerySizeLod, TypeU32(state), width, image, ConstantU32(state, 0)}); const auto width_f32 = state.builder.AllocateId(); state.builder.AddFunction({OpConvertUToF, TypeF32(state), width_f32, width}); const auto left = state.builder.AllocateId(); - state.builder.AddFunction( - {OpExtInst, TypeF32(state), left, GlslStd450(state), GlslFloor, - Binary(state, OpFSub, TypeF32(state), - Binary(state, OpFMul, TypeF32(state), coord, width_f32), - ConstantF32(state, 0x3f000000u))}); + state.builder.AddFunction({OpExtInst, TypeF32(state), left, GlslStd450(state), GlslFloor, + Binary(state, OpFSub, TypeF32(state), + Binary(state, OpFMul, TypeF32(state), coord, width_f32), + ConstantF32(state, 0x3f000000u))}); - const auto sampled = MakeSampledImage(state, mem, pc, ImageViewKind::Dim1D); + const auto sampled = MakeSampledImage(state, mem, ImageDimension::Dim1D); const auto vector_type = SampledImageVectorType(state, image_class, 4); const auto scalar_type = SampledImageScalarType(state, image_class); - const auto component = ImageConversionFormat(state, mem).format == Prospero::BufferFormat::kInvalid - ? ImageGatherComponent(mem.dmask) - : 0u; + const auto component = + ImageConversionFormat(state, mem).format == Prospero::BufferFormat::kInvalid + ? ImageGatherComponent(mem.dmask) + : 0u; uint32_t values[2] {}; for (uint32_t index = 0; index < 2u; index++) { - const auto sample_coord = Binary( - state, OpFDiv, TypeF32(state), - Binary(state, OpFAdd, TypeF32(state), left, - ConstantF32(state, index == 0u ? 0x3f000000u : 0x3fc00000u)), - width_f32); + const auto sample_coord = + Binary(state, OpFDiv, TypeF32(state), + Binary(state, OpFAdd, TypeF32(state), left, + ConstantF32(state, index == 0u ? 0x3f000000u : 0x3fc00000u)), + width_f32); const auto texel = state.builder.AllocateId(); - state.builder.AddFunction({OpImageSampleExplicitLod, vector_type, texel, sampled, sample_coord, - ImageOperandsLodMask, ZeroF32(state)}); + state.builder.AddFunction({OpImageSampleExplicitLod, vector_type, texel, sampled, + sample_coord, ImageOperandsLodMask, ZeroF32(state)}); values[index] = state.builder.AllocateId(); state.builder.AddFunction( {OpCompositeExtract, scalar_type, values[index], texel, component}); } const auto result = state.builder.AllocateId(); - state.builder.AddFunction({OpCompositeConstruct, vector_type, result, values[0], values[1], - values[1], values[0]}); + state.builder.AddFunction( + {OpCompositeConstruct, vector_type, result, values[0], values[1], values[1], values[0]}); return result; } @@ -589,24 +590,23 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { } auto& state = ctx.state; const auto& mem = ctx.Memory(inst); - const auto pc = inst.Flags().pc; const auto image_arg = inst.Arg(0); ctx.ResourceIndex(image_arg, IR::ValueOpcode::GetImageResource); const auto* address = ctx.ImageAddress(inst.Arg(image_info.needs_sampler ? 2 : 1)); if (address == nullptr) return true; if (op == IR::ValueOpcode::ImageQueryDimensions) { state.builder.RequireCapability(CapabilityImageQuery); - ctx.Define(inst, QueryDimensions(ctx, inst, mem, *address)); + ctx.Define(inst, QueryDimensions(ctx, mem, *address)); return true; } if (op == IR::ValueOpcode::ImageQueryLod) { state.builder.RequireCapability(CapabilityImageQuery); - const auto view = SampledImageViewKind(state, mem, pc); - const auto sampled = MakeSampledImage(state, mem, pc, view); - const auto lod = state.builder.AllocateId(); + const auto dimension = mem.image_dimension; + const auto sampled = MakeSampledImage(state, mem, dimension); + const auto lod = state.builder.AllocateId(); state.builder.AddFunction( {OpImageQueryLod, TypeF32Vector(state, 2), lod, sampled, - CoordF32(ctx, mem, *address, 0, ImageViewSpatialComponents(view))}); + CoordF32(ctx, mem, *address, 0, ImageDimensionInfoFor(dimension).spatial_components)}); uint32_t values[4] = {ConstantU32(state, 0), ConstantU32(state, 0), ConstantU32(state, 0), ConstantU32(state, 0)}; for (uint32_t index = 0; index < 2u; index++) { @@ -621,26 +621,28 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { return true; } if (op == IR::ValueOpcode::ImageRead) { - const auto view = SampledImageViewKind(state, mem, pc); - const auto image_class = SampledImageClassFor(mem.kind); - const auto condition = ctx.Arg(inst, 2); + const auto dimension = mem.image_dimension; + const auto& dimension_info = ImageDimensionInfoFor(dimension); + const auto image_class = SampledImageClassFor(mem.kind); + 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, pc, view); + const auto image = LoadSampledImageDescriptor(state, mem, dimension); const auto color = state.builder.AllocateId(); - const auto coord = CoordU32(ctx, mem, *address, view); - if (ImageSpirvMultisampled(view) != 0u) { + 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, - AddressU32(ctx, mem, *address, ImageViewCoordinateComponents(view))}); + AddressU32(ctx, mem, *address, dimension_info.coordinate_components)}); } else { - state.builder.AddFunction( - {OpImageFetch, SampledImageVectorType(state, image_class, 4), color, - image, coord, ImageOperandsLodMask, LodU32(ctx, mem, *address, view)}); + state.builder.AddFunction({OpImageFetch, + SampledImageVectorType(state, image_class, 4), + color, image, coord, ImageOperandsLodMask, + LodU32(ctx, mem, *address, dimension)}); } return ResultVector(ctx, UnpackImageTexel(ctx, mem, color), image_class, false, mem); @@ -649,48 +651,49 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { } if (op == IR::ValueOpcode::ImageWrite) { const auto uint_image = mem.kind == IR::ResourceKind::StorageImageUint; - const auto view = StorageImageViewKind(mem); + const auto dimension = mem.image_dimension; EmitIfCondition(state, ctx.Arg(inst, 3), [&]() { const auto mip_lod = state.program.info.images[mem.resource].mip_mode == IR::ImageMipMode::DynamicStorage - ? LodU32(ctx, mem, *address, view) + ? LodU32(ctx, mem, *address, dimension) : 0u; - const auto coord = CoordU32(ctx, mem, *address, view); + const auto coord = CoordU32(ctx, mem, *address, dimension); const auto texel = StoreTexel(ctx, mem, ctx.Arg(inst, 2), uint_image); - EmitStorageImageWrite(state, mem.resource, view, mip_lod, coord, texel); + EmitStorageImageWrite(state, mem.resource, dimension, mip_lod, coord, texel); }); return true; } if (op == IR::ValueOpcode::ImageSampleRaw || op == IR::ValueOpcode::ImageGatherRaw) { - const auto view = SampledImageViewKind(state, mem, pc); - const auto layout = Layout(mem, view); - const auto image_class = SampledImageClassFor(mem.kind); - const bool dref = HasFlag(mem, Decoder::ImageSampleFlagCompare); + const auto dimension = mem.image_dimension; + const auto& dimension_info = ImageDimensionInfoFor(dimension); + const auto layout = Layout(mem, dimension); + const auto image_class = SampledImageClassFor(mem.kind); + const bool dref = HasFlag(mem, Decoder::ImageSampleFlagCompare); if (dref && state.program.info.images[mem.resource].conversion_format != Prospero::BufferFormat::kInvalid) { ctx.Fail(inst, "uses depth comparison with a packed integer image"); return true; } const auto coord = - CoordF32(ctx, mem, *address, layout.coord, ImageViewCoordinateComponents(view)); + CoordF32(ctx, mem, *address, layout.coord, dimension_info.coordinate_components); if (op == IR::ValueOpcode::ImageGatherRaw) { - if (view == ImageViewKind::Dim1D) { + if (dimension == ImageDimension::Dim1D) { if (dref || !HasFlag(mem, Decoder::ImageSampleFlagLevelZero) || HasFlag(mem, Decoder::ImageSampleFlagOffset) || HasFlag(mem, Decoder::ImageSampleFlagGatherHorizontal)) { ctx.Fail(inst, "has an unsupported 1D gather variant"); return true; } - const auto sample = EmitOneDimensionalGatherLz(ctx, mem, pc, coord, image_class); + const auto sample = EmitOneDimensionalGatherLz(ctx, mem, coord, image_class); ctx.Define(inst, ResultVector(ctx, UnpackImageGather(ctx, mem, sample), image_class, false, mem, true)); return true; } - if (view == ImageViewKind::Dim1DArray) { + if (dimension == ImageDimension::Dim1DArray) { ctx.Fail(inst, "has an unsupported 1D-array gather"); return true; } - const auto sampled = MakeSampledImage(state, mem, pc, view); + const auto sampled = MakeSampledImage(state, mem, dimension); const auto sample = state.builder.AllocateId(); std::vector words = dref ? std::vector {OpImageDrefGather, @@ -713,10 +716,10 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { : 0u)}; if (HasFlag(mem, Decoder::ImageSampleFlagGatherHorizontal)) { words.push_back(ImageOperandsConstOffsetsMask); - words.push_back(HorizontalOffsets(state, view)); + words.push_back(HorizontalOffsets(state, dimension)); } else if (layout.offset != NoImageComponent) { words.push_back(ImageOperandsOffsetMask); - words.push_back(PackedOffset(ctx, mem, *address, layout, view)); + words.push_back(PackedOffset(ctx, mem, *address, layout, dimension)); } state.builder.AddFunction(words); ctx.Define(inst, ResultVector(ctx, UnpackImageGather(ctx, mem, sample), @@ -742,9 +745,9 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { if (HasFlag(mem, Decoder::ImageSampleFlagDerivative)) { operand_mask |= ImageOperandsGradMask; operands.push_back( - CoordF32(ctx, mem, *address, layout.grad_x, ImageViewSpatialComponents(view))); + CoordF32(ctx, mem, *address, layout.grad_x, dimension_info.spatial_components)); operands.push_back( - CoordF32(ctx, mem, *address, layout.grad_y, ImageViewSpatialComponents(view))); + CoordF32(ctx, mem, *address, layout.grad_y, dimension_info.spatial_components)); } else if (explicit_lod) { operand_mask |= ImageOperandsLodMask; operands.push_back(HasFlag(mem, Decoder::ImageSampleFlagLod) && @@ -756,7 +759,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, pc, view, resource); + const auto sampled = MakeSampledImage(state, mem, dimension, resource); const auto sample = state.builder.AllocateId(); std::vector words {opcode, result_type, sample, sampled, coord}; if (dref) { @@ -871,15 +874,15 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) { } const auto atomic_opcode = ImageAtomicOpcode(op); if (atomic_opcode != 0u) { - const auto view = StorageImageViewKind(mem); + const auto dimension = mem.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, view), - CoordU32(ctx, mem, *address, view), ConstantU32(state, 0)}); + StorageImageDescriptorPointer(state, mem.resource, dimension), + CoordU32(ctx, mem, *address, dimension), ConstantU32(state, 0)}); const auto old = state.builder.AllocateId(); state.builder.AddFunction({atomic_opcode, TypeU32(state), old, pointer, ConstantU32(state, ScopeDevice), diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h index 158785948..d850f72ab 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInternal.h @@ -6,7 +6,6 @@ #include "graphics/shader/recompiler/BufferFormat.h" #include "graphics/shader/recompiler/backend/spirv/SpirvBuilder.h" #include "graphics/shader/recompiler/ir/ShaderIR.h" -#include "graphics/shader/recompiler/ir/ShaderIR.h" #include "graphics/shader/recompiler/ir/passes/BindingLayout.h" #include "graphics/shader/recompiler/ir/passes/ResourceMaterialization.h" @@ -318,24 +317,32 @@ struct OutputBinding { std::string debug_name; }; -struct DescriptorResourceBinding { - const IR::DescriptorBinding* descriptor = nullptr; - uint32_t array_index = 0; +using ImageDimension = Decoder::ImageDimension; + +struct ImageDimensionInfo { + ImageDimension dimension; + uint32_t ordinal; + uint32_t spirv_dimension; + uint32_t coordinate_components; + uint32_t spatial_components; + uint32_t arrayed; + uint32_t multisampled; }; -enum class ImageViewKind { - Dim1D, - Dim1DArray, - Dim2D, - Dim2DArray, - Dim3D, - Dim2DMsaa, - Dim2DMsaaArray, - Count, -}; +constexpr std::array ImageDimensions {{ + {ImageDimension::Dim1D, 0, Dim1D, 1, 1, 0, 0}, + {ImageDimension::Dim1DArray, 1, Dim1D, 2, 1, 1, 0}, + {ImageDimension::Dim2D, 2, Dim2D, 2, 2, 0, 0}, + {ImageDimension::Dim2DArray, 3, Dim2D, 3, 2, 1, 0}, + {ImageDimension::Dim3D, 4, Dim3D, 3, 3, 0, 0}, + {ImageDimension::Dim2DMsaa, 5, Dim2D, 2, 2, 0, 1}, + {ImageDimension::Dim2DMsaaArray, 6, Dim2D, 3, 2, 1, 1}, +}}; -constexpr uint32_t SampledImageViewKindCount = static_cast(ImageViewKind::Count); -constexpr uint32_t StorageImageViewKindCount = static_cast(ImageViewKind::Dim2DMsaa); +constexpr uint32_t SampledImageDimensionCount = ImageDimensions.size(); +constexpr uint32_t StorageImageDimensionCount = 5; + +const ImageDimensionInfo& ImageDimensionInfoFor(ImageDimension dimension); enum class SampledImageClass : uint32_t { Float, Uint, Sint, Count }; @@ -352,30 +359,30 @@ struct EmitterState { : program(program_), resources(resources_), input_info(input_info_), requirements(*program_.spirv_requirements) {} - Builder builder; - const IR::Program& program; - const IR::ResourceSnapshot& resources; - ShaderStageInputInfo input_info; - const IR::SpirvRequirements& requirements; - ShaderType stage = ShaderType::Unknown; - uint32_t wave_size = 64; - uint32_t storage_buffer_variable = 0; - std::array memory_byte_offsets {}; - uint32_t bda_pagetable_variable = 0; - uint32_t fault_buffer_variable = 0; - uint32_t bda_pointer_function = 0; - uint32_t gds_variable = 0; - uint32_t gds_length = 0; - uint32_t push_constant_variable = 0; - uint32_t vsharp_storage_variable = 0; - uint32_t flattened_srt_variable = 0; - uint32_t lds_variable = 0; - uint32_t scratch_variable = 0; + Builder builder; + const IR::Program& program; + const IR::ResourceSnapshot& resources; + ShaderStageInputInfo input_info; + const IR::SpirvRequirements& requirements; + ShaderType stage = ShaderType::Unknown; + uint32_t wave_size = 64; + uint32_t storage_buffer_variable = 0; + std::array memory_byte_offsets {}; + uint32_t bda_pagetable_variable = 0; + uint32_t fault_buffer_variable = 0; + uint32_t bda_pointer_function = 0; + uint32_t gds_variable = 0; + uint32_t gds_length = 0; + uint32_t push_constant_variable = 0; + uint32_t vsharp_storage_variable = 0; + uint32_t flattened_srt_variable = 0; + uint32_t lds_variable = 0; + uint32_t scratch_variable = 0; std::array(SampledImageClass::Count) * SampledImageViewKindCount> + static_cast(SampledImageClass::Count) * SampledImageDimensionCount> sampled_image_variables {}; std::array(StorageImageClass::Count) * StorageImageViewKindCount> + static_cast(StorageImageClass::Count) * StorageImageDimensionCount> storage_image_variables {}; uint32_t sampler_variable = 0; uint32_t main_func = 0; @@ -447,7 +454,7 @@ struct ValueEmitContext { [[noreturn]] void Fail(const IR::Inst& inst, const char* reason) const; EmitterState& state; - const IR::Program& program; + const IR::Program& program; std::unordered_map definitions; std::unordered_map labels; const std::unordered_map* dispatcher_spills = nullptr; @@ -488,9 +495,9 @@ constexpr bool IsIntegerSampledImage(SampledImageClass image_class) { return image_class == SampledImageClass::Uint || image_class == SampledImageClass::Sint; } -constexpr uint32_t SampledImageIndex(SampledImageClass image_class, ImageViewKind view) { - return static_cast(view) + - static_cast(image_class) * SampledImageViewKindCount; +inline uint32_t SampledImageIndex(SampledImageClass image_class, ImageDimension dimension) { + return ImageDimensionInfoFor(dimension).ordinal + + static_cast(image_class) * SampledImageDimensionCount; } constexpr StorageImageClass StorageImageClassFor(bool uint_image, bool atomic) { @@ -503,86 +510,86 @@ constexpr StorageImageClass StorageImageClassFor(bool uint_image, bool atomic) { return StorageImageClass::FormatlessFloat; } -constexpr uint32_t StorageImageIndex(StorageImageClass image_class, ImageViewKind view) { - return static_cast(view) + - static_cast(image_class) * StorageImageViewKindCount; +inline uint32_t StorageImageIndex(StorageImageClass image_class, ImageDimension dimension) { + return ImageDimensionInfoFor(dimension).ordinal + + static_cast(image_class) * StorageImageDimensionCount; } constexpr IR::DescriptorBindingKind SampledBindingKind(SampledImageClass image_class, - ImageViewKind view) { + ImageDimension dimension) { if (image_class == SampledImageClass::Uint) { - switch (view) { - case ImageViewKind::Dim1D: return IR::DescriptorBindingKind::SampledUint1D; - case ImageViewKind::Dim1DArray: return IR::DescriptorBindingKind::SampledUint1DArray; - case ImageViewKind::Dim2D: return IR::DescriptorBindingKind::SampledUint2D; - case ImageViewKind::Dim2DArray: return IR::DescriptorBindingKind::SampledUint2DArray; - case ImageViewKind::Dim3D: return IR::DescriptorBindingKind::SampledUint3D; - case ImageViewKind::Dim2DMsaa: return IR::DescriptorBindingKind::SampledUint2DMsaa; - case ImageViewKind::Dim2DMsaaArray: + switch (dimension) { + case ImageDimension::Dim1D: return IR::DescriptorBindingKind::SampledUint1D; + case ImageDimension::Dim1DArray: return IR::DescriptorBindingKind::SampledUint1DArray; + case ImageDimension::Dim2D: return IR::DescriptorBindingKind::SampledUint2D; + case ImageDimension::Dim2DArray: return IR::DescriptorBindingKind::SampledUint2DArray; + case ImageDimension::Dim3D: return IR::DescriptorBindingKind::SampledUint3D; + case ImageDimension::Dim2DMsaa: return IR::DescriptorBindingKind::SampledUint2DMsaa; + case ImageDimension::Dim2DMsaaArray: return IR::DescriptorBindingKind::SampledUint2DMsaaArray; default: break; } } if (image_class == SampledImageClass::Sint) { - switch (view) { - case ImageViewKind::Dim1D: return IR::DescriptorBindingKind::SampledSint1D; - case ImageViewKind::Dim1DArray: return IR::DescriptorBindingKind::SampledSint1DArray; - case ImageViewKind::Dim2D: return IR::DescriptorBindingKind::SampledSint2D; - case ImageViewKind::Dim2DArray: return IR::DescriptorBindingKind::SampledSint2DArray; - case ImageViewKind::Dim3D: return IR::DescriptorBindingKind::SampledSint3D; - case ImageViewKind::Dim2DMsaa: return IR::DescriptorBindingKind::SampledSint2DMsaa; - case ImageViewKind::Dim2DMsaaArray: + switch (dimension) { + case ImageDimension::Dim1D: return IR::DescriptorBindingKind::SampledSint1D; + case ImageDimension::Dim1DArray: return IR::DescriptorBindingKind::SampledSint1DArray; + case ImageDimension::Dim2D: return IR::DescriptorBindingKind::SampledSint2D; + case ImageDimension::Dim2DArray: return IR::DescriptorBindingKind::SampledSint2DArray; + case ImageDimension::Dim3D: return IR::DescriptorBindingKind::SampledSint3D; + case ImageDimension::Dim2DMsaa: return IR::DescriptorBindingKind::SampledSint2DMsaa; + case ImageDimension::Dim2DMsaaArray: return IR::DescriptorBindingKind::SampledSint2DMsaaArray; default: break; } } - switch (view) { - case ImageViewKind::Dim1D: return IR::DescriptorBindingKind::Sampled1D; - case ImageViewKind::Dim1DArray: return IR::DescriptorBindingKind::Sampled1DArray; - case ImageViewKind::Dim2D: return IR::DescriptorBindingKind::Sampled2D; - case ImageViewKind::Dim2DArray: return IR::DescriptorBindingKind::Sampled2DArray; - case ImageViewKind::Dim3D: return IR::DescriptorBindingKind::Sampled3D; - case ImageViewKind::Dim2DMsaa: return IR::DescriptorBindingKind::Sampled2DMsaa; - case ImageViewKind::Dim2DMsaaArray: return IR::DescriptorBindingKind::Sampled2DMsaaArray; + switch (dimension) { + case ImageDimension::Dim1D: return IR::DescriptorBindingKind::Sampled1D; + case ImageDimension::Dim1DArray: return IR::DescriptorBindingKind::Sampled1DArray; + case ImageDimension::Dim2D: return IR::DescriptorBindingKind::Sampled2D; + case ImageDimension::Dim2DArray: return IR::DescriptorBindingKind::Sampled2DArray; + case ImageDimension::Dim3D: return IR::DescriptorBindingKind::Sampled3D; + case ImageDimension::Dim2DMsaa: return IR::DescriptorBindingKind::Sampled2DMsaa; + case ImageDimension::Dim2DMsaaArray: return IR::DescriptorBindingKind::Sampled2DMsaaArray; default: break; } return IR::DescriptorBindingKind::Count; } constexpr IR::DescriptorBindingKind StorageBindingKind(StorageImageClass image_class, - ImageViewKind view) { + ImageDimension dimension) { switch (image_class) { case StorageImageClass::FormatlessFloat: - switch (view) { - case ImageViewKind::Dim1D: return IR::DescriptorBindingKind::Storage1D; - case ImageViewKind::Dim1DArray: return IR::DescriptorBindingKind::Storage1DArray; - case ImageViewKind::Dim2D: return IR::DescriptorBindingKind::Storage2D; - case ImageViewKind::Dim2DArray: return IR::DescriptorBindingKind::Storage2DArray; - case ImageViewKind::Dim3D: return IR::DescriptorBindingKind::Storage3D; + switch (dimension) { + case ImageDimension::Dim1D: return IR::DescriptorBindingKind::Storage1D; + case ImageDimension::Dim1DArray: return IR::DescriptorBindingKind::Storage1DArray; + case ImageDimension::Dim2D: return IR::DescriptorBindingKind::Storage2D; + case ImageDimension::Dim2DArray: return IR::DescriptorBindingKind::Storage2DArray; + case ImageDimension::Dim3D: return IR::DescriptorBindingKind::Storage3D; default: break; } break; case StorageImageClass::FormatlessUint: - switch (view) { - case ImageViewKind::Dim1D: return IR::DescriptorBindingKind::StorageUint1D; - case ImageViewKind::Dim1DArray: + switch (dimension) { + case ImageDimension::Dim1D: return IR::DescriptorBindingKind::StorageUint1D; + case ImageDimension::Dim1DArray: return IR::DescriptorBindingKind::StorageUint1DArray; - case ImageViewKind::Dim2D: return IR::DescriptorBindingKind::StorageUint2D; - case ImageViewKind::Dim2DArray: + case ImageDimension::Dim2D: return IR::DescriptorBindingKind::StorageUint2D; + case ImageDimension::Dim2DArray: return IR::DescriptorBindingKind::StorageUint2DArray; - case ImageViewKind::Dim3D: return IR::DescriptorBindingKind::StorageUint3D; + case ImageDimension::Dim3D: return IR::DescriptorBindingKind::StorageUint3D; default: break; } break; case StorageImageClass::AtomicUint: - switch (view) { - case ImageViewKind::Dim1D: return IR::DescriptorBindingKind::StorageAtomic1D; - case ImageViewKind::Dim1DArray: + switch (dimension) { + case ImageDimension::Dim1D: return IR::DescriptorBindingKind::StorageAtomic1D; + case ImageDimension::Dim1DArray: return IR::DescriptorBindingKind::StorageAtomic1DArray; - case ImageViewKind::Dim2D: return IR::DescriptorBindingKind::StorageAtomic2D; - case ImageViewKind::Dim2DArray: + case ImageDimension::Dim2D: return IR::DescriptorBindingKind::StorageAtomic2D; + case ImageDimension::Dim2DArray: return IR::DescriptorBindingKind::StorageAtomic2DArray; - case ImageViewKind::Dim3D: return IR::DescriptorBindingKind::StorageAtomic3D; + case ImageDimension::Dim3D: return IR::DescriptorBindingKind::StorageAtomic3D; default: break; } break; @@ -591,31 +598,6 @@ constexpr IR::DescriptorBindingKind StorageBindingKind(StorageImageClass image_c return IR::DescriptorBindingKind::Count; } -constexpr uint32_t ImageSpirvDimension(ImageViewKind view) { - switch (view) { - case ImageViewKind::Dim1D: - case ImageViewKind::Dim1DArray: return Dim1D; - case ImageViewKind::Dim2D: - case ImageViewKind::Dim2DArray: - case ImageViewKind::Dim2DMsaa: - case ImageViewKind::Dim2DMsaaArray: - case ImageViewKind::Count: return Dim2D; - case ImageViewKind::Dim3D: return Dim3D; - } - return Dim2D; -} - -constexpr uint32_t ImageSpirvArrayed(ImageViewKind view) { - return view == ImageViewKind::Dim1DArray || view == ImageViewKind::Dim2DArray || - view == ImageViewKind::Dim2DMsaaArray - ? 1u - : 0u; -} - -constexpr uint32_t ImageSpirvMultisampled(ImageViewKind view) { - return view == ImageViewKind::Dim2DMsaa || view == ImageViewKind::Dim2DMsaaArray ? 1u : 0u; -} - struct F32Class { uint32_t bits = 0; uint32_t nan = 0; @@ -658,53 +640,46 @@ uint32_t EmitSubgroupLocalInvocationId(EmitterState& state); IR::DescriptorBindingKind kind, uint32_t resource, const char* reason); -DescriptorResourceBinding ResourceForDescriptor(const EmitterState& state, - IR::DescriptorBindingKind kind, uint32_t resource); +uint32_t ResourceForDescriptor(const EmitterState& state, IR::DescriptorBindingKind kind, + uint32_t resource); uint32_t DescriptorElementPointer(EmitterState& state, uint32_t result_ptr_type, uint32_t variable_id, uint32_t array_index, IR::DescriptorBindingKind kind, uint32_t resource, const char* variable_name); -ImageViewKind SampledImageViewKind(const EmitterState& state, const IR::MemoryInfo& mem, - uint32_t use_pc); - -uint32_t ImageViewCoordinateComponents(ImageViewKind view); - -uint32_t ImageViewSpatialComponents(ImageViewKind view); - uint32_t SampledImageScalarType(EmitterState& state, SampledImageClass image_class); uint32_t SampledImageVectorType(EmitterState& state, SampledImageClass image_class, uint32_t components); -uint32_t ImageViewImageType(EmitterState& state, ImageViewKind view, SampledImageClass image_class); +uint32_t ImageViewImageType(EmitterState& state, ImageDimension dimension, + SampledImageClass image_class); -uint32_t ImageViewSampledImageType(EmitterState& state, ImageViewKind view, +uint32_t ImageViewSampledImageType(EmitterState& state, ImageDimension dimension, SampledImageClass image_class); -uint32_t ImageViewSizeType(EmitterState& state, ImageViewKind view); +uint32_t ImageViewSizeType(EmitterState& state, ImageDimension dimension); -uint32_t StorageImageType(EmitterState& state, StorageImageClass image_class, ImageViewKind view); +uint32_t StorageImageType(EmitterState& state, StorageImageClass image_class, + ImageDimension dimension); uint32_t StorageImagePointerType(EmitterState& state, StorageImageClass image_class, - ImageViewKind view); + ImageDimension dimension); -uint32_t LoadSampledImageDescriptor(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc, - ImageViewKind view); +uint32_t LoadSampledImageDescriptor(EmitterState& state, const IR::MemoryInfo& mem, + ImageDimension dimension); -uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler, uint32_t use_pc); +uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler); -uint32_t MakeSampledImage(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc, - ImageViewKind view); -uint32_t MakeSampledImage(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc, - ImageViewKind view, uint32_t image_resource); +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); -ImageViewKind StorageImageViewKind(const IR::MemoryInfo& mem); +uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource, + ImageDimension dimension); -uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource, ImageViewKind view); - -void EmitStorageImageWrite(EmitterState& state, uint32_t resource, ImageViewKind view, +void EmitStorageImageWrite(EmitterState& state, uint32_t resource, ImageDimension dimension, uint32_t mip_lod, uint32_t coord, uint32_t texel); uint32_t ExecutionModelForStage(ShaderType stage); diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemoryHelpers.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemoryHelpers.cpp index a877d59db..943035c10 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemoryHelpers.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterMemoryHelpers.cpp @@ -117,15 +117,15 @@ MemoryResourceAccess PrepareMemoryResourceAccess(EmitterState& state, const IR:: mem.resource, "storage buffer descriptor array was not emitted"); } - const auto binding = + const auto array_index = ResourceForDescriptor(state, IR::DescriptorBindingKind::Buffers, mem.resource); access.object_pointer = state.builder.AllocateId(); state.builder.AddFunction({OpAccessChain, TypeStorageBufferPointer(state), access.object_pointer, state.storage_buffer_variable, - ConstantU32(state, binding.array_index)}); - access.index_offset = EmitBinaryU32(state, OpShiftRightLogical, - state.memory_byte_offsets[binding.array_index], - ConstantU32(state, 2u)); + ConstantU32(state, array_index)}); + access.index_offset = + EmitBinaryU32(state, OpShiftRightLogical, state.memory_byte_offsets[array_index], + ConstantU32(state, 2u)); access.add_index_offset = true; break; } diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterModule.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterModule.cpp index 6010cf263..8cce6e202 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterModule.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterModule.cpp @@ -188,36 +188,36 @@ void DefineDescriptorVariables(EmitterState& state) { TypeStorageBufferPointer(state), StorageClassStorageBuffer); } for (uint32_t i = 0; i < state.sampled_image_variables.size(); i++) { - const auto view = static_cast(i % SampledImageViewKindCount); - const auto image_class = static_cast(i / SampledImageViewKindCount); - const auto kind = SampledBindingKind(image_class, view); + const auto dimension = ImageDimensions[i % SampledImageDimensionCount].dimension; + const auto image_class = static_cast(i / SampledImageDimensionCount); + const auto kind = SampledBindingKind(image_class, dimension); if (DescriptorBinding(state, kind) == nullptr) { continue; } const auto count = ConstantU32(state, DescriptorCount(state, kind)); - const auto image_type = ImageViewImageType(state, view, image_class); + const auto image_type = ImageViewImageType(state, dimension, image_class); const auto array_type = state.builder.Type(OpTypeArray, {image_type, count}); const auto pointer_type = TypePointer(state, StorageClassUniformConstant, array_type); state.sampled_image_variables[i] = state.builder.DefineGlobalVariable(pointer_type, StorageClassUniformConstant); - if (view == ImageViewKind::Dim1D || view == ImageViewKind::Dim1DArray) { + if (dimension == ImageDimension::Dim1D || dimension == ImageDimension::Dim1DArray) { state.builder.RequireCapability(CapabilitySampled1D); } } for (uint32_t i = 0; i < state.storage_image_variables.size(); i++) { - const auto view = static_cast(i % StorageImageViewKindCount); - const auto image_class = static_cast(i / StorageImageViewKindCount); - const auto kind = StorageBindingKind(image_class, view); + const auto dimension = ImageDimensions[i % StorageImageDimensionCount].dimension; + const auto image_class = static_cast(i / StorageImageDimensionCount); + const auto kind = StorageBindingKind(image_class, dimension); if (DescriptorBinding(state, kind) == nullptr) { continue; } const auto count = ConstantU32(state, DescriptorCount(state, kind)); - const auto image_type = StorageImageType(state, image_class, view); + const auto image_type = StorageImageType(state, image_class, dimension); const auto array_type = state.builder.Type(OpTypeArray, {image_type, count}); const auto pointer_type = TypePointer(state, StorageClassUniformConstant, array_type); state.storage_image_variables[i] = state.builder.DefineGlobalVariable(pointer_type, StorageClassUniformConstant); - if (view == ImageViewKind::Dim1D || view == ImageViewKind::Dim1DArray) { + if (dimension == ImageDimension::Dim1D || dimension == ImageDimension::Dim1DArray) { state.builder.RequireCapability(CapabilityImage1D); } } @@ -616,10 +616,10 @@ void AddDescriptorAnnotationsAndNames(EmitterState& state) { "sampled_sint_2d_msaa", "sampled_sint_2d_msaa_array"}; for (uint32_t i = 0; i < state.sampled_image_variables.size(); i++) { - const auto view = static_cast(i % SampledImageViewKindCount); - const auto image_class = static_cast(i / SampledImageViewKindCount); + const auto dimension = ImageDimensions[i % SampledImageDimensionCount].dimension; + const auto image_class = static_cast(i / SampledImageDimensionCount); Decorate(state.sampled_image_variables[i], SampledNames[i], - SampledBindingKind(image_class, view)); + SampledBindingKind(image_class, dimension)); } constexpr const char* StorageNames[] = {"storage_1d", "storage_1d_array", @@ -637,10 +637,10 @@ void AddDescriptorAnnotationsAndNames(EmitterState& state) { "storage_atomic_2d_array", "storage_atomic_3d"}; for (uint32_t i = 0; i < state.storage_image_variables.size(); i++) { - const auto view = static_cast(i % StorageImageViewKindCount); - const auto image_class = static_cast(i / StorageImageViewKindCount); + const auto dimension = ImageDimensions[i % StorageImageDimensionCount].dimension; + const auto image_class = static_cast(i / StorageImageDimensionCount); Decorate(state.storage_image_variables[i], StorageNames[i], - StorageBindingKind(image_class, view)); + StorageBindingKind(image_class, dimension)); } if (state.sampler_variable != 0) { Decorate(state.sampler_variable, "samplers", IR::DescriptorBindingKind::Samplers);