mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 11:26:56 +02:00
shader: simplify typed image bindings
This commit is contained in:
@@ -124,34 +124,42 @@ const ImageDimensionInfo& ImageDimensionInfoFor(ImageDimension dimension) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
uint32_t SampledImageScalarType(EmitterState& state, SampledImageClass image_class) {
|
||||
switch (image_class) {
|
||||
case SampledImageClass::Float: return TypeF32(state);
|
||||
case SampledImageClass::Uint: return TypeU32(state);
|
||||
case SampledImageClass::Sint: return TypeI32(state);
|
||||
case SampledImageClass::Count: break;
|
||||
uint32_t ImageScalarType(EmitterState& state, Prospero::TextureNumericClass numeric_class) {
|
||||
switch (numeric_class) {
|
||||
case Prospero::TextureNumericClass::Float: return TypeF32(state);
|
||||
case Prospero::TextureNumericClass::Uint: return TypeU32(state);
|
||||
case Prospero::TextureNumericClass::Sint: return TypeI32(state);
|
||||
case Prospero::TextureNumericClass::Unsupported: break;
|
||||
}
|
||||
return 0;
|
||||
EXIT("invalid image numeric class");
|
||||
}
|
||||
|
||||
uint32_t SampledImageVectorType(EmitterState& state, SampledImageClass image_class,
|
||||
uint32_t components) {
|
||||
return state.builder.Type(OpTypeVector,
|
||||
{SampledImageScalarType(state, image_class), components});
|
||||
uint32_t ImageVectorType(EmitterState& state, Prospero::TextureNumericClass numeric_class,
|
||||
uint32_t components) {
|
||||
return state.builder.Type(OpTypeVector, {ImageScalarType(state, numeric_class), components});
|
||||
}
|
||||
|
||||
uint32_t ImageViewImageType(EmitterState& state, ImageDimension dimension,
|
||||
SampledImageClass image_class) {
|
||||
const auto& info = ImageDimensionInfoFor(dimension);
|
||||
uint32_t ImageType(EmitterState& state, const IR::ImageResource& image) {
|
||||
uint32_t sampled = 0;
|
||||
uint32_t format = ImageFormatUnknown;
|
||||
if (image.resource_class == IR::ImageResourceClass::Sampled) {
|
||||
EXIT_IF(image.atomic);
|
||||
sampled = 1;
|
||||
} else if (image.resource_class == IR::ImageResourceClass::Storage) {
|
||||
EXIT_IF(image.numeric_class == Prospero::TextureNumericClass::Sint ||
|
||||
image.numeric_class == Prospero::TextureNumericClass::Unsupported);
|
||||
sampled = 2;
|
||||
if (image.atomic) {
|
||||
EXIT_IF(image.numeric_class != Prospero::TextureNumericClass::Uint);
|
||||
format = ImageFormatR32ui;
|
||||
}
|
||||
} else {
|
||||
EXIT("invalid image resource class");
|
||||
}
|
||||
const auto& info = ImageDimensionInfoFor(image.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, ImageDimension dimension,
|
||||
SampledImageClass image_class) {
|
||||
return state.builder.Type(OpTypeSampledImage,
|
||||
{ImageViewImageType(state, dimension, image_class)});
|
||||
{ImageScalarType(state, image.numeric_class), info.spirv_dimension, 0,
|
||||
info.arrayed, info.multisampled, sampled, format});
|
||||
}
|
||||
|
||||
uint32_t ImageViewSizeType(EmitterState& state, ImageDimension dimension) {
|
||||
@@ -163,62 +171,20 @@ uint32_t ImageViewSizeType(EmitterState& state, ImageDimension dimension) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t StorageImageType(EmitterState& state, StorageImageClass image_class,
|
||||
ImageDimension dimension) {
|
||||
uint32_t component = TypeF32(state);
|
||||
uint32_t format = ImageFormatUnknown;
|
||||
if (image_class == StorageImageClass::FormatlessUint) {
|
||||
component = TypeU32(state);
|
||||
} else if (image_class == StorageImageClass::AtomicUint) {
|
||||
component = TypeU32(state);
|
||||
format = ImageFormatR32ui;
|
||||
}
|
||||
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,
|
||||
ImageDimension dimension) {
|
||||
return state.builder.Type(OpTypePointer, {StorageClassUniformConstant,
|
||||
StorageImageType(state, image_class, dimension)});
|
||||
}
|
||||
|
||||
StorageImageClass StorageImageClassForResource(const EmitterState& state, uint32_t resource) {
|
||||
const auto& image = state.program.info.images.at(resource);
|
||||
EXIT_IF(image.resource_class != IR::ImageResourceClass::Storage);
|
||||
if (image.atomic) {
|
||||
EXIT_IF(image.numeric_class != Prospero::TextureNumericClass::Uint);
|
||||
return StorageImageClass::AtomicUint;
|
||||
}
|
||||
switch (image.numeric_class) {
|
||||
case Prospero::TextureNumericClass::Float: return StorageImageClass::FormatlessFloat;
|
||||
case Prospero::TextureNumericClass::Uint: return StorageImageClass::FormatlessUint;
|
||||
case Prospero::TextureNumericClass::Sint:
|
||||
case Prospero::TextureNumericClass::Unsupported:
|
||||
EXIT("invalid storage image numeric class");
|
||||
}
|
||||
EXIT("invalid storage image numeric class");
|
||||
}
|
||||
|
||||
uint32_t LoadSampledImageDescriptor(EmitterState& state, uint32_t resource) {
|
||||
const auto& image_resource = state.program.info.images.at(resource);
|
||||
EXIT_IF(image_resource.resource_class != IR::ImageResourceClass::Sampled);
|
||||
const auto dimension = image_resource.dimension;
|
||||
const auto image_class = SampledImageClassFor(image_resource.numeric_class);
|
||||
EXIT_IF(image_class == SampledImageClass::Count);
|
||||
const auto kind = SampledBindingKind(image_class, dimension);
|
||||
const auto array_index = ResourceForDescriptor(state, kind, 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 kind = IR::DescriptorBindingForImage(image_resource);
|
||||
EXIT_IF(!kind.has_value());
|
||||
const auto array_index = ResourceForDescriptor(state, *kind, resource);
|
||||
const auto variable = state.image_variables[IR::ImageBindingIndex(*kind)];
|
||||
const auto pointer_type = state.builder.Type(
|
||||
OpTypePointer, {StorageClassUniformConstant, ImageType(state, image_resource)});
|
||||
const auto pointer =
|
||||
DescriptorElementPointer(state, pointer_type, variable, array_index, kind, resource,
|
||||
DescriptorElementPointer(state, pointer_type, variable, array_index, *kind, resource,
|
||||
"sampled image descriptor array was not emitted");
|
||||
const auto image = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpLoad, ImageViewImageType(state, dimension, image_class), image, pointer});
|
||||
state.builder.AddFunction({OpLoad, ImageType(state, image_resource), image, pointer});
|
||||
return image;
|
||||
}
|
||||
|
||||
@@ -238,50 +204,48 @@ uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler) {
|
||||
|
||||
uint32_t MakeSampledImage(EmitterState& state, uint32_t resource, uint32_t sampler) {
|
||||
const auto& image_resource = state.program.info.images.at(resource);
|
||||
const auto dimension = image_resource.dimension;
|
||||
const auto image_class = SampledImageClassFor(image_resource.numeric_class);
|
||||
const auto image = LoadSampledImageDescriptor(state, resource);
|
||||
const auto sampler_id = LoadSamplerDescriptor(state, sampler);
|
||||
if (image == 0 || sampler_id == 0) {
|
||||
ExitDescriptorBindingFailure(state, SampledBindingKind(image_class, dimension), resource,
|
||||
"sampled image or sampler descriptor load failed");
|
||||
}
|
||||
const auto sampled_image = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpSampledImage,
|
||||
ImageViewSampledImageType(state, dimension, image_class),
|
||||
sampled_image, image, sampler_id});
|
||||
const auto sampled_image = state.builder.AllocateId();
|
||||
const auto sampled_type =
|
||||
state.builder.Type(OpTypeSampledImage, {ImageType(state, image_resource)});
|
||||
state.builder.AddFunction({OpSampledImage, sampled_type, sampled_image, image, sampler_id});
|
||||
return sampled_image;
|
||||
}
|
||||
|
||||
uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource) {
|
||||
const auto dimension = state.program.info.images.at(resource).dimension;
|
||||
const auto image_class = StorageImageClassForResource(state, resource);
|
||||
const auto kind = StorageBindingKind(image_class, dimension);
|
||||
const auto array_index = ResourceForDescriptor(state, kind, resource);
|
||||
const auto ptr_type = StorageImagePointerType(state, image_class, dimension);
|
||||
const auto variable = state.storage_image_variables[StorageImageIndex(image_class, dimension)];
|
||||
return DescriptorElementPointer(state, ptr_type, variable, array_index, kind, resource,
|
||||
const auto& image = state.program.info.images.at(resource);
|
||||
EXIT_IF(image.resource_class != IR::ImageResourceClass::Storage);
|
||||
const auto kind = IR::DescriptorBindingForImage(image);
|
||||
EXIT_IF(!kind.has_value());
|
||||
const auto array_index = ResourceForDescriptor(state, *kind, resource);
|
||||
const auto pointer_type =
|
||||
state.builder.Type(OpTypePointer, {StorageClassUniformConstant, ImageType(state, image)});
|
||||
const auto variable = state.image_variables[IR::ImageBindingIndex(*kind)];
|
||||
return DescriptorElementPointer(state, pointer_type, variable, array_index, *kind, resource,
|
||||
"storage image descriptor array was not emitted");
|
||||
}
|
||||
|
||||
void EmitStorageImageWrite(EmitterState& state, uint32_t resource, uint32_t mip_lod, uint32_t coord,
|
||||
uint32_t texel) {
|
||||
const auto dimension = state.program.info.images.at(resource).dimension;
|
||||
const auto image_class = StorageImageClassForResource(state, resource);
|
||||
if (image_class != StorageImageClass::AtomicUint) {
|
||||
const auto& image = state.program.info.images.at(resource);
|
||||
EXIT_IF(image.resource_class != IR::ImageResourceClass::Storage);
|
||||
if (!image.atomic) {
|
||||
state.builder.RequireCapability(CapabilityStorageImageWriteWithoutFormat);
|
||||
}
|
||||
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, dimension),
|
||||
state.storage_image_variables[StorageImageIndex(image_class, dimension)], array_index,
|
||||
kind, resource, "storage image descriptor array was not emitted");
|
||||
const auto kind = IR::DescriptorBindingForImage(image);
|
||||
EXIT_IF(!kind.has_value());
|
||||
const auto array_index = ResourceForDescriptor(state, *kind, resource);
|
||||
const auto image_type = ImageType(state, image);
|
||||
const auto pointer_type =
|
||||
state.builder.Type(OpTypePointer, {StorageClassUniformConstant, image_type});
|
||||
const auto variable = state.image_variables[IR::ImageBindingIndex(*kind)];
|
||||
const auto LoadAt = [&](uint32_t array_index) {
|
||||
const auto pointer =
|
||||
DescriptorElementPointer(state, pointer_type, variable, array_index, *kind, resource,
|
||||
"storage image descriptor array was not emitted");
|
||||
const auto descriptor = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpLoad, StorageImageType(state, image_class, dimension), descriptor, pointer});
|
||||
state.builder.AddFunction({OpLoad, image_type, descriptor, pointer});
|
||||
return descriptor;
|
||||
};
|
||||
if (image.mip_mode != IR::ImageMipMode::DynamicStorage) {
|
||||
@@ -289,7 +253,7 @@ void EmitStorageImageWrite(EmitterState& state, uint32_t resource, uint32_t mip_
|
||||
return;
|
||||
}
|
||||
if (image.mip_count == 0u) {
|
||||
ExitDescriptorBindingFailure(state, kind, resource,
|
||||
ExitDescriptorBindingFailure(state, *kind, resource,
|
||||
"dynamic storage image has no mip descriptors");
|
||||
}
|
||||
|
||||
|
||||
@@ -202,26 +202,32 @@ uint32_t FloatBits(ValueEmitContext& ctx, uint32_t value) {
|
||||
}
|
||||
|
||||
uint32_t SampledComponentBits(ValueEmitContext& ctx, uint32_t value,
|
||||
SampledImageClass image_class) {
|
||||
return image_class == SampledImageClass::Uint
|
||||
? value
|
||||
: Unary(ctx.state, OpBitcast, TypeU32(ctx.state), value);
|
||||
}
|
||||
|
||||
uint32_t SampledComponentZero(EmitterState& state, SampledImageClass image_class) {
|
||||
switch (image_class) {
|
||||
case SampledImageClass::Float: return ZeroF32(state);
|
||||
case SampledImageClass::Uint: return ConstantU32(state, 0);
|
||||
case SampledImageClass::Sint: return ConstantI32(state, 0);
|
||||
case SampledImageClass::Count: return 0;
|
||||
Prospero::TextureNumericClass numeric_class) {
|
||||
if (numeric_class == Prospero::TextureNumericClass::Uint) {
|
||||
return value;
|
||||
}
|
||||
return 0;
|
||||
return Unary(ctx.state, OpBitcast, TypeU32(ctx.state), value);
|
||||
}
|
||||
|
||||
uint32_t ResultVector(ValueEmitContext& ctx, uint32_t value, SampledImageClass image_class,
|
||||
bool dref, const IR::MemoryInfo& mem, bool gather = false) {
|
||||
const auto value_class = dref ? SampledImageClass::Float : image_class;
|
||||
const bool integer = IsIntegerSampledImage(value_class);
|
||||
uint32_t SampledComponentZero(EmitterState& state, Prospero::TextureNumericClass numeric_class) {
|
||||
switch (numeric_class) {
|
||||
case Prospero::TextureNumericClass::Float: return ZeroF32(state);
|
||||
case Prospero::TextureNumericClass::Uint: return ConstantU32(state, 0);
|
||||
case Prospero::TextureNumericClass::Sint: return ConstantI32(state, 0);
|
||||
case Prospero::TextureNumericClass::Unsupported: break;
|
||||
}
|
||||
EXIT("invalid sampled image numeric class");
|
||||
}
|
||||
|
||||
uint32_t ResultVector(ValueEmitContext& ctx, uint32_t value,
|
||||
Prospero::TextureNumericClass numeric_class, bool dref,
|
||||
const IR::MemoryInfo& mem, bool gather = false) {
|
||||
auto value_class = numeric_class;
|
||||
if (dref) {
|
||||
value_class = Prospero::TextureNumericClass::Float;
|
||||
}
|
||||
const bool integer = value_class == Prospero::TextureNumericClass::Uint ||
|
||||
value_class == Prospero::TextureNumericClass::Sint;
|
||||
if (mem.data_bits == 16u) {
|
||||
uint32_t packed[4] = {ConstantU32(ctx.state, 0), ConstantU32(ctx.state, 0),
|
||||
ConstantU32(ctx.state, 0), ConstantU32(ctx.state, 0)};
|
||||
@@ -230,8 +236,8 @@ uint32_t ResultVector(ValueEmitContext& ctx, uint32_t value, SampledImageClass i
|
||||
const auto component = gather ? index : DmaskComponent(mem.dmask, index);
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({OpCompositeExtract,
|
||||
SampledImageScalarType(ctx.state, value_class), result,
|
||||
value, component});
|
||||
ImageScalarType(ctx.state, value_class), result, value,
|
||||
component});
|
||||
return result;
|
||||
};
|
||||
for (uint32_t word = 0; word < mem.data_dwords; word++) {
|
||||
@@ -272,9 +278,8 @@ uint32_t ResultVector(ValueEmitContext& ctx, uint32_t value, SampledImageClass i
|
||||
continue;
|
||||
}
|
||||
const auto scalar = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction({OpCompositeExtract,
|
||||
SampledImageScalarType(ctx.state, value_class), scalar,
|
||||
value, index});
|
||||
ctx.state.builder.AddFunction(
|
||||
{OpCompositeExtract, ImageScalarType(ctx.state, value_class), scalar, value, index});
|
||||
component[index] = SampledComponentBits(ctx, scalar, value_class);
|
||||
}
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
@@ -462,7 +467,7 @@ uint32_t UnpackImageGather(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uin
|
||||
}
|
||||
|
||||
uint32_t EmitOneDimensionalGatherLz(ValueEmitContext& ctx, const IR::MemoryInfo& mem,
|
||||
uint32_t coord, SampledImageClass image_class) {
|
||||
uint32_t coord, Prospero::TextureNumericClass numeric_class) {
|
||||
auto& state = ctx.state;
|
||||
state.builder.RequireCapability(CapabilityImageQuery);
|
||||
const auto image = LoadSampledImageDescriptor(state, mem.resource);
|
||||
@@ -478,8 +483,8 @@ uint32_t EmitOneDimensionalGatherLz(ValueEmitContext& ctx, const IR::MemoryInfo&
|
||||
ConstantF32(state, 0x3f000000u))});
|
||||
|
||||
const auto sampled = MakeSampledImage(state, mem.resource, mem.sampler);
|
||||
const auto vector_type = SampledImageVectorType(state, image_class, 4);
|
||||
const auto scalar_type = SampledImageScalarType(state, image_class);
|
||||
const auto vector_type = ImageVectorType(state, numeric_class, 4);
|
||||
const auto scalar_type = ImageScalarType(state, numeric_class);
|
||||
const auto component =
|
||||
ImageConversionFormat(state, mem).format == Prospero::BufferFormat::kInvalid
|
||||
? ImageGatherComponent(mem.dmask)
|
||||
@@ -625,7 +630,7 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
if (op == IR::ValueOpcode::ImageRead) {
|
||||
const auto dimension = image.dimension;
|
||||
const auto& dimension_info = ImageDimensionInfoFor(dimension);
|
||||
const auto image_class = SampledImageClassFor(image.numeric_class);
|
||||
const auto numeric_class = image.numeric_class;
|
||||
const auto condition = ctx.Arg(inst, 2);
|
||||
ctx.Define(
|
||||
inst,
|
||||
@@ -637,17 +642,17 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto coord = CoordU32(ctx, mem, *address, dimension);
|
||||
if (dimension_info.multisampled != 0u) {
|
||||
state.builder.AddFunction(
|
||||
{OpImageFetch, SampledImageVectorType(state, image_class, 4), color,
|
||||
{OpImageFetch, ImageVectorType(state, numeric_class, 4), color,
|
||||
descriptor, coord, ImageOperandsSampleMask,
|
||||
AddressU32(ctx, mem, *address, dimension_info.coordinate_components)});
|
||||
} else {
|
||||
state.builder.AddFunction({OpImageFetch,
|
||||
SampledImageVectorType(state, image_class, 4),
|
||||
color, descriptor, coord, ImageOperandsLodMask,
|
||||
ImageVectorType(state, numeric_class, 4), color,
|
||||
descriptor, coord, ImageOperandsLodMask,
|
||||
LodU32(ctx, mem, *address, dimension)});
|
||||
}
|
||||
return ResultVector(ctx, UnpackImageTexel(ctx, mem, color), image_class, false,
|
||||
mem);
|
||||
return ResultVector(ctx, UnpackImageTexel(ctx, mem, color), numeric_class,
|
||||
false, mem);
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
@@ -669,7 +674,7 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto dimension = image.dimension;
|
||||
const auto& dimension_info = ImageDimensionInfoFor(dimension);
|
||||
const auto layout = Layout(mem, dimension);
|
||||
const auto image_class = SampledImageClassFor(image.numeric_class);
|
||||
const auto numeric_class = image.numeric_class;
|
||||
const bool dref = HasFlag(mem, Decoder::ImageSampleFlagCompare);
|
||||
if (dref && state.program.info.images[mem.resource].conversion_format !=
|
||||
Prospero::BufferFormat::kInvalid) {
|
||||
@@ -686,9 +691,9 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
ctx.Fail(inst, "has an unsupported 1D gather variant");
|
||||
return true;
|
||||
}
|
||||
const auto sample = EmitOneDimensionalGatherLz(ctx, mem, coord, image_class);
|
||||
ctx.Define(inst, ResultVector(ctx, UnpackImageGather(ctx, mem, sample), image_class,
|
||||
false, mem, true));
|
||||
const auto sample = EmitOneDimensionalGatherLz(ctx, mem, coord, numeric_class);
|
||||
ctx.Define(inst, ResultVector(ctx, UnpackImageGather(ctx, mem, sample),
|
||||
numeric_class, false, mem, true));
|
||||
return true;
|
||||
}
|
||||
if (dimension == ImageDimension::Dim1DArray) {
|
||||
@@ -697,25 +702,23 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
}
|
||||
const auto sampled = MakeSampledImage(state, mem.resource, mem.sampler);
|
||||
const auto sample = state.builder.AllocateId();
|
||||
std::vector<uint32_t> words =
|
||||
dref ? std::vector<uint32_t> {OpImageDrefGather,
|
||||
TypeF32Vector(state, 4),
|
||||
sample,
|
||||
sampled,
|
||||
coord,
|
||||
layout.dref != NoImageComponent
|
||||
? AddressF32(ctx, mem, *address, layout.dref)
|
||||
: ZeroF32(state)}
|
||||
: std::vector<uint32_t> {
|
||||
OpImageGather,
|
||||
SampledImageVectorType(state, image_class, 4),
|
||||
sample,
|
||||
sampled,
|
||||
coord,
|
||||
ConstantU32(state, ImageConversionFormat(state, mem).format ==
|
||||
Prospero::BufferFormat::kInvalid
|
||||
? ImageGatherComponent(mem.dmask)
|
||||
: 0u)};
|
||||
std::vector<uint32_t> words;
|
||||
if (dref) {
|
||||
auto dref_value = ZeroF32(state);
|
||||
if (layout.dref != NoImageComponent) {
|
||||
dref_value = AddressF32(ctx, mem, *address, layout.dref);
|
||||
}
|
||||
words = {OpImageDrefGather, TypeF32Vector(state, 4), sample, sampled, coord,
|
||||
dref_value};
|
||||
} else {
|
||||
uint32_t component = 0;
|
||||
if (ImageConversionFormat(state, mem).format == Prospero::BufferFormat::kInvalid) {
|
||||
component = ImageGatherComponent(mem.dmask);
|
||||
}
|
||||
words = {OpImageGather, ImageVectorType(state, numeric_class, 4),
|
||||
sample, sampled,
|
||||
coord, ConstantU32(state, component)};
|
||||
}
|
||||
if (HasFlag(mem, Decoder::ImageSampleFlagGatherHorizontal)) {
|
||||
words.push_back(ImageOperandsConstOffsetsMask);
|
||||
words.push_back(HorizontalOffsets(state, dimension));
|
||||
@@ -724,24 +727,33 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
words.push_back(PackedOffset(ctx, mem, *address, layout, dimension));
|
||||
}
|
||||
state.builder.AddFunction(words);
|
||||
auto result_numeric_class = numeric_class;
|
||||
if (dref) {
|
||||
result_numeric_class = Prospero::TextureNumericClass::Float;
|
||||
}
|
||||
ctx.Define(inst, ResultVector(ctx, UnpackImageGather(ctx, mem, sample),
|
||||
dref ? SampledImageClass::Float : image_class, false, mem,
|
||||
true));
|
||||
result_numeric_class, false, mem, true));
|
||||
return true;
|
||||
}
|
||||
const bool explicit_lod = HasFlag(mem, Decoder::ImageSampleFlagDerivative) ||
|
||||
HasFlag(mem, Decoder::ImageSampleFlagLod) ||
|
||||
HasFlag(mem, Decoder::ImageSampleFlagLevelZero) ||
|
||||
state.stage != ShaderType::Pixel;
|
||||
const auto opcode = explicit_lod
|
||||
? (dref ? OpImageSampleDrefExplicitLod : OpImageSampleExplicitLod)
|
||||
: (dref ? OpImageSampleDrefImplicitLod : OpImageSampleImplicitLod);
|
||||
const auto result_type =
|
||||
dref ? TypeF32(state) : SampledImageVectorType(state, image_class, 4);
|
||||
const auto dref_value =
|
||||
dref ? (layout.dref != NoImageComponent ? AddressF32(ctx, mem, *address, layout.dref)
|
||||
: ZeroF32(state))
|
||||
: 0u;
|
||||
uint32_t opcode = OpImageSampleImplicitLod;
|
||||
if (explicit_lod) {
|
||||
opcode = dref ? OpImageSampleDrefExplicitLod : OpImageSampleExplicitLod;
|
||||
} else if (dref) {
|
||||
opcode = OpImageSampleDrefImplicitLod;
|
||||
}
|
||||
uint32_t result_type = ImageVectorType(state, numeric_class, 4);
|
||||
uint32_t dref_value = 0;
|
||||
if (dref) {
|
||||
result_type = TypeF32(state);
|
||||
dref_value = ZeroF32(state);
|
||||
if (layout.dref != NoImageComponent) {
|
||||
dref_value = AddressF32(ctx, mem, *address, layout.dref);
|
||||
}
|
||||
}
|
||||
uint32_t operand_mask = 0;
|
||||
std::vector<uint32_t> operands;
|
||||
if (HasFlag(mem, Decoder::ImageSampleFlagDerivative)) {
|
||||
@@ -752,10 +764,11 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
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) &&
|
||||
layout.lod != NoImageComponent
|
||||
? AddressF32(ctx, mem, *address, layout.lod)
|
||||
: ZeroF32(state));
|
||||
auto lod = ZeroF32(state);
|
||||
if (HasFlag(mem, Decoder::ImageSampleFlagLod) && layout.lod != NoImageComponent) {
|
||||
lod = AddressF32(ctx, mem, *address, layout.lod);
|
||||
}
|
||||
operands.push_back(lod);
|
||||
} else if (layout.bias != NoImageComponent) {
|
||||
operand_mask |= ImageOperandsBiasMask;
|
||||
operands.push_back(AddressF32(ctx, mem, *address, layout.bias));
|
||||
@@ -776,8 +789,11 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
};
|
||||
if (image.indirect_root != mem.resource) {
|
||||
const auto sample = EmitSample(mem.resource);
|
||||
ctx.Define(inst, ResultVector(ctx, dref ? sample : UnpackImageTexel(ctx, mem, sample),
|
||||
image_class, dref, mem));
|
||||
auto result = sample;
|
||||
if (!dref) {
|
||||
result = UnpackImageTexel(ctx, mem, sample);
|
||||
}
|
||||
ctx.Define(inst, ResultVector(ctx, result, numeric_class, dref, mem));
|
||||
return true;
|
||||
}
|
||||
const auto* handle = image_arg.ResolveInstruction();
|
||||
@@ -868,9 +884,11 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
}
|
||||
EmitLabel(state, merge_label);
|
||||
state.builder.AddFunction(phi_words);
|
||||
ctx.Define(inst,
|
||||
ResultVector(ctx, dref ? phi_words[2] : UnpackImageTexel(ctx, mem, phi_words[2]),
|
||||
image_class, dref, mem));
|
||||
auto result = phi_words[2];
|
||||
if (!dref) {
|
||||
result = UnpackImageTexel(ctx, mem, result);
|
||||
}
|
||||
ctx.Define(inst, ResultVector(ctx, result, numeric_class, dref, mem));
|
||||
return true;
|
||||
}
|
||||
const auto atomic_opcode = ImageAtomicOpcode(op);
|
||||
|
||||
@@ -321,7 +321,6 @@ using ImageDimension = Decoder::ImageDimension;
|
||||
|
||||
struct ImageDimensionInfo {
|
||||
ImageDimension dimension;
|
||||
uint32_t ordinal;
|
||||
uint32_t spirv_dimension;
|
||||
uint32_t coordinate_components;
|
||||
uint32_t spatial_components;
|
||||
@@ -330,29 +329,17 @@ struct ImageDimensionInfo {
|
||||
};
|
||||
|
||||
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},
|
||||
{ImageDimension::Dim1D, Dim1D, 1, 1, 0, 0},
|
||||
{ImageDimension::Dim1DArray, Dim1D, 2, 1, 1, 0},
|
||||
{ImageDimension::Dim2D, Dim2D, 2, 2, 0, 0},
|
||||
{ImageDimension::Dim2DArray, Dim2D, 3, 2, 1, 0},
|
||||
{ImageDimension::Dim3D, Dim3D, 3, 3, 0, 0},
|
||||
{ImageDimension::Dim2DMsaa, Dim2D, 2, 2, 0, 1},
|
||||
{ImageDimension::Dim2DMsaaArray, Dim2D, 3, 2, 1, 1},
|
||||
}};
|
||||
|
||||
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 };
|
||||
|
||||
enum class StorageImageClass : uint32_t {
|
||||
FormatlessFloat,
|
||||
FormatlessUint,
|
||||
AtomicUint,
|
||||
Count,
|
||||
};
|
||||
|
||||
struct EmitterState {
|
||||
EmitterState(const IR::Program& program_, const IR::ResourceSnapshot& resources_,
|
||||
ShaderStageInputInfo input_info_)
|
||||
@@ -378,12 +365,7 @@ struct EmitterState {
|
||||
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) * SampledImageDimensionCount>
|
||||
sampled_image_variables {};
|
||||
std::array<uint32_t,
|
||||
static_cast<uint32_t>(StorageImageClass::Count) * StorageImageDimensionCount>
|
||||
storage_image_variables {};
|
||||
std::array<uint32_t, IR::ImageBindingCount> image_variables {};
|
||||
uint32_t sampler_variable = 0;
|
||||
uint32_t main_func = 0;
|
||||
uint32_t entry_label = 0;
|
||||
@@ -482,113 +464,6 @@ struct ImageSampleLayout {
|
||||
uint32_t grad_y = NoImageComponent;
|
||||
};
|
||||
|
||||
constexpr SampledImageClass SampledImageClassFor(Prospero::TextureNumericClass numeric_class) {
|
||||
switch (numeric_class) {
|
||||
case Prospero::TextureNumericClass::Float: return SampledImageClass::Float;
|
||||
case Prospero::TextureNumericClass::Uint: return SampledImageClass::Uint;
|
||||
case Prospero::TextureNumericClass::Sint: return SampledImageClass::Sint;
|
||||
case Prospero::TextureNumericClass::Unsupported: return SampledImageClass::Count;
|
||||
}
|
||||
return SampledImageClass::Count;
|
||||
}
|
||||
|
||||
constexpr bool IsIntegerSampledImage(SampledImageClass image_class) {
|
||||
return image_class == SampledImageClass::Uint || image_class == SampledImageClass::Sint;
|
||||
}
|
||||
|
||||
inline uint32_t SampledImageIndex(SampledImageClass image_class, ImageDimension dimension) {
|
||||
return ImageDimensionInfoFor(dimension).ordinal +
|
||||
static_cast<uint32_t>(image_class) * SampledImageDimensionCount;
|
||||
}
|
||||
|
||||
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,
|
||||
ImageDimension dimension) {
|
||||
if (image_class == SampledImageClass::Uint) {
|
||||
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 (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 (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,
|
||||
ImageDimension dimension) {
|
||||
switch (image_class) {
|
||||
case StorageImageClass::FormatlessFloat:
|
||||
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 (dimension) {
|
||||
case ImageDimension::Dim1D: return IR::DescriptorBindingKind::StorageUint1D;
|
||||
case ImageDimension::Dim1DArray:
|
||||
return IR::DescriptorBindingKind::StorageUint1DArray;
|
||||
case ImageDimension::Dim2D: return IR::DescriptorBindingKind::StorageUint2D;
|
||||
case ImageDimension::Dim2DArray:
|
||||
return IR::DescriptorBindingKind::StorageUint2DArray;
|
||||
case ImageDimension::Dim3D: return IR::DescriptorBindingKind::StorageUint3D;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case StorageImageClass::AtomicUint:
|
||||
switch (dimension) {
|
||||
case ImageDimension::Dim1D: return IR::DescriptorBindingKind::StorageAtomic1D;
|
||||
case ImageDimension::Dim1DArray:
|
||||
return IR::DescriptorBindingKind::StorageAtomic1DArray;
|
||||
case ImageDimension::Dim2D: return IR::DescriptorBindingKind::StorageAtomic2D;
|
||||
case ImageDimension::Dim2DArray:
|
||||
return IR::DescriptorBindingKind::StorageAtomic2DArray;
|
||||
case ImageDimension::Dim3D: return IR::DescriptorBindingKind::StorageAtomic3D;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case StorageImageClass::Count: break;
|
||||
}
|
||||
return IR::DescriptorBindingKind::Count;
|
||||
}
|
||||
|
||||
struct F32Class {
|
||||
uint32_t bits = 0;
|
||||
uint32_t nan = 0;
|
||||
@@ -639,25 +514,15 @@ uint32_t DescriptorElementPointer(EmitterState& state, uint32_t result_ptr_type,
|
||||
IR::DescriptorBindingKind kind, uint32_t resource,
|
||||
const char* variable_name);
|
||||
|
||||
uint32_t SampledImageScalarType(EmitterState& state, SampledImageClass image_class);
|
||||
uint32_t ImageScalarType(EmitterState& state, Prospero::TextureNumericClass numeric_class);
|
||||
|
||||
uint32_t SampledImageVectorType(EmitterState& state, SampledImageClass image_class,
|
||||
uint32_t components);
|
||||
uint32_t ImageVectorType(EmitterState& state, Prospero::TextureNumericClass numeric_class,
|
||||
uint32_t components);
|
||||
|
||||
uint32_t ImageViewImageType(EmitterState& state, ImageDimension dimension,
|
||||
SampledImageClass image_class);
|
||||
|
||||
uint32_t ImageViewSampledImageType(EmitterState& state, ImageDimension dimension,
|
||||
SampledImageClass image_class);
|
||||
uint32_t ImageType(EmitterState& state, const IR::ImageResource& image);
|
||||
|
||||
uint32_t ImageViewSizeType(EmitterState& state, ImageDimension dimension);
|
||||
|
||||
uint32_t StorageImageType(EmitterState& state, StorageImageClass image_class,
|
||||
ImageDimension dimension);
|
||||
|
||||
uint32_t StorageImagePointerType(EmitterState& state, StorageImageClass image_class,
|
||||
ImageDimension dimension);
|
||||
|
||||
uint32_t LoadSampledImageDescriptor(EmitterState& state, uint32_t resource);
|
||||
|
||||
uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler);
|
||||
|
||||
@@ -187,38 +187,23 @@ void DefineDescriptorVariables(EmitterState& state) {
|
||||
state.flattened_srt_variable = state.builder.DefineGlobalVariable(
|
||||
TypeStorageBufferPointer(state), StorageClassStorageBuffer);
|
||||
}
|
||||
for (uint32_t i = 0; i < state.sampled_image_variables.size(); i++) {
|
||||
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) {
|
||||
for (const auto& binding: state.program.bindings.descriptors) {
|
||||
if (IR::ImageBindingResourceClass(binding.kind) == IR::ImageResourceClass::None) {
|
||||
continue;
|
||||
}
|
||||
const auto count = ConstantU32(state, DescriptorCount(state, kind));
|
||||
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] =
|
||||
const auto& image = state.program.info.images.at(binding.resources.front());
|
||||
const auto count = ConstantU32(state, DescriptorCount(state, binding.kind));
|
||||
const auto image_type = ImageType(state, image);
|
||||
const auto array_type = state.builder.Type(OpTypeArray, {image_type, count});
|
||||
const auto pointer_type = TypePointer(state, StorageClassUniformConstant, array_type);
|
||||
state.image_variables[IR::ImageBindingIndex(binding.kind)] =
|
||||
state.builder.DefineGlobalVariable(pointer_type, StorageClassUniformConstant);
|
||||
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 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, 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 (dimension == ImageDimension::Dim1D || dimension == ImageDimension::Dim1DArray) {
|
||||
state.builder.RequireCapability(CapabilityImage1D);
|
||||
if (image.dimension == ImageDimension::Dim1D ||
|
||||
image.dimension == ImageDimension::Dim1DArray) {
|
||||
const auto capability = image.resource_class == IR::ImageResourceClass::Sampled
|
||||
? CapabilitySampled1D
|
||||
: CapabilityImage1D;
|
||||
state.builder.RequireCapability(capability);
|
||||
}
|
||||
}
|
||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::Samplers) != nullptr) {
|
||||
@@ -594,53 +579,13 @@ void AddDescriptorAnnotationsAndNames(EmitterState& state) {
|
||||
Decorate(state.fault_buffer_variable, "fault_buffer",
|
||||
IR::DescriptorBindingKind::FaultBuffer);
|
||||
}
|
||||
constexpr const char* SampledNames[] = {"sampled_1d",
|
||||
"sampled_1d_array",
|
||||
"sampled_2d",
|
||||
"sampled_2d_array",
|
||||
"sampled_3d",
|
||||
"sampled_2d_msaa",
|
||||
"sampled_2d_msaa_array",
|
||||
"sampled_uint_1d",
|
||||
"sampled_uint_1d_array",
|
||||
"sampled_uint_2d",
|
||||
"sampled_uint_2d_array",
|
||||
"sampled_uint_3d",
|
||||
"sampled_uint_2d_msaa",
|
||||
"sampled_uint_2d_msaa_array",
|
||||
"sampled_sint_1d",
|
||||
"sampled_sint_1d_array",
|
||||
"sampled_sint_2d",
|
||||
"sampled_sint_2d_array",
|
||||
"sampled_sint_3d",
|
||||
"sampled_sint_2d_msaa",
|
||||
"sampled_sint_2d_msaa_array"};
|
||||
for (uint32_t i = 0; i < state.sampled_image_variables.size(); i++) {
|
||||
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, dimension));
|
||||
}
|
||||
constexpr const char* StorageNames[] = {"storage_1d",
|
||||
"storage_1d_array",
|
||||
"storage_2d",
|
||||
"storage_2d_array",
|
||||
"storage_3d",
|
||||
"storage_uint_1d",
|
||||
"storage_uint_1d_array",
|
||||
"storage_uint_2d",
|
||||
"storage_uint_2d_array",
|
||||
"storage_uint_3d",
|
||||
"storage_atomic_1d",
|
||||
"storage_atomic_1d_array",
|
||||
"storage_atomic_2d",
|
||||
"storage_atomic_2d_array",
|
||||
"storage_atomic_3d"};
|
||||
for (uint32_t i = 0; i < state.storage_image_variables.size(); i++) {
|
||||
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, dimension));
|
||||
for (const auto& binding: state.program.bindings.descriptors) {
|
||||
if (IR::ImageBindingResourceClass(binding.kind) == IR::ImageResourceClass::None) {
|
||||
continue;
|
||||
}
|
||||
const auto name = "image_" + std::to_string(static_cast<uint32_t>(binding.kind));
|
||||
Decorate(state.image_variables[IR::ImageBindingIndex(binding.kind)], name.c_str(),
|
||||
binding.kind);
|
||||
}
|
||||
if (state.sampler_variable != 0) {
|
||||
Decorate(state.sampler_variable, "samplers", IR::DescriptorBindingKind::Samplers);
|
||||
|
||||
Reference in New Issue
Block a user