shader: unify SPIR-V image dimension

This commit is contained in:
nmzik
2026-09-02 10:51:13 +04:00
parent 894bc7de3c
commit 93be8c201b
5 changed files with 290 additions and 345 deletions
@@ -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<uint32_t>(found - descriptor->resources.begin())};
return static_cast<uint32_t>(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<uint32_t>(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);
@@ -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<IR::MemoryFlags>().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<IR::MemoryFlags>().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<uint32_t> words =
dref ? std::vector<uint32_t> {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<uint32_t> 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),
@@ -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<ImageDimensionInfo, 7> 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<uint32_t>(ImageViewKind::Count);
constexpr uint32_t StorageImageViewKindCount = static_cast<uint32_t>(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<uint32_t, IR::ShaderInfo::MaxBuffers> 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<uint32_t, IR::ShaderInfo::MaxBuffers> 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<uint32_t,
static_cast<uint32_t>(SampledImageClass::Count) * SampledImageViewKindCount>
static_cast<uint32_t>(SampledImageClass::Count) * SampledImageDimensionCount>
sampled_image_variables {};
std::array<uint32_t,
static_cast<uint32_t>(StorageImageClass::Count) * StorageImageViewKindCount>
static_cast<uint32_t>(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<const IR::Inst*, uint32_t> definitions;
std::unordered_map<const IR::Block*, uint32_t> labels;
const std::unordered_map<const IR::Inst*, uint32_t>* 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<uint32_t>(view) +
static_cast<uint32_t>(image_class) * SampledImageViewKindCount;
inline uint32_t SampledImageIndex(SampledImageClass image_class, ImageDimension dimension) {
return ImageDimensionInfoFor(dimension).ordinal +
static_cast<uint32_t>(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<uint32_t>(view) +
static_cast<uint32_t>(image_class) * StorageImageViewKindCount;
inline uint32_t StorageImageIndex(StorageImageClass image_class, ImageDimension dimension) {
return ImageDimensionInfoFor(dimension).ordinal +
static_cast<uint32_t>(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);
@@ -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;
}
@@ -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<ImageViewKind>(i % SampledImageViewKindCount);
const auto image_class = static_cast<SampledImageClass>(i / SampledImageViewKindCount);
const auto kind = SampledBindingKind(image_class, view);
const auto dimension = ImageDimensions[i % SampledImageDimensionCount].dimension;
const auto image_class = static_cast<SampledImageClass>(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<ImageViewKind>(i % StorageImageViewKindCount);
const auto image_class = static_cast<StorageImageClass>(i / StorageImageViewKindCount);
const auto kind = StorageBindingKind(image_class, view);
const auto dimension = ImageDimensions[i % StorageImageDimensionCount].dimension;
const auto image_class = static_cast<StorageImageClass>(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<ImageViewKind>(i % SampledImageViewKindCount);
const auto image_class = static_cast<SampledImageClass>(i / SampledImageViewKindCount);
const auto dimension = ImageDimensions[i % SampledImageDimensionCount].dimension;
const auto image_class = static_cast<SampledImageClass>(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<ImageViewKind>(i % StorageImageViewKindCount);
const auto image_class = static_cast<StorageImageClass>(i / StorageImageViewKindCount);
const auto dimension = ImageDimensions[i % StorageImageDimensionCount].dimension;
const auto image_class = static_cast<StorageImageClass>(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);