graphics: add 1D image descriptor support

This commit is contained in:
nmzik
2026-07-27 14:10:51 +02:00
parent 125287dc30
commit 7351eae117
20 changed files with 1148 additions and 531 deletions
@@ -22,9 +22,13 @@ vk::ShaderStageFlags StageFlags(DescriptorCache::Stage stage) {
bool IsSampledImage(BindingKind kind) {
switch (kind) {
case BindingKind::Sampled1D:
case BindingKind::Sampled1DArray:
case BindingKind::Sampled2D:
case BindingKind::Sampled2DArray:
case BindingKind::Sampled3D:
case BindingKind::SampledUint1D:
case BindingKind::SampledUint1DArray:
case BindingKind::SampledUint2D:
case BindingKind::SampledUint2DArray:
case BindingKind::SampledUint3D: return true;
@@ -34,9 +38,13 @@ bool IsSampledImage(BindingKind kind) {
bool IsStorageImage(BindingKind kind) {
switch (kind) {
case BindingKind::Storage1D:
case BindingKind::Storage1DArray:
case BindingKind::Storage2D:
case BindingKind::Storage2DArray:
case BindingKind::Storage3D:
case BindingKind::StorageUint1D:
case BindingKind::StorageUint1DArray:
case BindingKind::StorageUint2D:
case BindingKind::StorageUint2DArray:
case BindingKind::StorageUint3D: return true;
+57 -12
View File
@@ -155,6 +155,8 @@ NativeAddressBuffer(RenderContext& context, CommandBuffer& command_buffer,
static bool IsSupportedSampledColorResource(const ShaderRecompiler::IR::ImageResource& resource) {
bool supported_dimension = false;
switch (resource.dimension) {
case ShaderRecompiler::Decoder::ImageDimension::Dim1D:
case ShaderRecompiler::Decoder::ImageDimension::Dim1DArray:
case ShaderRecompiler::Decoder::ImageDimension::Dim2D:
case ShaderRecompiler::Decoder::ImageDimension::Dim2DArray:
supported_dimension = true;
@@ -295,14 +297,32 @@ static void ValidateDepthTargetBinding(const ShaderRecompiler::IR::ImageResource
static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::ImageResource& resource,
const ShaderTextureResource& descriptor) {
const auto tile = descriptor.TileMode();
const auto tile = descriptor.TileMode();
const bool is_color_1d =
descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor1D);
const bool is_color_1d_array =
descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor1DArray);
const bool valid_1d_slice =
(is_color_1d && descriptor.Depth() == 0 && descriptor.BaseArray5() == 0) ||
(is_color_1d_array && descriptor.BaseArray5() <= descriptor.Depth());
const bool is_1d = resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim1D &&
descriptor.Height5() == 0 && valid_1d_slice;
const bool is_1d_array =
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim1DArray &&
is_color_1d_array && descriptor.Height5() == 0 &&
descriptor.BaseArray5() <= descriptor.Depth();
const bool is_color_2d =
descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D);
const bool is_color_2d_array =
descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray);
const bool valid_2d_slice =
(is_color_2d && descriptor.Depth() == 0 && descriptor.BaseArray5() == 0) ||
(is_color_2d_array && descriptor.BaseArray5() <= descriptor.Depth());
const bool is_2d = resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D &&
descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) &&
descriptor.Depth() == 0 && descriptor.BaseArray5() == 0;
valid_2d_slice;
const bool is_2d_array =
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2DArray &&
descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) &&
descriptor.BaseArray5() <= descriptor.Depth();
is_color_2d_array && descriptor.BaseArray5() <= descriptor.Depth();
const bool is_3d = resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim3D &&
descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor3D) &&
descriptor.BaseArray5() == 0;
@@ -321,8 +341,9 @@ static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::Imag
const bool supported_swizzle =
IsValidImageSwizzle(descriptor.DstSelXYZW()) &&
(descriptor.DstSelXYZW() == DstSel(4, 5, 6, 7) || !resource.read);
const bool supported_mip_view = descriptor.BaseLevel() == 0 || is_2d;
return (is_2d || is_2d_array || is_3d) && supported_tile && supported_mip_view &&
const bool supported_mip_view = descriptor.BaseLevel() == 0 || is_1d || is_2d;
return (is_1d || is_1d_array || is_2d || is_2d_array || is_3d) && supported_tile &&
supported_mip_view &&
descriptor.BaseLevel() == descriptor.LastLevel() &&
descriptor.LastLevel() <= descriptor.MaxMip() && descriptor.MinLod() == 0 &&
supported_swizzle && descriptor.BCSwizzle() == 0 && !descriptor.MsaaDepth();
@@ -471,6 +492,22 @@ static ImageViewInfo TextureViewInfo(const ShaderRecompiler::IR::ImageResource&
view.mapping =
storage ? vk::ComponentMapping {} : TextureGetComponentMapping(descriptor.DstSelXYZW());
switch (resource.dimension) {
case ShaderRecompiler::Decoder::ImageDimension::Dim1D:
view.type = vk::ImageViewType::e1D;
view.base_layer = descriptor.BaseArray5();
if (view.base_layer >= image_layers) {
EXIT("texture base layer is out of bounds\n");
}
view.layer_count = 1;
break;
case ShaderRecompiler::Decoder::ImageDimension::Dim1DArray:
view.type = vk::ImageViewType::e1DArray;
view.base_layer = descriptor.BaseArray5();
if (view.base_layer >= image_layers) {
EXIT("texture array base layer is out of bounds\n");
}
view.layer_count = image_layers - view.base_layer;
break;
case ShaderRecompiler::Decoder::ImageDimension::Dim3D:
view.type = vk::ImageViewType::e3D;
view.base_layer = 0;
@@ -484,11 +521,15 @@ static ImageViewInfo TextureViewInfo(const ShaderRecompiler::IR::ImageResource&
}
view.layer_count = image_layers - view.base_layer;
break;
default:
view.type = vk::ImageViewType::e2D;
view.base_layer = 0;
case ShaderRecompiler::Decoder::ImageDimension::Dim2D:
view.type = vk::ImageViewType::e2D;
view.base_layer = descriptor.BaseArray5();
if (view.base_layer >= image_layers) {
EXIT("texture base layer is out of bounds\n");
}
view.layer_count = 1;
break;
default: EXIT("unsupported texture view dimension\n");
}
return view;
}
@@ -576,6 +617,10 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso
}
const auto pixel_format = TextureGetFormat(format);
const auto storage_view_format = SrgbStorageViewFormat(pixel_format);
const auto view_format =
storage && storage_view_format != vk::Format::eUndefined ? storage_view_format
: pixel_format;
const auto block_bytes = Prospero::BlockCompressedBytesPerBlock(format);
TextureCache::ImageDesc desc {};
desc.info.data = {address, size.size};
@@ -594,7 +639,7 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso
} else {
PopulateTextureMipLayout(desc.info);
}
desc.view_info = TextureViewInfo(resource, descriptor, pixel_format, storage, view_levels,
desc.view_info = TextureViewInfo(resource, descriptor, view_format, storage, view_levels,
desc.info.resources.layers);
desc.type = storage ? TextureCache::BindingType::Storage : TextureCache::BindingType::Texture;
@@ -612,7 +657,7 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso
(void)SelectSampledDepthView(image->info.pixel_format, pixel_format,
descriptor.DstSelXYZW());
} else if (storage) {
ValidateStorageColorView(image->info.pixel_format, pixel_format, descriptor.DstSelXYZW());
ValidateStorageColorView(image->info.pixel_format, view_format, descriptor.DstSelXYZW());
} else {
(void)SelectSampledColorView(image->info.pixel_format, pixel_format,
descriptor.DstSelXYZW());
+24 -6
View File
@@ -69,8 +69,19 @@ namespace {
default: return false;
}
case vk::ImageType::e3D:
return info.type == vk::ImageViewType::e3D && info.base_layer == 0 &&
info.layer_count == 1;
switch (info.type) {
case vk::ImageViewType::e3D:
return info.base_layer == 0 && info.layer_count == 1;
case vk::ImageViewType::e2D:
return static_cast<bool>(
image.flags & vk::ImageCreateFlagBits::e2DArrayCompatible) &&
info.level_count == 1 && info.layer_count == 1;
case vk::ImageViewType::e2DArray:
return static_cast<bool>(
image.flags & vk::ImageCreateFlagBits::e2DArrayCompatible) &&
info.level_count == 1;
default: return false;
}
default: return false;
}
}
@@ -333,11 +344,18 @@ vk::ImageView Image::FindView(const ImageViewInfo& view_info) {
is_storage ? vk::ImageUsageFlagBits::eStorage : vk::ImageUsageFlags {};
const bool format_compatible = normalized.format != vk::Format::eUndefined &&
IsCompatibleViewFormat(image.format, normalized.format);
const bool ranges_valid = normalized.level_count != 0 &&
const bool slice_view = image.image_type == vk::ImageType::e3D &&
(normalized.type == vk::ImageViewType::e2D ||
normalized.type == vk::ImageViewType::e2DArray);
const bool levels_valid = normalized.level_count != 0 &&
normalized.base_level < image.mip_levels &&
normalized.level_count <= image.mip_levels - normalized.base_level &&
normalized.layer_count != 0 && normalized.base_layer < image.layers &&
normalized.layer_count <= image.layers - normalized.base_layer;
normalized.level_count <= image.mip_levels - normalized.base_level;
const auto view_layers = slice_view && levels_valid
? std::max(image.extent.depth >> normalized.base_level, 1u)
: image.layers;
const bool ranges_valid = levels_valid &&
normalized.layer_count != 0 && normalized.base_layer < view_layers &&
normalized.layer_count <= view_layers - normalized.base_layer;
const bool mapping_valid =
IsComponentSwizzle(normalized.mapping.r) && IsComponentSwizzle(normalized.mapping.g) &&
IsComponentSwizzle(normalized.mapping.b) && IsComponentSwizzle(normalized.mapping.a);
+12 -15
View File
@@ -38,19 +38,12 @@ namespace ImageViewOps {
static_cast<int>(image_format), static_cast<int>(view_format), swizzle);
}
[[nodiscard]] inline vk::Format BgraSrgbStorageViewFormat(vk::Format image_format) noexcept {
return image_format == vk::Format::eB8G8R8A8Srgb ? vk::Format::eR8G8B8A8Unorm
: vk::Format::eUndefined;
}
[[nodiscard]] inline vk::Format SrgbStorageViewFormat(vk::Format image_format) noexcept {
return image_format == vk::Format::eR8G8B8A8Srgb ? vk::Format::eR8G8B8A8Unorm
: BgraSrgbStorageViewFormat(image_format);
}
[[nodiscard]] inline bool IsBgraSrgbStorageView(vk::Format image_format, vk::Format view_format,
uint32_t swizzle) noexcept {
return view_format == BgraSrgbStorageViewFormat(image_format) && swizzle == DstSel(6, 5, 4, 7);
switch (image_format) {
case vk::Format::eR8G8B8A8Srgb:
case vk::Format::eB8G8R8A8Srgb: return vk::Format::eR8G8B8A8Unorm;
default: return vk::Format::eUndefined;
}
}
[[nodiscard]] inline bool IsSupportedSampledColorView(vk::Format image_format,
@@ -110,8 +103,10 @@ IsSupportedSampledDepthUintResource(const ShaderRecompiler::IR::ImageResource& r
inline void ValidateStorageColorView(vk::Format image_format, vk::Format view_format,
uint32_t swizzle) noexcept {
if ((image_format != view_format &&
!IsBgraSrgbStorageView(image_format, view_format, swizzle)) ||
const auto srgb_view = SrgbStorageViewFormat(image_format);
const bool srgb_storage_view =
srgb_view != vk::Format::eUndefined && view_format == srgb_view;
if ((image_format != view_format && !srgb_storage_view) ||
!IsValidImageSwizzle(swizzle)) {
UnsupportedColorView("storage", image_format, view_format, swizzle);
}
@@ -121,7 +116,9 @@ inline void ValidateStorageColorView(vk::Format image_format, vk::Format view_fo
IsSupportedStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource) noexcept {
return (resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImage ||
resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint) &&
(resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D ||
(resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim1D ||
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim1DArray ||
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D ||
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim3D ||
resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2DArray) &&
resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::None && resource.written &&
@@ -13,11 +13,15 @@ namespace {
constexpr uint32_t MaxPushConstantBytes = 128;
constexpr std::array ImageBindingKinds = {
DescriptorBindingKind::Sampled1D, DescriptorBindingKind::Sampled1DArray,
DescriptorBindingKind::Sampled2D, DescriptorBindingKind::Sampled2DArray,
DescriptorBindingKind::Sampled3D, DescriptorBindingKind::SampledUint2D,
DescriptorBindingKind::Sampled3D, DescriptorBindingKind::SampledUint1D,
DescriptorBindingKind::SampledUint1DArray, DescriptorBindingKind::SampledUint2D,
DescriptorBindingKind::SampledUint2DArray, DescriptorBindingKind::SampledUint3D,
DescriptorBindingKind::Storage1D, DescriptorBindingKind::Storage1DArray,
DescriptorBindingKind::Storage2D, DescriptorBindingKind::Storage2DArray,
DescriptorBindingKind::Storage3D, DescriptorBindingKind::StorageUint2D,
DescriptorBindingKind::Storage3D, DescriptorBindingKind::StorageUint1D,
DescriptorBindingKind::StorageUint1DArray, DescriptorBindingKind::StorageUint2D,
DescriptorBindingKind::StorageUint2DArray, DescriptorBindingKind::StorageUint3D,
};
@@ -28,6 +32,8 @@ bool ImageBinding(const ImageResource& image, DescriptorBindingKind& result) {
switch (image.kind) {
case ResourceKind::Image:
switch (image.dimension) {
case Dimension::Dim1D: result = Kind::Sampled1D; return true;
case Dimension::Dim1DArray: result = Kind::Sampled1DArray; return true;
case Dimension::Dim2D: result = Kind::Sampled2D; return true;
case Dimension::Dim2DArray: result = Kind::Sampled2DArray; return true;
case Dimension::Dim3D: result = Kind::Sampled3D; return true;
@@ -35,6 +41,8 @@ bool ImageBinding(const ImageResource& image, DescriptorBindingKind& result) {
}
case ResourceKind::ImageUint:
switch (image.dimension) {
case Dimension::Dim1D: result = Kind::SampledUint1D; return true;
case Dimension::Dim1DArray: result = Kind::SampledUint1DArray; return true;
case Dimension::Dim2D: result = Kind::SampledUint2D; return true;
case Dimension::Dim2DArray: result = Kind::SampledUint2DArray; return true;
case Dimension::Dim3D: result = Kind::SampledUint3D; return true;
@@ -42,6 +50,8 @@ bool ImageBinding(const ImageResource& image, DescriptorBindingKind& result) {
}
case ResourceKind::StorageImage:
switch (image.dimension) {
case Dimension::Dim1D: result = Kind::Storage1D; return true;
case Dimension::Dim1DArray: result = Kind::Storage1DArray; return true;
case Dimension::Dim2D: result = Kind::Storage2D; return true;
case Dimension::Dim2DArray: result = Kind::Storage2DArray; return true;
case Dimension::Dim3D: result = Kind::Storage3D; return true;
@@ -49,6 +59,8 @@ bool ImageBinding(const ImageResource& image, DescriptorBindingKind& result) {
}
case ResourceKind::StorageImageUint:
switch (image.dimension) {
case Dimension::Dim1D: result = Kind::StorageUint1D; return true;
case Dimension::Dim1DArray: result = Kind::StorageUint1DArray; return true;
case Dimension::Dim2D: result = Kind::StorageUint2D; return true;
case Dimension::Dim2DArray: result = Kind::StorageUint2DArray; return true;
case Dimension::Dim3D: result = Kind::StorageUint3D; return true;
+15 -2
View File
@@ -30,9 +30,11 @@ struct MimgAtomicInfo {
constexpr ImageDimension DecodeImageDimension(uint32_t dim) {
switch (dim) {
case 0u: return ImageDimension::Dim1D;
case 1u: return ImageDimension::Dim2D;
case 2u: return ImageDimension::Dim3D;
case 3u: return ImageDimension::Dim2DArray;
case 4u: return ImageDimension::Dim1DArray;
case 5u:
case 7u: return ImageDimension::Dim2DArray;
case 6u: return ImageDimension::Dim2D;
@@ -42,12 +44,23 @@ constexpr ImageDimension DecodeImageDimension(uint32_t dim) {
constexpr uint32_t ImageCoordComponents(ImageDimension dimension) {
switch (dimension) {
case ImageDimension::Dim1D: return 1u;
case ImageDimension::Dim1DArray: return 2u;
case ImageDimension::Dim3D:
case ImageDimension::Dim2DArray: return 3u;
default: return 2u;
}
}
constexpr uint32_t ImageGradientComponents(ImageDimension dimension) {
switch (dimension) {
case ImageDimension::Dim1D:
case ImageDimension::Dim1DArray: return 1u;
case ImageDimension::Dim3D: return 3u;
default: return 2u;
}
}
constexpr uint32_t ImageSampleAddressComponents(uint32_t flags, ImageDimension dimension) {
const auto coord_components = ImageCoordComponents(dimension);
uint32_t components = coord_components;
@@ -64,7 +77,7 @@ constexpr uint32_t ImageSampleAddressComponents(uint32_t flags, ImageDimension d
components++;
}
if ((flags & ImageSampleFlagDerivative) != 0) {
components += 4u;
components += ImageGradientComponents(dimension) * 2u;
}
return components;
}
@@ -255,7 +268,7 @@ uint32_t DecodeMimgAddressComponents(uint32_t opcode, ImageDimension dimension,
return ImageSampleAddressComponents(gather->flags, dimension);
}
if (atomic != nullptr) {
return 3u;
return ImageCoordComponents(dimension);
}
switch (opcode) {
@@ -12,14 +12,25 @@ namespace {
constexpr uint64_t AddressMask = 0x0000ffffffffffffull;
Decoder::ImageDimension DescriptorDimension(const DescriptorValue& descriptor) {
Decoder::ImageDimension DescriptorDimension(const DescriptorValue& descriptor,
Decoder::ImageDimension requested) {
const bool is_array = requested == Decoder::ImageDimension::Dim1DArray ||
requested == Decoder::ImageDimension::Dim2DArray;
switch (static_cast<Prospero::ImageType>((descriptor.dwords[3] >> 28u) & 0xfu)) {
case Prospero::ImageType::kColor3D: return Decoder::ImageDimension::Dim3D;
case Prospero::ImageType::kCube:
case Prospero::ImageType::kColor1D: return Decoder::ImageDimension::Dim1D;
case Prospero::ImageType::kColor1DArray:
if (is_array) {
return Decoder::ImageDimension::Dim1DArray;
}
return Decoder::ImageDimension::Dim1D;
case Prospero::ImageType::kColor3D: return Decoder::ImageDimension::Dim3D;
case Prospero::ImageType::kCube: return Decoder::ImageDimension::Dim2DArray;
case Prospero::ImageType::kColor2DArray:
case Prospero::ImageType::kColor2DMsaaArray: return Decoder::ImageDimension::Dim2DArray;
case Prospero::ImageType::kColor1D:
case Prospero::ImageType::kColor2DMsaaArray:
if (is_array) {
return Decoder::ImageDimension::Dim2DArray;
}
return Decoder::ImageDimension::Dim2D;
case Prospero::ImageType::kColor2D:
case Prospero::ImageType::kColor2DMsaa: return Decoder::ImageDimension::Dim2D;
default: return Decoder::ImageDimension::Unknown;
@@ -160,9 +171,21 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh
const auto& image = program.info.images[i];
const auto& descriptor = snapshot.images[i];
if (NullImageDescriptor(descriptor)) {
bool canonical_kind = image.kind == ResourceKind::Image ||
image.kind == ResourceKind::StorageImage;
if (image.atomic) {
canonical_kind = image.kind == ResourceKind::StorageImageUint;
}
if (image.dimension != Decoder::ImageDimension::Dim2D || !canonical_kind) {
if (error != nullptr) {
*error = fmt::format(
"image descriptor {} no longer matches canonical null specialization", i);
}
return false;
}
continue;
}
const auto dimension = DescriptorDimension(descriptor);
const auto dimension = DescriptorDimension(descriptor, image.dimension);
if (dimension == Decoder::ImageDimension::Unknown || dimension != image.dimension) {
if (error != nullptr) {
*error =
@@ -337,9 +360,19 @@ bool SpecializeResources(Program& program, const ResourceSnapshot& snapshot, std
const auto& descriptor = snapshot.images[i];
auto& image = next.images[i];
if (NullImageDescriptor(descriptor)) {
image.dimension = Decoder::ImageDimension::Dim2D;
switch (image.kind) {
case ResourceKind::ImageUint: image.kind = ResourceKind::Image; break;
case ResourceKind::StorageImageUint:
if (!image.atomic) {
image.kind = ResourceKind::StorageImage;
}
break;
default: break;
}
continue;
}
const auto descriptor_dimension = DescriptorDimension(descriptor);
const auto descriptor_dimension = DescriptorDimension(descriptor, image.dimension);
if (descriptor_dimension == Decoder::ImageDimension::Unknown) {
if (error != nullptr) {
*error = fmt::format(
@@ -134,15 +134,6 @@ std::string ImageSampleFlagsToString(uint32_t flags) {
return text;
}
const char* ImageDimensionToString(ImageDimension dimension) {
switch (dimension) {
case ImageDimension::Dim2D: return "2d";
case ImageDimension::Dim3D: return "3d";
case ImageDimension::Dim2DArray: return "2d_array";
default: return "unknown";
}
}
std::string FormatMimg(const Instruction& inst) {
const char* sample_name =
inst.opcode == Opcode::ImageSample ? MimgSampleOpcodeName(inst.opcode_id) : nullptr;
@@ -196,6 +187,17 @@ std::string FormatExp(const Instruction& inst) {
} // namespace
const char* ImageDimensionToString(ImageDimension dimension) {
switch (dimension) {
case ImageDimension::Dim1D: return "1d";
case ImageDimension::Dim1DArray: return "1d_array";
case ImageDimension::Dim2D: return "2d";
case ImageDimension::Dim3D: return "3d";
case ImageDimension::Dim2DArray: return "2d_array";
default: return "unknown";
}
}
bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand& operand, std::string* error) {
operand = {};
@@ -570,6 +570,8 @@ enum ImageSampleFlag : uint32_t {
enum class ImageDimension : uint32_t {
Unknown,
Dim1D,
Dim1DArray,
Dim2D,
Dim3D,
Dim2DArray,
@@ -669,6 +671,7 @@ void SetUnsupported(Instruction& inst, Family family, uint32_t opcode_id, const
std::string FamilyToString(Family family);
std::string OpcodeToString(Opcode opcode);
std::string OperandToString(const Operand& operand);
const char* ImageDimensionToString(ImageDimension dimension);
std::string InstructionToString(const Instruction& inst);
std::string ProgramToString(const Program& program);
@@ -673,15 +673,23 @@ struct StageOutput {
enum class DescriptorBindingKind {
Buffers,
Sampled1D,
Sampled1DArray,
Sampled2D,
Sampled2DArray,
Sampled3D,
SampledUint1D,
SampledUint1DArray,
SampledUint2D,
SampledUint2DArray,
SampledUint3D,
Storage1D,
Storage1DArray,
Storage2D,
Storage2DArray,
Storage3D,
StorageUint1D,
StorageUint1DArray,
StorageUint2D,
StorageUint2DArray,
StorageUint3D,
@@ -25,6 +25,10 @@ bool ImageBinding(const IR::ImageResource& image, IR::DescriptorBindingKind& kin
if (image.kind == IR::ResourceKind::Image || image.kind == IR::ResourceKind::ImageUint) {
const bool integer = image.kind == IR::ResourceKind::ImageUint;
switch (image.dimension) {
case Dim::Dim1D: kind = integer ? Kind::SampledUint1D : Kind::Sampled1D; return true;
case Dim::Dim1DArray:
kind = integer ? Kind::SampledUint1DArray : Kind::Sampled1DArray;
return true;
case Dim::Dim2D: kind = integer ? Kind::SampledUint2D : Kind::Sampled2D; return true;
case Dim::Dim3D: kind = integer ? Kind::SampledUint3D : Kind::Sampled3D; return true;
case Dim::Dim2DArray:
@@ -38,6 +42,10 @@ bool ImageBinding(const IR::ImageResource& image, IR::DescriptorBindingKind& kin
return false;
}
switch (image.dimension) {
case Dim::Dim1D: kind = uint_image ? Kind::StorageUint1D : Kind::Storage1D; return true;
case Dim::Dim1DArray:
kind = uint_image ? Kind::StorageUint1DArray : Kind::Storage1DArray;
return true;
case Dim::Dim2D: kind = uint_image ? Kind::StorageUint2D : Kind::Storage2D; return true;
case Dim::Dim3D: kind = uint_image ? Kind::StorageUint3D : Kind::Storage3D; return true;
case Dim::Dim2DArray:
@@ -175,6 +183,11 @@ bool ValidateInstructionContract(const IR::Instruction& inst, std::string* error
inst.src_count != 1)) {
return Fail(error, "sampled image instruction has an invalid resource class");
}
if (inst.op == IR::Opcode::ImageGather4 &&
(inst.memory.image_dimension == Decoder::ImageDimension::Dim1D ||
inst.memory.image_dimension == Decoder::ImageDimension::Dim1DArray)) {
return Fail(error, "1D image gather is not supported by SPIR-V");
}
if (inst.op == IR::Opcode::ImageStore &&
((kind != IR::ResourceKind::StorageImage && kind != IR::ResourceKind::StorageImageUint) ||
inst.src_count != 2)) {
@@ -86,15 +86,6 @@ std::string ResourceKindToString(ResourceKind kind) {
}
}
const char* ImageDimensionToString(Decoder::ImageDimension dimension) {
switch (dimension) {
case Decoder::ImageDimension::Dim2D: return "2d";
case Decoder::ImageDimension::Dim3D: return "3d";
case Decoder::ImageDimension::Dim2DArray: return "2d_array";
default: return "unknown";
}
}
std::string MemoryInfoToString(const MemoryInfo& mem) {
if (mem.kind == ResourceKind::None) {
return "";
@@ -109,7 +100,7 @@ std::string MemoryInfoToString(const MemoryInfo& mem) {
mem.component_count, mem.data_format, mem.number_format, mem.data_signed ? 1u : 0u,
mem.typed ? 1u : 0u, mem.formatted ? 1u : 0u, mem.memory_segment, mem.glc ? 1u : 0u,
mem.slc ? 1u : 0u, mem.idxen ? 1u : 0u, mem.offen ? 1u : 0u, mem.image_sample_flags,
ImageDimensionToString(mem.image_dimension), mem.image_address_components,
Decoder::ImageDimensionToString(mem.image_dimension), mem.image_address_components,
mem.image_has_mip ? 1u : 0u);
if (mem.image_nsa_dwords != 0) {
text += fmt::format(" image_nsa_dwords={} image_nsa_addr=", mem.image_nsa_dwords);
@@ -572,6 +572,8 @@ uint32_t DescriptorElementPointer(EmitterState& state, uint32_t result_ptr_type,
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;
default: return ImageViewKind::Dim2D;
@@ -595,9 +597,23 @@ ImageViewKind StorageImageViewKind(const EmitterState& state, const IR::MemoryIn
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::Dim3D: return 3u;
default: 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: return 2u;
case ImageViewKind::Dim3D: return 3u;
default: return 0u;
}
}
@@ -610,67 +626,24 @@ uint32_t ImageViewSampledImageType(const EmitterState& state, ImageViewKind view
}
uint32_t ImageViewSizeType(const EmitterState& state, ImageViewKind view) {
return ImageViewCoordinateComponents(view) == 3u ? state.vec3_uint_type : state.vec2_uint_type;
switch (ImageViewCoordinateComponents(view)) {
case 1u: return state.uint_type;
case 2u: return state.vec2_uint_type;
case 3u: return state.vec3_uint_type;
default: return 0;
}
}
uint32_t StorageImageType(const EmitterState& state, bool uint_image, ImageViewKind view) {
if (uint_image) {
switch (view) {
case ImageViewKind::Dim2DArray: return state.storage_image_uint_2d_array_type;
case ImageViewKind::Dim3D: return state.storage_image_uint_3d_type;
default: return state.storage_image_uint_type;
}
}
switch (view) {
case ImageViewKind::Dim2DArray: return state.storage_image_2d_array_type;
case ImageViewKind::Dim3D: return state.storage_image_3d_type;
default: return state.storage_image_type;
}
return state.storage_images[StorageImageIndex(uint_image, view)].image_type;
}
uint32_t StorageImagePointerType(const EmitterState& state, bool uint_image, ImageViewKind view) {
if (uint_image) {
switch (view) {
case ImageViewKind::Dim2DArray: return state.ptr_uniform_storage_image_uint_2d_array;
case ImageViewKind::Dim3D: return state.ptr_uniform_storage_image_uint_3d;
default: return state.ptr_uniform_storage_image_uint;
}
}
switch (view) {
case ImageViewKind::Dim2DArray: return state.ptr_uniform_storage_image_2d_array;
case ImageViewKind::Dim3D: return state.ptr_uniform_storage_image_3d;
default: return state.ptr_uniform_storage_image;
}
return state.storage_images[StorageImageIndex(uint_image, view)].pointer_type;
}
uint32_t StorageImageVariable(const EmitterState& state, bool uint_image, ImageViewKind view) {
if (uint_image) {
switch (view) {
case ImageViewKind::Dim2DArray: return state.storage_image_uint_2d_array_variable;
case ImageViewKind::Dim3D: return state.storage_image_uint_3d_variable;
default: return state.storage_image_uint_variable;
}
}
switch (view) {
case ImageViewKind::Dim2DArray: return state.storage_image_2d_array_variable;
case ImageViewKind::Dim3D: return state.storage_image_3d_variable;
default: return state.storage_image_variable;
}
}
IR::DescriptorBindingKind StorageBindingKind(bool uint_image, ImageViewKind view) {
if (uint_image) {
switch (view) {
case ImageViewKind::Dim2DArray: return IR::DescriptorBindingKind::StorageUint2DArray;
case ImageViewKind::Dim3D: return IR::DescriptorBindingKind::StorageUint3D;
default: return IR::DescriptorBindingKind::StorageUint2D;
}
}
switch (view) {
case ImageViewKind::Dim2DArray: return IR::DescriptorBindingKind::Storage2DArray;
case ImageViewKind::Dim3D: return IR::DescriptorBindingKind::Storage3D;
default: return IR::DescriptorBindingKind::Storage2D;
}
return state.storage_images[StorageImageIndex(uint_image, view)].variable;
}
uint32_t LoadSampledImageDescriptor(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc,
@@ -20,10 +20,11 @@ ImageSampleLayout MakeImageSampleLayout(const IR::Instruction& inst, ImageViewKi
layout.dref = cursor++;
}
if (HasImageSampleFlag(inst, Decoder::ImageSampleFlagDerivative)) {
const auto components = ImageViewSpatialComponents(view);
layout.grad_x = cursor;
cursor += 2u;
cursor += components;
layout.grad_y = cursor;
cursor += 2u;
cursor += components;
}
layout.coord = cursor;
cursor += ImageViewCoordinateComponents(view);
@@ -35,12 +36,16 @@ ImageSampleLayout MakeImageSampleLayout(const IR::Instruction& inst, ImageViewKi
uint32_t EmitImageCoordF32(EmitterState& state, const IR::Instruction& inst,
const ImageSampleLayout& layout, ImageViewKind view) {
const auto x = EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.coord);
const auto y = inst.memory.image_address_components > layout.coord + 1u
const auto x = EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.coord);
const auto components = ImageViewCoordinateComponents(view);
if (components == 1u) {
return x;
}
const auto y = inst.memory.image_address_components > layout.coord + 1u
? EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.coord + 1u)
: EmitZeroF32(state);
const auto coord = state.builder.AllocateId();
if (ImageViewCoordinateComponents(view) == 3u) {
if (components == 3u) {
const auto z = inst.memory.image_address_components > layout.coord + 2u
? EmitImageAddressFloatLoad(state, inst, inst.src[0], layout.coord + 2u)
: EmitZeroF32(state);
@@ -77,108 +82,87 @@ uint32_t EmitImageBiasF32(EmitterState& state, const IR::Instruction& inst,
}
uint32_t EmitImageGradientF32(EmitterState& state, const IR::Instruction& inst,
uint32_t first_component) {
uint32_t first_component, ImageViewKind view) {
const auto x = inst.memory.image_address_components > first_component
? EmitImageAddressFloatLoad(state, inst, inst.src[0], first_component)
: EmitZeroF32(state);
const auto components = ImageViewSpatialComponents(view);
if (components == 1u) {
return x;
}
const auto y = inst.memory.image_address_components > first_component + 1u
? EmitImageAddressFloatLoad(state, inst, inst.src[0], first_component + 1u)
: EmitZeroF32(state);
const auto grad = state.builder.AllocateId();
state.builder.AddFunction({OpCompositeConstruct, state.vec2_float_type, grad, x, y});
if (components == 3u) {
const auto z = inst.memory.image_address_components > first_component + 2u
? EmitImageAddressFloatLoad(state, inst, inst.src[0],
first_component + 2u)
: EmitZeroF32(state);
state.builder.AddFunction({OpCompositeConstruct, state.vec3_float_type, grad, x, y, z});
} else {
state.builder.AddFunction({OpCompositeConstruct, state.vec2_float_type, grad, x, y});
}
return grad;
}
uint32_t EmitImagePackedOffset2I32(EmitterState& state, const IR::Instruction& inst,
const ImageSampleLayout& layout) {
uint32_t EmitImagePackedOffsetI32(EmitterState& state, const IR::Instruction& inst,
const ImageSampleLayout& layout, ImageViewKind view) {
const auto components = ImageViewSpatialComponents(view);
if (layout.offset == NoImageComponent ||
inst.memory.image_address_components <= layout.offset) {
const auto zero = ConstantI32(state, 0);
const auto ret = state.builder.AllocateId();
state.builder.AddFunction({OpCompositeConstruct, state.vec2_int_type, ret, zero, zero});
if (components == 1u) {
return zero;
}
const auto ret = state.builder.AllocateId();
if (components == 3u) {
state.builder.AddFunction(
{OpCompositeConstruct, state.vec3_int_type, ret, zero, zero, zero});
} else {
state.builder.AddFunction(
{OpCompositeConstruct, state.vec2_int_type, ret, zero, zero});
}
return ret;
}
const auto packed_bits = EmitImageAddressValueLoad(state, inst, inst.src[0], layout.offset);
const auto packed_i32 = state.builder.AllocateId();
const auto offset_x = state.builder.AllocateId();
const auto offset_y = state.builder.AllocateId();
const auto offset = state.builder.AllocateId();
state.builder.AddFunction({OpBitcast, state.int_type, packed_i32, packed_bits});
state.builder.AddFunction({OpBitFieldSExtract, state.int_type, offset_x, packed_i32,
ConstantI32(state, 0), ConstantI32(state, 6)});
if (components == 1u) {
return offset_x;
}
const auto offset_y = state.builder.AllocateId();
const auto offset = state.builder.AllocateId();
state.builder.AddFunction({OpBitFieldSExtract, state.int_type, offset_y, packed_i32,
ConstantI32(state, 8), ConstantI32(state, 6)});
state.builder.AddFunction(
{OpCompositeConstruct, state.vec2_int_type, offset, offset_x, offset_y});
if (components == 3u) {
const auto offset_z = state.builder.AllocateId();
state.builder.AddFunction({OpBitFieldSExtract, state.int_type, offset_z, packed_i32,
ConstantI32(state, 16), ConstantI32(state, 6)});
state.builder.AddFunction(
{OpCompositeConstruct, state.vec3_int_type, offset, offset_x, offset_y, offset_z});
} else {
state.builder.AddFunction(
{OpCompositeConstruct, state.vec2_int_type, offset, offset_x, offset_y});
}
return offset;
}
uint32_t EmitImageOffsetCoordF32(EmitterState& state, const IR::Instruction& inst,
const ImageSampleLayout& layout, uint32_t sampled_image,
uint32_t coord, ImageViewKind view) {
if (!HasImageSampleFlag(inst, Decoder::ImageSampleFlagOffset)) {
return coord;
}
const auto offset_i32 = EmitImagePackedOffset2I32(state, inst, layout);
const auto offset_f32 = state.builder.AllocateId();
const auto image = state.builder.AllocateId();
const auto size_u32 = state.builder.AllocateId();
const auto size_xy_u32 =
ImageViewCoordinateComponents(view) == 3u ? state.builder.AllocateId() : size_u32;
const auto size_f32 = state.builder.AllocateId();
const auto normalized = state.builder.AllocateId();
const auto adjusted = state.builder.AllocateId();
state.builder.AddFunction({OpConvertSToF, state.vec2_float_type, offset_f32, offset_i32});
state.builder.AddFunction(
{OpImage, ImageViewImageType(state, view, inst.memory.kind == IR::ResourceKind::ImageUint),
image, sampled_image});
state.builder.AddFunction({OpImageQuerySizeLod, ImageViewSizeType(state, view), size_u32,
image, ConstantU32(state, 0)});
if (ImageViewCoordinateComponents(view) == 3u) {
const auto width = state.builder.AllocateId();
const auto height = state.builder.AllocateId();
state.builder.AddFunction({OpCompositeExtract, state.uint_type, width, size_u32, 0});
state.builder.AddFunction({OpCompositeExtract, state.uint_type, height, size_u32, 1});
state.builder.AddFunction(
{OpCompositeConstruct, state.vec2_uint_type, size_xy_u32, width, height});
}
state.builder.AddFunction({OpConvertUToF, state.vec2_float_type, size_f32, size_xy_u32});
state.builder.AddFunction({OpFDiv, state.vec2_float_type, normalized, offset_f32, size_f32});
if (ImageViewCoordinateComponents(view) == 2u) {
state.builder.AddFunction({OpFAdd, state.vec2_float_type, adjusted, coord, normalized});
return adjusted;
}
const auto x = state.builder.AllocateId();
const auto y = state.builder.AllocateId();
const auto z = state.builder.AllocateId();
const auto normalized_x = state.builder.AllocateId();
const auto normalized_y = state.builder.AllocateId();
const auto adjusted_x = state.builder.AllocateId();
const auto adjusted_y = state.builder.AllocateId();
state.builder.AddFunction({OpCompositeExtract, state.float_type, x, coord, 0});
state.builder.AddFunction({OpCompositeExtract, state.float_type, y, coord, 1});
state.builder.AddFunction({OpCompositeExtract, state.float_type, z, coord, 2});
state.builder.AddFunction(
{OpCompositeExtract, state.float_type, normalized_x, normalized, 0});
state.builder.AddFunction(
{OpCompositeExtract, state.float_type, normalized_y, normalized, 1});
state.builder.AddFunction({OpFAdd, state.float_type, adjusted_x, x, normalized_x});
state.builder.AddFunction({OpFAdd, state.float_type, adjusted_y, y, normalized_y});
state.builder.AddFunction(
{OpCompositeConstruct, state.vec3_float_type, adjusted, adjusted_x, adjusted_y, z});
return adjusted;
}
uint32_t EmitImageCoordU32(EmitterState& state, const IR::Instruction& inst, ImageViewKind view) {
const auto x = EmitImageAddressValueLoad(state, inst, inst.src[1], 0);
const auto y = inst.memory.image_address_components > 1u
const auto x = EmitImageAddressValueLoad(state, inst, inst.src[1], 0);
const auto components = ImageViewCoordinateComponents(view);
if (components == 1u) {
return x;
}
const auto y = inst.memory.image_address_components > 1u
? EmitImageAddressValueLoad(state, inst, inst.src[1], 1)
: ConstantU32(state, 0);
const auto coord = state.builder.AllocateId();
if (ImageViewCoordinateComponents(view) == 3u) {
if (components == 3u) {
const auto z = inst.memory.image_address_components > 2u
? EmitImageAddressValueLoad(state, inst, inst.src[1], 2)
: ConstantU32(state, 0);
@@ -191,12 +175,16 @@ uint32_t EmitImageCoordU32(EmitterState& state, const IR::Instruction& inst, Ima
uint32_t EmitImageLoadCoordU32(EmitterState& state, const IR::Instruction& inst,
ImageViewKind view) {
const auto x = EmitImageAddressValueLoad(state, inst, inst.src[0], 0);
const auto y = inst.memory.image_address_components > 1u
const auto x = EmitImageAddressValueLoad(state, inst, inst.src[0], 0);
const auto components = ImageViewCoordinateComponents(view);
if (components == 1u) {
return x;
}
const auto y = inst.memory.image_address_components > 1u
? EmitImageAddressValueLoad(state, inst, inst.src[0], 1)
: ConstantU32(state, 0);
const auto coord = state.builder.AllocateId();
if (ImageViewCoordinateComponents(view) == 3u) {
if (components == 3u) {
const auto z = inst.memory.image_address_components > 2u
? EmitImageAddressValueLoad(state, inst, inst.src[0], 2)
: ConstantU32(state, 0);
@@ -221,12 +209,16 @@ uint32_t EmitImageMipLodU32(EmitterState& state, const IR::Instruction& inst,
uint32_t EmitImageQueryCoordF32(EmitterState& state, const IR::Instruction& inst,
ImageViewKind view) {
const auto x = EmitImageAddressFloatLoad(state, inst, inst.src[0], 0);
const auto y = inst.memory.image_address_components > 1u
const auto x = EmitImageAddressFloatLoad(state, inst, inst.src[0], 0);
const auto components = ImageViewCoordinateComponents(view);
if (components == 1u) {
return x;
}
const auto y = inst.memory.image_address_components > 1u
? EmitImageAddressFloatLoad(state, inst, inst.src[0], 1)
: EmitZeroF32(state);
const auto coord = state.builder.AllocateId();
if (ImageViewCoordinateComponents(view) == 3u) {
if (components == 3u) {
const auto z = inst.memory.image_address_components > 2u
? EmitImageAddressFloatLoad(state, inst, inst.src[0], 2)
: EmitZeroF32(state);
@@ -11,7 +11,16 @@ uint32_t ConstantVec2I32(EmitterState& state, int32_t x, int32_t y) {
return value;
}
uint32_t ConstantImageGatherHorizontalOffsets(EmitterState& state) {
uint32_t ConstantImageGatherHorizontalOffsets(EmitterState& state, ImageViewKind view) {
if (ImageViewSpatialComponents(view) == 1u) {
const auto type = state.builder.AllocateId();
state.builder.AddType({OpTypeArray, type, state.int_type, ConstantU32(state, 4)});
const auto value = state.builder.AllocateId();
state.builder.AddType({OpConstantComposite, type, value, ConstantI32(state, -1),
ConstantI32(state, 0), ConstantI32(state, 1),
ConstantI32(state, 2)});
return value;
}
const auto offset0 = ConstantVec2I32(state, -1, 0);
const auto offset1 = ConstantVec2I32(state, 0, 0);
const auto offset2 = ConstantVec2I32(state, 1, 0);
@@ -23,56 +32,16 @@ uint32_t ConstantImageGatherHorizontalOffsets(EmitterState& state) {
return value;
}
IR::DescriptorBindingKind StorageImageBindingKind(ImageViewKind view, bool uint_image) {
switch (view) {
case ImageViewKind::Dim2D:
return uint_image ? IR::DescriptorBindingKind::StorageUint2D
: IR::DescriptorBindingKind::Storage2D;
case ImageViewKind::Dim2DArray:
return uint_image ? IR::DescriptorBindingKind::StorageUint2DArray
: IR::DescriptorBindingKind::Storage2DArray;
case ImageViewKind::Dim3D:
return uint_image ? IR::DescriptorBindingKind::StorageUint3D
: IR::DescriptorBindingKind::Storage3D;
default:
return uint_image ? IR::DescriptorBindingKind::StorageUint2D
: IR::DescriptorBindingKind::Storage2D;
}
}
uint32_t LoadStorageImageDescriptorAtIndex(EmitterState& state, uint32_t resource,
uint32_t array_index, bool uint_image,
ImageViewKind view) {
uint32_t pointer_type =
uint_image ? state.ptr_uniform_storage_image_uint : state.ptr_uniform_storage_image;
uint32_t variable =
uint_image ? state.storage_image_uint_variable : state.storage_image_variable;
uint32_t image_type = uint_image ? state.storage_image_uint_type : state.storage_image_type;
const auto kind = StorageImageBindingKind(view, uint_image);
switch (view) {
case ImageViewKind::Dim2D: break;
case ImageViewKind::Dim2DArray:
pointer_type = uint_image ? state.ptr_uniform_storage_image_uint_2d_array
: state.ptr_uniform_storage_image_2d_array;
variable = uint_image ? state.storage_image_uint_2d_array_variable
: state.storage_image_2d_array_variable;
image_type = uint_image ? state.storage_image_uint_2d_array_type
: state.storage_image_2d_array_type;
break;
case ImageViewKind::Dim3D:
pointer_type = uint_image ? state.ptr_uniform_storage_image_uint_3d
: state.ptr_uniform_storage_image_3d;
variable =
uint_image ? state.storage_image_uint_3d_variable : state.storage_image_3d_variable;
image_type =
uint_image ? state.storage_image_uint_3d_type : state.storage_image_3d_type;
break;
}
const auto kind = StorageBindingKind(uint_image, view);
const auto& descriptors = state.storage_images[StorageImageIndex(uint_image, view)];
const auto pointer =
DescriptorElementPointer(state, pointer_type, variable, array_index, kind, resource,
"storage image descriptor array was not emitted");
DescriptorElementPointer(state, descriptors.pointer_type, descriptors.variable, array_index,
kind, resource, "storage image descriptor array was not emitted");
const auto image = state.builder.AllocateId();
state.builder.AddFunction({OpLoad, image_type, image, pointer});
state.builder.AddFunction({OpLoad, descriptors.image_type, image, pointer});
return image;
}
@@ -80,24 +49,31 @@ uint32_t LoadStorageImageDescriptorAtIndex(EmitterState& state, uint32_t resourc
uint32_t EmitImageGetResinfoComponent(EmitterState& state, uint32_t image, uint32_t size,
uint32_t component_index, ImageViewKind view) {
const auto components = ImageViewCoordinateComponents(view);
switch (component_index) {
case 0: {
if (components == 1u) {
return size;
}
const auto width = state.builder.AllocateId();
state.builder.AddFunction({OpCompositeExtract, state.uint_type, width, size, 0});
return width;
}
case 1: {
if (components < 2u) {
return ConstantU32(state, 0);
}
const auto height = state.builder.AllocateId();
state.builder.AddFunction({OpCompositeExtract, state.uint_type, height, size, 1});
return height;
}
case 2:
if (ImageViewCoordinateComponents(view) == 3u) {
if (components == 3u) {
const auto depth = state.builder.AllocateId();
state.builder.AddFunction({OpCompositeExtract, state.uint_type, depth, size, 2});
return depth;
}
return ConstantU32(state, 1);
return ConstantU32(state, 0);
case 3: {
const auto levels = state.builder.AllocateId();
state.builder.AddFunction({OpImageQueryLevels, state.uint_type, levels, image});
@@ -182,7 +158,7 @@ void EmitImageLoad(EmitterState& state, const IR::Instruction& inst) {
void EmitImageStore(EmitterState& state, const IR::Instruction& inst) {
const auto uint_image = inst.memory.kind == IR::ResourceKind::StorageImageUint;
const auto view = StorageImageViewKind(state, inst.memory, uint_image, inst.pc);
const auto binding = ResourceForDescriptor(state, StorageImageBindingKind(view, uint_image),
const auto binding = ResourceForDescriptor(state, StorageBindingKind(uint_image, view),
inst.memory.resource);
const auto image = LoadStorageImageDescriptorAtIndex(state, inst.memory.resource,
binding.array_index, uint_image, view);
@@ -244,8 +220,9 @@ void AddImageSampleOperands(EmitterState& state, const IR::Instruction& inst,
// sampling because it modifies the hardware-computed LOD.
if (HasImageSampleFlag(inst, Decoder::ImageSampleFlagDerivative)) {
mask |= ImageOperandsGradMask;
operands.push_back(EmitImageGradientF32(state, inst, layout.grad_x));
operands.push_back(EmitImageGradientF32(state, inst, layout.grad_y));
const auto view = SampledImageViewKind(state, inst.memory, inst.pc);
operands.push_back(EmitImageGradientF32(state, inst, layout.grad_x, view));
operands.push_back(EmitImageGradientF32(state, inst, layout.grad_y, view));
} else if (explicit_lod) {
mask |= ImageOperandsLodMask;
operands.push_back(EmitImageLodF32(state, inst, layout));
@@ -286,10 +263,7 @@ void EmitImageSample(EmitterState& state, const IR::Instruction& inst) {
}
const auto explicit_lod = ImageSampleNeedsExplicitLod(state, inst);
const auto opcode = ImageSampleOpcode(state, inst);
const auto coord =
EmitImageOffsetCoordF32(state, inst, layout, sampled_image, base_coord, view);
std::vector<uint32_t> words = {opcode, result_type, sample, sampled_image, coord};
std::vector<uint32_t> words = {opcode, result_type, sample, sampled_image, base_coord};
if (dref) {
words.push_back(EmitImageDrefF32(state, inst, layout));
}
@@ -308,15 +282,16 @@ uint32_t ImageGatherComponent(uint32_t dmask) {
}
void AddImageGatherOperands(EmitterState& state, const IR::Instruction& inst,
const ImageSampleLayout& layout, std::vector<uint32_t>& words) {
const ImageSampleLayout& layout, ImageViewKind view,
std::vector<uint32_t>& words) {
if (HasImageSampleFlag(inst, Decoder::ImageSampleFlagGatherHorizontal)) {
words.push_back(ImageOperandsConstOffsetsMask);
words.push_back(ConstantImageGatherHorizontalOffsets(state));
words.push_back(ConstantImageGatherHorizontalOffsets(state, view));
return;
}
if (HasImageSampleFlag(inst, Decoder::ImageSampleFlagOffset)) {
words.push_back(ImageOperandsOffsetMask);
words.push_back(EmitImagePackedOffset2I32(state, inst, layout));
words.push_back(EmitImagePackedOffsetI32(state, inst, layout, view));
}
}
@@ -341,7 +316,7 @@ void EmitImageGather4(EmitterState& state, const IR::Instruction& inst) {
OpImageGather, result_type,
texels, sampled_image,
coord, ConstantU32(state, ImageGatherComponent(inst.memory.dmask))};
AddImageGatherOperands(state, inst, layout, words);
AddImageGatherOperands(state, inst, layout, view, words);
state.builder.AddFunction(words);
for (uint32_t i = 0; i < inst.memory.data_dwords; i++) {
@@ -35,6 +35,8 @@ enum : uint32_t {
MemoryModelGLSL450 = 1,
CapabilityShader = 1,
CapabilityImageGatherExtended = 25,
CapabilitySampled1D = 43,
CapabilityImage1D = 44,
CapabilityImageQuery = 50,
CapabilityStorageImageReadWithoutFormat = 55,
CapabilityStorageImageWriteWithoutFormat = 56,
@@ -83,6 +85,7 @@ enum : uint32_t {
};
enum : uint32_t {
Dim1D = 0,
Dim3D = 2,
Dim2D = 1,
ImageFormatUnknown = 0,
@@ -297,6 +300,14 @@ struct SampledImageDescriptors {
uint32_t variable = 0;
};
struct StorageImageDescriptors {
uint32_t image_type = 0;
uint32_t pointer_type = 0;
uint32_t array_type = 0;
uint32_t array_pointer_type = 0;
uint32_t variable = 0;
};
struct EmitterState {
EmitterState(const IR::Program& program_, const IR::ResourceSnapshot& resources_)
: program(program_), resources(resources_) {}
@@ -371,42 +382,13 @@ struct EmitterState {
uint32_t ptr_workgroup_array = 0;
uint32_t ptr_workgroup_uint = 0;
uint32_t lds_variable = 0;
std::array<SampledImageDescriptors, 6> sampled_images;
std::array<SampledImageDescriptors, 10> sampled_images;
std::array<StorageImageDescriptors, 10> storage_images;
uint32_t sampler_type = 0;
uint32_t sampler_array_type = 0;
uint32_t ptr_uniform_sampler = 0;
uint32_t ptr_uniform_sampler_array = 0;
uint32_t sampler_variable = 0;
uint32_t storage_image_type = 0;
uint32_t ptr_uniform_storage_image = 0;
uint32_t storage_image_array_type = 0;
uint32_t ptr_uniform_storage_image_array = 0;
uint32_t storage_image_variable = 0;
uint32_t storage_image_2d_array_type = 0;
uint32_t ptr_uniform_storage_image_2d_array = 0;
uint32_t storage_image_2d_array_array_type = 0;
uint32_t ptr_uniform_storage_image_2d_array_array = 0;
uint32_t storage_image_2d_array_variable = 0;
uint32_t storage_image_3d_type = 0;
uint32_t ptr_uniform_storage_image_3d = 0;
uint32_t storage_image_3d_array_type = 0;
uint32_t ptr_uniform_storage_image_3d_array = 0;
uint32_t storage_image_3d_variable = 0;
uint32_t storage_image_uint_type = 0;
uint32_t ptr_uniform_storage_image_uint = 0;
uint32_t storage_image_uint_array_type = 0;
uint32_t ptr_uniform_storage_image_uint_array = 0;
uint32_t storage_image_uint_variable = 0;
uint32_t storage_image_uint_2d_array_type = 0;
uint32_t ptr_uniform_storage_image_uint_2d_array = 0;
uint32_t storage_image_uint_2d_array_array_type = 0;
uint32_t ptr_uniform_storage_image_uint_2d_array_array = 0;
uint32_t storage_image_uint_2d_array_variable = 0;
uint32_t storage_image_uint_3d_type = 0;
uint32_t ptr_uniform_storage_image_uint_3d = 0;
uint32_t storage_image_uint_3d_array_type = 0;
uint32_t ptr_uniform_storage_image_uint_3d_array = 0;
uint32_t storage_image_uint_3d_variable = 0;
uint32_t ptr_image_uint = 0;
uint32_t func_type = 0;
uint32_t main_func = 0;
@@ -466,28 +448,82 @@ struct ImageSampleLayout {
};
enum class ImageViewKind {
Dim1D,
Dim1DArray,
Dim2D,
Dim2DArray,
Dim3D,
Count,
};
constexpr uint32_t ImageViewKindCount = static_cast<uint32_t>(ImageViewKind::Count);
constexpr uint32_t SampledImageIndex(bool integer, ImageViewKind view) {
return static_cast<uint32_t>(view) + (integer ? 3u : 0u);
return static_cast<uint32_t>(view) + (integer ? ImageViewKindCount : 0u);
}
constexpr uint32_t StorageImageIndex(bool integer, ImageViewKind view) {
return static_cast<uint32_t>(view) + (integer ? ImageViewKindCount : 0u);
}
constexpr IR::DescriptorBindingKind SampledBindingKind(bool integer, ImageViewKind view) {
if (integer) {
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;
default: return IR::DescriptorBindingKind::SampledUint2D;
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;
default: return IR::DescriptorBindingKind::Sampled2D;
default: break;
}
return IR::DescriptorBindingKind::Count;
}
constexpr IR::DescriptorBindingKind StorageBindingKind(bool integer, ImageViewKind view) {
if (integer) {
switch (view) {
case ImageViewKind::Dim1D: return IR::DescriptorBindingKind::StorageUint1D;
case ImageViewKind::Dim1DArray: return IR::DescriptorBindingKind::StorageUint1DArray;
case ImageViewKind::Dim2D: return IR::DescriptorBindingKind::StorageUint2D;
case ImageViewKind::Dim2DArray: return IR::DescriptorBindingKind::StorageUint2DArray;
case ImageViewKind::Dim3D: return IR::DescriptorBindingKind::StorageUint3D;
default: break;
}
}
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;
default: break;
}
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::Count: return Dim2D;
case ImageViewKind::Dim3D: return Dim3D;
}
return Dim2D;
}
constexpr uint32_t ImageSpirvArrayed(ImageViewKind view) {
return view == ImageViewKind::Dim1DArray || view == ImageViewKind::Dim2DArray ? 1u : 0u;
}
struct AddCarryResult {
@@ -632,6 +668,8 @@ ImageViewKind SampledImageViewKind(const EmitterState& state, const IR::MemoryIn
uint32_t ImageViewCoordinateComponents(ImageViewKind view);
uint32_t ImageViewSpatialComponents(ImageViewKind view);
uint32_t ImageViewImageType(const EmitterState& state, ImageViewKind view, bool integer);
uint32_t ImageViewSampledImageType(const EmitterState& state, ImageViewKind view, bool integer);
@@ -792,14 +830,10 @@ uint32_t EmitImageBiasF32(EmitterState& state, const IR::Instruction& inst,
const ImageSampleLayout& layout);
uint32_t EmitImageGradientF32(EmitterState& state, const IR::Instruction& inst,
uint32_t first_component);
uint32_t first_component, ImageViewKind view);
uint32_t EmitImagePackedOffset2I32(EmitterState& state, const IR::Instruction& inst,
const ImageSampleLayout& layout);
uint32_t EmitImageOffsetCoordF32(EmitterState& state, const IR::Instruction& inst,
const ImageSampleLayout& layout, uint32_t sampled_image,
uint32_t coord, ImageViewKind view);
uint32_t EmitImagePackedOffsetI32(EmitterState& state, const IR::Instruction& inst,
const ImageSampleLayout& layout, ImageViewKind view);
uint32_t EmitImageCoordU32(EmitterState& state, const IR::Instruction& inst,
ImageViewKind view = ImageViewKind::Dim2D);
@@ -324,36 +324,22 @@ void AddDescriptorAnnotationsAndNames(EmitterState& state) {
IR::DescriptorBindingKind::AddressMemory);
}
constexpr const char* SampledNames[] = {
"sampled_2d", "sampled_2d_array", "sampled_3d",
"sampled_1d", "sampled_1d_array", "sampled_2d", "sampled_2d_array",
"sampled_3d", "sampled_uint_1d", "sampled_uint_1d_array",
"sampled_uint_2d", "sampled_uint_2d_array", "sampled_uint_3d"};
for (uint32_t i = 0; i < state.sampled_images.size(); i++) {
const auto view = static_cast<ImageViewKind>(i % 3u);
const auto view = static_cast<ImageViewKind>(i % ImageViewKindCount);
Decorate(state.sampled_images[i].variable, SampledNames[i],
SampledBindingKind(i >= 3u, view));
SampledBindingKind(i >= ImageViewKindCount, view));
}
if (state.storage_image_variable != 0) {
Decorate(state.storage_image_variable, "textures2D_L",
IR::DescriptorBindingKind::Storage2D);
}
if (state.storage_image_uint_variable != 0) {
Decorate(state.storage_image_uint_variable, "textures2D_L_U",
IR::DescriptorBindingKind::StorageUint2D);
}
if (state.storage_image_2d_array_variable != 0) {
Decorate(state.storage_image_2d_array_variable, "textures2D_L_A",
IR::DescriptorBindingKind::Storage2DArray);
}
if (state.storage_image_uint_2d_array_variable != 0) {
Decorate(state.storage_image_uint_2d_array_variable, "textures2D_L_U_A",
IR::DescriptorBindingKind::StorageUint2DArray);
}
if (state.storage_image_3d_variable != 0) {
Decorate(state.storage_image_3d_variable, "textures2D_L_3D",
IR::DescriptorBindingKind::Storage3D);
}
if (state.storage_image_uint_3d_variable != 0) {
Decorate(state.storage_image_uint_3d_variable, "textures2D_L_U_3D",
IR::DescriptorBindingKind::StorageUint3D);
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"};
for (uint32_t i = 0; i < state.storage_images.size(); i++) {
const auto view = static_cast<ImageViewKind>(i % ImageViewKindCount);
Decorate(state.storage_images[i].variable, StorageNames[i],
StorageBindingKind(i >= ImageViewKindCount, view));
}
if (state.sampler_variable != 0) {
Decorate(state.sampler_variable, "samplers", IR::DescriptorBindingKind::Samplers);
@@ -452,34 +438,16 @@ void EmitHeaderAndTypes(EmitterState& state) {
image.array_type = state.builder.AllocateId();
image.array_pointer_type = state.builder.AllocateId();
}
for (auto& image: state.storage_images) {
image.image_type = state.builder.AllocateId();
image.pointer_type = state.builder.AllocateId();
image.array_type = state.builder.AllocateId();
image.array_pointer_type = state.builder.AllocateId();
}
state.sampler_type = state.builder.AllocateId();
state.sampler_array_type = state.builder.AllocateId();
state.ptr_uniform_sampler = state.builder.AllocateId();
state.ptr_uniform_sampler_array = state.builder.AllocateId();
state.storage_image_type = state.builder.AllocateId();
state.ptr_uniform_storage_image = state.builder.AllocateId();
state.storage_image_array_type = state.builder.AllocateId();
state.ptr_uniform_storage_image_array = state.builder.AllocateId();
state.storage_image_2d_array_type = state.builder.AllocateId();
state.ptr_uniform_storage_image_2d_array = state.builder.AllocateId();
state.storage_image_2d_array_array_type = state.builder.AllocateId();
state.ptr_uniform_storage_image_2d_array_array = state.builder.AllocateId();
state.storage_image_3d_type = state.builder.AllocateId();
state.ptr_uniform_storage_image_3d = state.builder.AllocateId();
state.storage_image_3d_array_type = state.builder.AllocateId();
state.ptr_uniform_storage_image_3d_array = state.builder.AllocateId();
state.storage_image_uint_type = state.builder.AllocateId();
state.ptr_uniform_storage_image_uint = state.builder.AllocateId();
state.storage_image_uint_array_type = state.builder.AllocateId();
state.ptr_uniform_storage_image_uint_array = state.builder.AllocateId();
state.storage_image_uint_2d_array_type = state.builder.AllocateId();
state.ptr_uniform_storage_image_uint_2d_array = state.builder.AllocateId();
state.storage_image_uint_2d_array_array_type = state.builder.AllocateId();
state.ptr_uniform_storage_image_uint_2d_array_array = state.builder.AllocateId();
state.storage_image_uint_3d_type = state.builder.AllocateId();
state.ptr_uniform_storage_image_uint_3d = state.builder.AllocateId();
state.storage_image_uint_3d_array_type = state.builder.AllocateId();
state.ptr_uniform_storage_image_uint_3d_array = state.builder.AllocateId();
state.ptr_image_uint = state.builder.AllocateId();
state.func_type = state.builder.AllocateId();
state.main_func = state.builder.AllocateId();
@@ -487,12 +455,15 @@ void EmitHeaderAndTypes(EmitterState& state) {
state.glsl_std450 = state.builder.AllocateId();
state.builder.AddCapability({CapabilityShader});
state.builder.AddCapability({CapabilitySampled1D});
state.builder.AddCapability({CapabilityImage1D});
state.builder.AddCapability({CapabilityImageQuery});
if (state.needs_image_gather_extended) {
state.builder.AddCapability({CapabilityImageGatherExtended});
}
if (state.storage_image_variable != 0 || state.storage_image_2d_array_variable != 0 ||
state.storage_image_3d_variable != 0) {
if (std::any_of(state.storage_images.begin(),
state.storage_images.begin() + ImageViewKindCount,
[](const auto& image) { return image.variable != 0; })) {
state.builder.AddCapability({CapabilityStorageImageReadWithoutFormat});
state.builder.AddCapability({CapabilityStorageImageWriteWithoutFormat});
}
@@ -729,17 +700,17 @@ void EmitHeaderAndTypes(EmitterState& state) {
}
for (uint32_t i = 0; i < state.sampled_images.size(); i++) {
auto& image = state.sampled_images[i];
const auto view = static_cast<ImageViewKind>(i % 3u);
const auto component = i >= 3u ? state.uint_type : state.float_type;
const auto dimension = view == ImageViewKind::Dim3D ? Dim3D : Dim2D;
const auto arrayed = view == ImageViewKind::Dim2DArray ? 1u : 0u;
state.builder.AddType({OpTypeImage, image.image_type, component, dimension, 0, arrayed, 0,
1, ImageFormatUnknown});
const auto view = static_cast<ImageViewKind>(i % ImageViewKindCount);
const bool integer = i >= ImageViewKindCount;
const auto component = integer ? state.uint_type : state.float_type;
state.builder.AddType({OpTypeImage, image.image_type, component,
ImageSpirvDimension(view), 0, ImageSpirvArrayed(view), 0, 1,
ImageFormatUnknown});
state.builder.AddType({OpTypeSampledImage, image.sampled_image_type, image.image_type});
state.builder.AddType(
{OpTypePointer, image.pointer_type, StorageClassUniformConstant, image.image_type});
if (image.variable != 0) {
const auto kind = SampledBindingKind(i >= 3u, view);
const auto kind = SampledBindingKind(integer, view);
const auto count = ConstantU32(state, DescriptorCount(state, kind));
state.builder.AddType({OpTypeArray, image.array_type, image.image_type, count});
state.builder.AddType({OpTypePointer, image.array_pointer_type,
@@ -760,93 +731,26 @@ void EmitHeaderAndTypes(EmitterState& state) {
state.builder.AddType({OpVariable, state.ptr_uniform_sampler_array, state.sampler_variable,
StorageClassUniformConstant});
}
state.builder.AddType({OpTypeImage, state.storage_image_type, state.float_type, Dim2D, 0, 0, 0,
2, ImageFormatUnknown});
state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image,
StorageClassUniformConstant, state.storage_image_type});
if (state.storage_image_variable != 0) {
const auto count =
ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::Storage2D));
for (uint32_t i = 0; i < state.storage_images.size(); i++) {
auto& image = state.storage_images[i];
const auto view = static_cast<ImageViewKind>(i % ImageViewKindCount);
const bool integer = i >= ImageViewKindCount;
const auto component = integer ? state.uint_type : state.float_type;
const auto format = integer ? ImageFormatR32ui : ImageFormatUnknown;
state.builder.AddType({OpTypeImage, image.image_type, component,
ImageSpirvDimension(view), 0, ImageSpirvArrayed(view), 0, 2,
format});
state.builder.AddType(
{OpTypeArray, state.storage_image_array_type, state.storage_image_type, count});
state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_array,
StorageClassUniformConstant, state.storage_image_array_type});
state.builder.AddType({OpVariable, state.ptr_uniform_storage_image_array,
state.storage_image_variable, StorageClassUniformConstant});
}
state.builder.AddType({OpTypeImage, state.storage_image_2d_array_type, state.float_type, Dim2D,
0, 1, 0, 2, ImageFormatUnknown});
state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_2d_array,
StorageClassUniformConstant, state.storage_image_2d_array_type});
if (state.storage_image_2d_array_variable != 0) {
const auto count =
ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::Storage2DArray));
state.builder.AddType({OpTypeArray, state.storage_image_2d_array_array_type,
state.storage_image_2d_array_type, count});
state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_2d_array_array,
StorageClassUniformConstant,
state.storage_image_2d_array_array_type});
state.builder.AddType({OpVariable, state.ptr_uniform_storage_image_2d_array_array,
state.storage_image_2d_array_variable, StorageClassUniformConstant});
}
state.builder.AddType({OpTypeImage, state.storage_image_3d_type, state.float_type, Dim3D, 0, 0,
0, 2, ImageFormatUnknown});
state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_3d,
StorageClassUniformConstant, state.storage_image_3d_type});
if (state.storage_image_3d_variable != 0) {
const auto count =
ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::Storage3D));
state.builder.AddType(
{OpTypeArray, state.storage_image_3d_array_type, state.storage_image_3d_type, count});
state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_3d_array,
StorageClassUniformConstant, state.storage_image_3d_array_type});
state.builder.AddType({OpVariable, state.ptr_uniform_storage_image_3d_array,
state.storage_image_3d_variable, StorageClassUniformConstant});
}
state.builder.AddType({OpTypeImage, state.storage_image_uint_type, state.uint_type, Dim2D, 0, 0,
0, 2, ImageFormatR32ui});
state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_uint,
StorageClassUniformConstant, state.storage_image_uint_type});
if (state.storage_image_uint_variable != 0) {
const auto count =
ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::StorageUint2D));
state.builder.AddType({OpTypeArray, state.storage_image_uint_array_type,
state.storage_image_uint_type, count});
state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_uint_array,
StorageClassUniformConstant, state.storage_image_uint_array_type});
state.builder.AddType({OpVariable, state.ptr_uniform_storage_image_uint_array,
state.storage_image_uint_variable, StorageClassUniformConstant});
}
state.builder.AddType({OpTypeImage, state.storage_image_uint_2d_array_type, state.uint_type,
Dim2D, 0, 1, 0, 2, ImageFormatR32ui});
state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_uint_2d_array,
StorageClassUniformConstant, state.storage_image_uint_2d_array_type});
if (state.storage_image_uint_2d_array_variable != 0) {
const auto count = ConstantU32(
state, DescriptorCount(state, IR::DescriptorBindingKind::StorageUint2DArray));
state.builder.AddType({OpTypeArray, state.storage_image_uint_2d_array_array_type,
state.storage_image_uint_2d_array_type, count});
state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_uint_2d_array_array,
StorageClassUniformConstant,
state.storage_image_uint_2d_array_array_type});
state.builder.AddType({OpVariable, state.ptr_uniform_storage_image_uint_2d_array_array,
state.storage_image_uint_2d_array_variable,
StorageClassUniformConstant});
}
state.builder.AddType({OpTypeImage, state.storage_image_uint_3d_type, state.uint_type, Dim3D, 0,
0, 0, 2, ImageFormatR32ui});
state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_uint_3d,
StorageClassUniformConstant, state.storage_image_uint_3d_type});
if (state.storage_image_uint_3d_variable != 0) {
const auto count =
ConstantU32(state, DescriptorCount(state, IR::DescriptorBindingKind::StorageUint3D));
state.builder.AddType({OpTypeArray, state.storage_image_uint_3d_array_type,
state.storage_image_uint_3d_type, count});
state.builder.AddType({OpTypePointer, state.ptr_uniform_storage_image_uint_3d_array,
StorageClassUniformConstant,
state.storage_image_uint_3d_array_type});
state.builder.AddType({OpVariable, state.ptr_uniform_storage_image_uint_3d_array,
state.storage_image_uint_3d_variable, StorageClassUniformConstant});
{OpTypePointer, image.pointer_type, StorageClassUniformConstant, image.image_type});
if (image.variable != 0) {
const auto kind = StorageBindingKind(integer, view);
const auto count = ConstantU32(state, DescriptorCount(state, kind));
state.builder.AddType({OpTypeArray, image.array_type, image.image_type, count});
state.builder.AddType({OpTypePointer, image.array_pointer_type,
StorageClassUniformConstant, image.array_type});
state.builder.AddType({OpVariable, image.array_pointer_type, image.variable,
StorageClassUniformConstant});
}
}
state.builder.AddType(
{OpTypePointer, state.ptr_image_uint, StorageClassImage, state.uint_type});
@@ -882,28 +786,18 @@ void AllocateDescriptorVariables(EmitterState& state) {
state.flattened_srt_variable = state.builder.AllocateId();
}
for (uint32_t i = 0; i < state.sampled_images.size(); i++) {
const auto view = static_cast<ImageViewKind>(i % 3u);
if (DescriptorBinding(state, SampledBindingKind(i >= 3u, view)) != nullptr) {
const auto view = static_cast<ImageViewKind>(i % ImageViewKindCount);
if (DescriptorBinding(state, SampledBindingKind(i >= ImageViewKindCount, view)) !=
nullptr) {
state.sampled_images[i].variable = state.builder.AllocateId();
}
}
if (DescriptorBinding(state, IR::DescriptorBindingKind::Storage2D) != nullptr) {
state.storage_image_variable = state.builder.AllocateId();
}
if (DescriptorBinding(state, IR::DescriptorBindingKind::StorageUint2D) != nullptr) {
state.storage_image_uint_variable = state.builder.AllocateId();
}
if (DescriptorBinding(state, IR::DescriptorBindingKind::Storage2DArray) != nullptr) {
state.storage_image_2d_array_variable = state.builder.AllocateId();
}
if (DescriptorBinding(state, IR::DescriptorBindingKind::StorageUint2DArray) != nullptr) {
state.storage_image_uint_2d_array_variable = state.builder.AllocateId();
}
if (DescriptorBinding(state, IR::DescriptorBindingKind::Storage3D) != nullptr) {
state.storage_image_3d_variable = state.builder.AllocateId();
}
if (DescriptorBinding(state, IR::DescriptorBindingKind::StorageUint3D) != nullptr) {
state.storage_image_uint_3d_variable = state.builder.AllocateId();
for (uint32_t i = 0; i < state.storage_images.size(); i++) {
const auto view = static_cast<ImageViewKind>(i % ImageViewKindCount);
if (DescriptorBinding(state, StorageBindingKind(i >= ImageViewKindCount, view)) !=
nullptr) {
state.storage_images[i].variable = state.builder.AllocateId();
}
}
if (DescriptorBinding(state, IR::DescriptorBindingKind::Samplers) != nullptr) {
state.sampler_variable = state.builder.AllocateId();