mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 05:46:56 +01:00
shader: simplify typed image bindings
This commit is contained in:
@@ -48,67 +48,27 @@ namespace {
|
|||||||
|
|
||||||
using BindingKind = ShaderRecompiler::IR::DescriptorBindingKind;
|
using BindingKind = ShaderRecompiler::IR::DescriptorBindingKind;
|
||||||
|
|
||||||
bool IsSampledImage(BindingKind kind) {
|
|
||||||
switch (kind) {
|
|
||||||
case BindingKind::Sampled1D:
|
|
||||||
case BindingKind::Sampled1DArray:
|
|
||||||
case BindingKind::Sampled2D:
|
|
||||||
case BindingKind::Sampled2DArray:
|
|
||||||
case BindingKind::Sampled2DMsaa:
|
|
||||||
case BindingKind::Sampled2DMsaaArray:
|
|
||||||
case BindingKind::Sampled3D:
|
|
||||||
case BindingKind::SampledUint1D:
|
|
||||||
case BindingKind::SampledUint1DArray:
|
|
||||||
case BindingKind::SampledUint2D:
|
|
||||||
case BindingKind::SampledUint2DArray:
|
|
||||||
case BindingKind::SampledUint2DMsaa:
|
|
||||||
case BindingKind::SampledUint2DMsaaArray:
|
|
||||||
case BindingKind::SampledUint3D:
|
|
||||||
case BindingKind::SampledSint1D:
|
|
||||||
case BindingKind::SampledSint1DArray:
|
|
||||||
case BindingKind::SampledSint2D:
|
|
||||||
case BindingKind::SampledSint2DArray:
|
|
||||||
case BindingKind::SampledSint2DMsaa:
|
|
||||||
case BindingKind::SampledSint2DMsaaArray:
|
|
||||||
case BindingKind::SampledSint3D: return true;
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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:
|
|
||||||
case BindingKind::StorageAtomic1D:
|
|
||||||
case BindingKind::StorageAtomic1DArray:
|
|
||||||
case BindingKind::StorageAtomic2D:
|
|
||||||
case BindingKind::StorageAtomic2DArray:
|
|
||||||
case BindingKind::StorageAtomic3D: return true;
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
vk::DescriptorType NativeDescriptorType(BindingKind kind) {
|
vk::DescriptorType NativeDescriptorType(BindingKind kind) {
|
||||||
if (kind == BindingKind::Samplers) {
|
const auto image_class = ShaderRecompiler::IR::ImageBindingResourceClass(kind);
|
||||||
return vk::DescriptorType::eSampler;
|
if (image_class == ShaderRecompiler::IR::ImageResourceClass::Sampled) {
|
||||||
}
|
|
||||||
if (IsSampledImage(kind)) {
|
|
||||||
return vk::DescriptorType::eSampledImage;
|
return vk::DescriptorType::eSampledImage;
|
||||||
}
|
}
|
||||||
if (IsStorageImage(kind)) {
|
if (image_class == ShaderRecompiler::IR::ImageResourceClass::Storage) {
|
||||||
return vk::DescriptorType::eStorageImage;
|
return vk::DescriptorType::eStorageImage;
|
||||||
}
|
}
|
||||||
return vk::DescriptorType::eStorageBuffer;
|
switch (kind) {
|
||||||
|
case BindingKind::Samplers: return vk::DescriptorType::eSampler;
|
||||||
|
case BindingKind::Buffers:
|
||||||
|
case BindingKind::Gds:
|
||||||
|
case BindingKind::BdaPagetable:
|
||||||
|
case BindingKind::FaultBuffer:
|
||||||
|
case BindingKind::FlattenedSrt:
|
||||||
|
case BindingKind::UserData: return vk::DescriptorType::eStorageBuffer;
|
||||||
|
case BindingKind::Count: EXIT("invalid native descriptor binding kind");
|
||||||
|
}
|
||||||
|
EXIT("invalid native descriptor binding kind");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t NativeDescriptorCount(const ShaderRecompiler::IR::DescriptorBinding& binding) {
|
uint32_t NativeDescriptorCount(const ShaderRecompiler::IR::DescriptorBinding& binding) {
|
||||||
@@ -1181,48 +1141,54 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
|
|||||||
write.descriptorCount = NativeDescriptorCount(binding);
|
write.descriptorCount = NativeDescriptorCount(binding);
|
||||||
const auto buffer_start = m_descriptor_buffers.size();
|
const auto buffer_start = m_descriptor_buffers.size();
|
||||||
const auto image_start = m_descriptor_images.size();
|
const auto image_start = m_descriptor_images.size();
|
||||||
switch (binding.kind) {
|
if (ShaderRecompiler::IR::ImageBindingResourceClass(binding.kind) !=
|
||||||
case BindingKind::Buffers:
|
ShaderRecompiler::IR::ImageResourceClass::None) {
|
||||||
for (const auto resource: binding.resources) {
|
for (const auto resource: binding.resources) {
|
||||||
const auto& view = descriptors.buffers.at(resource);
|
m_descriptor_images.push_back(MakeImageInfo(
|
||||||
EXIT_IF(view.buffer == nullptr);
|
descriptors.images.at(resource), m_image_occurrences.at(resource)++));
|
||||||
m_descriptor_buffers.emplace_back(view.buffer, view.offset, view.range);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BindingKind::BdaPagetable:
|
|
||||||
case BindingKind::FaultBuffer: {
|
|
||||||
auto& cache = m_context.GetBufferCache();
|
|
||||||
const auto* bda_buffer = binding.kind == BindingKind::BdaPagetable
|
|
||||||
? cache.GetBdaPageTableBuffer()
|
|
||||||
: cache.GetFaultBuffer();
|
|
||||||
m_descriptor_buffers.emplace_back(bda_buffer->Handle(), 0, bda_buffer->Size());
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case BindingKind::FlattenedSrt:
|
} else {
|
||||||
case BindingKind::UserData:
|
switch (binding.kind) {
|
||||||
case BindingKind::Gds: {
|
case BindingKind::Buffers:
|
||||||
const auto& view =
|
for (const auto resource: binding.resources) {
|
||||||
binding.kind == BindingKind::FlattenedSrt ? descriptors.flattened_srt
|
const auto& view = descriptors.buffers.at(resource);
|
||||||
: binding.kind == BindingKind::UserData ? descriptors.user_data
|
EXIT_IF(view.buffer == nullptr);
|
||||||
: descriptors.gds;
|
m_descriptor_buffers.emplace_back(view.buffer, view.offset, view.range);
|
||||||
EXIT_IF(view.buffer == nullptr);
|
}
|
||||||
m_descriptor_buffers.emplace_back(view.buffer, view.offset, view.range);
|
break;
|
||||||
break;
|
case BindingKind::BdaPagetable:
|
||||||
|
case BindingKind::FaultBuffer: {
|
||||||
|
auto& cache = m_context.GetBufferCache();
|
||||||
|
const auto* bda_buffer = binding.kind == BindingKind::BdaPagetable
|
||||||
|
? cache.GetBdaPageTableBuffer()
|
||||||
|
: cache.GetFaultBuffer();
|
||||||
|
m_descriptor_buffers.emplace_back(bda_buffer->Handle(), 0,
|
||||||
|
bda_buffer->Size());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BindingKind::FlattenedSrt:
|
||||||
|
case BindingKind::UserData:
|
||||||
|
case BindingKind::Gds: {
|
||||||
|
const BufferView* view = &descriptors.gds;
|
||||||
|
if (binding.kind == BindingKind::FlattenedSrt) {
|
||||||
|
view = &descriptors.flattened_srt;
|
||||||
|
} else if (binding.kind == BindingKind::UserData) {
|
||||||
|
view = &descriptors.user_data;
|
||||||
|
}
|
||||||
|
EXIT_IF(view->buffer == nullptr);
|
||||||
|
m_descriptor_buffers.emplace_back(view->buffer, view->offset, view->range);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BindingKind::Samplers:
|
||||||
|
for (const auto resource: binding.resources) {
|
||||||
|
const auto sampler = descriptors.samplers.at(resource);
|
||||||
|
EXIT_IF(sampler == nullptr);
|
||||||
|
m_descriptor_images.emplace_back(sampler, nullptr,
|
||||||
|
vk::ImageLayout::eUndefined);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BindingKind::Count: EXIT("invalid descriptor binding kind");
|
||||||
}
|
}
|
||||||
case BindingKind::Samplers:
|
|
||||||
for (const auto resource: binding.resources) {
|
|
||||||
const auto sampler = descriptors.samplers.at(resource);
|
|
||||||
EXIT_IF(sampler == nullptr);
|
|
||||||
m_descriptor_images.emplace_back(sampler, nullptr,
|
|
||||||
vk::ImageLayout::eUndefined);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
for (const auto resource: binding.resources) {
|
|
||||||
m_descriptor_images.push_back(MakeImageInfo(
|
|
||||||
descriptors.images.at(resource), m_image_occurrences.at(resource)++));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (m_descriptor_buffers.size() != buffer_start) {
|
if (m_descriptor_buffers.size() != buffer_start) {
|
||||||
write.pBufferInfo = m_descriptor_buffers.data() + buffer_start;
|
write.pBufferInfo = m_descriptor_buffers.data() + buffer_start;
|
||||||
|
|||||||
@@ -124,34 +124,42 @@ const ImageDimensionInfo& ImageDimensionInfoFor(ImageDimension dimension) {
|
|||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t SampledImageScalarType(EmitterState& state, SampledImageClass image_class) {
|
uint32_t ImageScalarType(EmitterState& state, Prospero::TextureNumericClass numeric_class) {
|
||||||
switch (image_class) {
|
switch (numeric_class) {
|
||||||
case SampledImageClass::Float: return TypeF32(state);
|
case Prospero::TextureNumericClass::Float: return TypeF32(state);
|
||||||
case SampledImageClass::Uint: return TypeU32(state);
|
case Prospero::TextureNumericClass::Uint: return TypeU32(state);
|
||||||
case SampledImageClass::Sint: return TypeI32(state);
|
case Prospero::TextureNumericClass::Sint: return TypeI32(state);
|
||||||
case SampledImageClass::Count: break;
|
case Prospero::TextureNumericClass::Unsupported: break;
|
||||||
}
|
}
|
||||||
return 0;
|
EXIT("invalid image numeric class");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t SampledImageVectorType(EmitterState& state, SampledImageClass image_class,
|
uint32_t ImageVectorType(EmitterState& state, Prospero::TextureNumericClass numeric_class,
|
||||||
uint32_t components) {
|
uint32_t components) {
|
||||||
return state.builder.Type(OpTypeVector,
|
return state.builder.Type(OpTypeVector, {ImageScalarType(state, numeric_class), components});
|
||||||
{SampledImageScalarType(state, image_class), components});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ImageViewImageType(EmitterState& state, ImageDimension dimension,
|
uint32_t ImageType(EmitterState& state, const IR::ImageResource& image) {
|
||||||
SampledImageClass image_class) {
|
uint32_t sampled = 0;
|
||||||
const auto& info = ImageDimensionInfoFor(dimension);
|
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,
|
return state.builder.Type(OpTypeImage,
|
||||||
{SampledImageScalarType(state, image_class), info.spirv_dimension, 0,
|
{ImageScalarType(state, image.numeric_class), info.spirv_dimension, 0,
|
||||||
info.arrayed, info.multisampled, 1, ImageFormatUnknown});
|
info.arrayed, info.multisampled, sampled, format});
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ImageViewSampledImageType(EmitterState& state, ImageDimension dimension,
|
|
||||||
SampledImageClass image_class) {
|
|
||||||
return state.builder.Type(OpTypeSampledImage,
|
|
||||||
{ImageViewImageType(state, dimension, image_class)});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ImageViewSizeType(EmitterState& state, ImageDimension dimension) {
|
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) {
|
uint32_t LoadSampledImageDescriptor(EmitterState& state, uint32_t resource) {
|
||||||
const auto& image_resource = state.program.info.images.at(resource);
|
const auto& image_resource = state.program.info.images.at(resource);
|
||||||
EXIT_IF(image_resource.resource_class != IR::ImageResourceClass::Sampled);
|
EXIT_IF(image_resource.resource_class != IR::ImageResourceClass::Sampled);
|
||||||
const auto dimension = image_resource.dimension;
|
const auto kind = IR::DescriptorBindingForImage(image_resource);
|
||||||
const auto image_class = SampledImageClassFor(image_resource.numeric_class);
|
EXIT_IF(!kind.has_value());
|
||||||
EXIT_IF(image_class == SampledImageClass::Count);
|
const auto array_index = ResourceForDescriptor(state, *kind, resource);
|
||||||
const auto kind = SampledBindingKind(image_class, dimension);
|
const auto variable = state.image_variables[IR::ImageBindingIndex(*kind)];
|
||||||
const auto array_index = ResourceForDescriptor(state, kind, resource);
|
const auto pointer_type = state.builder.Type(
|
||||||
const auto variable = state.sampled_image_variables[SampledImageIndex(image_class, dimension)];
|
OpTypePointer, {StorageClassUniformConstant, ImageType(state, image_resource)});
|
||||||
const auto pointer_type =
|
|
||||||
state.builder.Type(OpTypePointer, {StorageClassUniformConstant,
|
|
||||||
ImageViewImageType(state, dimension, image_class)});
|
|
||||||
const auto pointer =
|
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");
|
"sampled image descriptor array was not emitted");
|
||||||
const auto image = state.builder.AllocateId();
|
const auto image = state.builder.AllocateId();
|
||||||
state.builder.AddFunction(
|
state.builder.AddFunction({OpLoad, ImageType(state, image_resource), image, pointer});
|
||||||
{OpLoad, ImageViewImageType(state, dimension, image_class), image, pointer});
|
|
||||||
return image;
|
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) {
|
uint32_t MakeSampledImage(EmitterState& state, uint32_t resource, uint32_t sampler) {
|
||||||
const auto& image_resource = state.program.info.images.at(resource);
|
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 image = LoadSampledImageDescriptor(state, resource);
|
||||||
const auto sampler_id = LoadSamplerDescriptor(state, sampler);
|
const auto sampler_id = LoadSamplerDescriptor(state, sampler);
|
||||||
if (image == 0 || sampler_id == 0) {
|
const auto sampled_image = state.builder.AllocateId();
|
||||||
ExitDescriptorBindingFailure(state, SampledBindingKind(image_class, dimension), resource,
|
const auto sampled_type =
|
||||||
"sampled image or sampler descriptor load failed");
|
state.builder.Type(OpTypeSampledImage, {ImageType(state, image_resource)});
|
||||||
}
|
state.builder.AddFunction({OpSampledImage, sampled_type, sampled_image, image, sampler_id});
|
||||||
const auto sampled_image = state.builder.AllocateId();
|
|
||||||
state.builder.AddFunction({OpSampledImage,
|
|
||||||
ImageViewSampledImageType(state, dimension, image_class),
|
|
||||||
sampled_image, image, sampler_id});
|
|
||||||
return sampled_image;
|
return sampled_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource) {
|
uint32_t StorageImageDescriptorPointer(EmitterState& state, uint32_t resource) {
|
||||||
const auto dimension = state.program.info.images.at(resource).dimension;
|
const auto& image = state.program.info.images.at(resource);
|
||||||
const auto image_class = StorageImageClassForResource(state, resource);
|
EXIT_IF(image.resource_class != IR::ImageResourceClass::Storage);
|
||||||
const auto kind = StorageBindingKind(image_class, dimension);
|
const auto kind = IR::DescriptorBindingForImage(image);
|
||||||
const auto array_index = ResourceForDescriptor(state, kind, resource);
|
EXIT_IF(!kind.has_value());
|
||||||
const auto ptr_type = StorageImagePointerType(state, image_class, dimension);
|
const auto array_index = ResourceForDescriptor(state, *kind, resource);
|
||||||
const auto variable = state.storage_image_variables[StorageImageIndex(image_class, dimension)];
|
const auto pointer_type =
|
||||||
return DescriptorElementPointer(state, ptr_type, variable, array_index, kind, resource,
|
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");
|
"storage image descriptor array was not emitted");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitStorageImageWrite(EmitterState& state, uint32_t resource, uint32_t mip_lod, uint32_t coord,
|
void EmitStorageImageWrite(EmitterState& state, uint32_t resource, uint32_t mip_lod, uint32_t coord,
|
||||||
uint32_t texel) {
|
uint32_t texel) {
|
||||||
const auto dimension = state.program.info.images.at(resource).dimension;
|
const auto& image = state.program.info.images.at(resource);
|
||||||
const auto image_class = StorageImageClassForResource(state, resource);
|
EXIT_IF(image.resource_class != IR::ImageResourceClass::Storage);
|
||||||
if (image_class != StorageImageClass::AtomicUint) {
|
if (!image.atomic) {
|
||||||
state.builder.RequireCapability(CapabilityStorageImageWriteWithoutFormat);
|
state.builder.RequireCapability(CapabilityStorageImageWriteWithoutFormat);
|
||||||
}
|
}
|
||||||
const auto kind = StorageBindingKind(image_class, dimension);
|
const auto kind = IR::DescriptorBindingForImage(image);
|
||||||
const auto array_index = ResourceForDescriptor(state, kind, resource);
|
EXIT_IF(!kind.has_value());
|
||||||
const auto& image = state.program.info.images.at(resource);
|
const auto array_index = ResourceForDescriptor(state, *kind, resource);
|
||||||
const auto LoadAt = [&](uint32_t array_index) {
|
const auto image_type = ImageType(state, image);
|
||||||
const auto pointer = DescriptorElementPointer(
|
const auto pointer_type =
|
||||||
state, StorageImagePointerType(state, image_class, dimension),
|
state.builder.Type(OpTypePointer, {StorageClassUniformConstant, image_type});
|
||||||
state.storage_image_variables[StorageImageIndex(image_class, dimension)], array_index,
|
const auto variable = state.image_variables[IR::ImageBindingIndex(*kind)];
|
||||||
kind, resource, "storage image descriptor array was not emitted");
|
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();
|
const auto descriptor = state.builder.AllocateId();
|
||||||
state.builder.AddFunction(
|
state.builder.AddFunction({OpLoad, image_type, descriptor, pointer});
|
||||||
{OpLoad, StorageImageType(state, image_class, dimension), descriptor, pointer});
|
|
||||||
return descriptor;
|
return descriptor;
|
||||||
};
|
};
|
||||||
if (image.mip_mode != IR::ImageMipMode::DynamicStorage) {
|
if (image.mip_mode != IR::ImageMipMode::DynamicStorage) {
|
||||||
@@ -289,7 +253,7 @@ void EmitStorageImageWrite(EmitterState& state, uint32_t resource, uint32_t mip_
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (image.mip_count == 0u) {
|
if (image.mip_count == 0u) {
|
||||||
ExitDescriptorBindingFailure(state, kind, resource,
|
ExitDescriptorBindingFailure(state, *kind, resource,
|
||||||
"dynamic storage image has no mip descriptors");
|
"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,
|
uint32_t SampledComponentBits(ValueEmitContext& ctx, uint32_t value,
|
||||||
SampledImageClass image_class) {
|
Prospero::TextureNumericClass numeric_class) {
|
||||||
return image_class == SampledImageClass::Uint
|
if (numeric_class == Prospero::TextureNumericClass::Uint) {
|
||||||
? value
|
return 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;
|
|
||||||
}
|
}
|
||||||
return 0;
|
return Unary(ctx.state, OpBitcast, TypeU32(ctx.state), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ResultVector(ValueEmitContext& ctx, uint32_t value, SampledImageClass image_class,
|
uint32_t SampledComponentZero(EmitterState& state, Prospero::TextureNumericClass numeric_class) {
|
||||||
bool dref, const IR::MemoryInfo& mem, bool gather = false) {
|
switch (numeric_class) {
|
||||||
const auto value_class = dref ? SampledImageClass::Float : image_class;
|
case Prospero::TextureNumericClass::Float: return ZeroF32(state);
|
||||||
const bool integer = IsIntegerSampledImage(value_class);
|
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) {
|
if (mem.data_bits == 16u) {
|
||||||
uint32_t packed[4] = {ConstantU32(ctx.state, 0), ConstantU32(ctx.state, 0),
|
uint32_t packed[4] = {ConstantU32(ctx.state, 0), ConstantU32(ctx.state, 0),
|
||||||
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 component = gather ? index : DmaskComponent(mem.dmask, index);
|
||||||
const auto result = ctx.state.builder.AllocateId();
|
const auto result = ctx.state.builder.AllocateId();
|
||||||
ctx.state.builder.AddFunction({OpCompositeExtract,
|
ctx.state.builder.AddFunction({OpCompositeExtract,
|
||||||
SampledImageScalarType(ctx.state, value_class), result,
|
ImageScalarType(ctx.state, value_class), result, value,
|
||||||
value, component});
|
component});
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
for (uint32_t word = 0; word < mem.data_dwords; word++) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
const auto scalar = ctx.state.builder.AllocateId();
|
const auto scalar = ctx.state.builder.AllocateId();
|
||||||
ctx.state.builder.AddFunction({OpCompositeExtract,
|
ctx.state.builder.AddFunction(
|
||||||
SampledImageScalarType(ctx.state, value_class), scalar,
|
{OpCompositeExtract, ImageScalarType(ctx.state, value_class), scalar, value, index});
|
||||||
value, index});
|
|
||||||
component[index] = SampledComponentBits(ctx, scalar, value_class);
|
component[index] = SampledComponentBits(ctx, scalar, value_class);
|
||||||
}
|
}
|
||||||
const auto result = ctx.state.builder.AllocateId();
|
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 EmitOneDimensionalGatherLz(ValueEmitContext& ctx, const IR::MemoryInfo& mem,
|
||||||
uint32_t coord, SampledImageClass image_class) {
|
uint32_t coord, Prospero::TextureNumericClass numeric_class) {
|
||||||
auto& state = ctx.state;
|
auto& state = ctx.state;
|
||||||
state.builder.RequireCapability(CapabilityImageQuery);
|
state.builder.RequireCapability(CapabilityImageQuery);
|
||||||
const auto image = LoadSampledImageDescriptor(state, mem.resource);
|
const auto image = LoadSampledImageDescriptor(state, mem.resource);
|
||||||
@@ -478,8 +483,8 @@ uint32_t EmitOneDimensionalGatherLz(ValueEmitContext& ctx, const IR::MemoryInfo&
|
|||||||
ConstantF32(state, 0x3f000000u))});
|
ConstantF32(state, 0x3f000000u))});
|
||||||
|
|
||||||
const auto sampled = MakeSampledImage(state, mem.resource, mem.sampler);
|
const auto sampled = MakeSampledImage(state, mem.resource, mem.sampler);
|
||||||
const auto vector_type = SampledImageVectorType(state, image_class, 4);
|
const auto vector_type = ImageVectorType(state, numeric_class, 4);
|
||||||
const auto scalar_type = SampledImageScalarType(state, image_class);
|
const auto scalar_type = ImageScalarType(state, numeric_class);
|
||||||
const auto component =
|
const auto component =
|
||||||
ImageConversionFormat(state, mem).format == Prospero::BufferFormat::kInvalid
|
ImageConversionFormat(state, mem).format == Prospero::BufferFormat::kInvalid
|
||||||
? ImageGatherComponent(mem.dmask)
|
? ImageGatherComponent(mem.dmask)
|
||||||
@@ -625,7 +630,7 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
if (op == IR::ValueOpcode::ImageRead) {
|
if (op == IR::ValueOpcode::ImageRead) {
|
||||||
const auto dimension = image.dimension;
|
const auto dimension = image.dimension;
|
||||||
const auto& dimension_info = ImageDimensionInfoFor(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);
|
const auto condition = ctx.Arg(inst, 2);
|
||||||
ctx.Define(
|
ctx.Define(
|
||||||
inst,
|
inst,
|
||||||
@@ -637,17 +642,17 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
const auto coord = CoordU32(ctx, mem, *address, dimension);
|
const auto coord = CoordU32(ctx, mem, *address, dimension);
|
||||||
if (dimension_info.multisampled != 0u) {
|
if (dimension_info.multisampled != 0u) {
|
||||||
state.builder.AddFunction(
|
state.builder.AddFunction(
|
||||||
{OpImageFetch, SampledImageVectorType(state, image_class, 4), color,
|
{OpImageFetch, ImageVectorType(state, numeric_class, 4), color,
|
||||||
descriptor, coord, ImageOperandsSampleMask,
|
descriptor, coord, ImageOperandsSampleMask,
|
||||||
AddressU32(ctx, mem, *address, dimension_info.coordinate_components)});
|
AddressU32(ctx, mem, *address, dimension_info.coordinate_components)});
|
||||||
} else {
|
} else {
|
||||||
state.builder.AddFunction({OpImageFetch,
|
state.builder.AddFunction({OpImageFetch,
|
||||||
SampledImageVectorType(state, image_class, 4),
|
ImageVectorType(state, numeric_class, 4), color,
|
||||||
color, descriptor, coord, ImageOperandsLodMask,
|
descriptor, coord, ImageOperandsLodMask,
|
||||||
LodU32(ctx, mem, *address, dimension)});
|
LodU32(ctx, mem, *address, dimension)});
|
||||||
}
|
}
|
||||||
return ResultVector(ctx, UnpackImageTexel(ctx, mem, color), image_class, false,
|
return ResultVector(ctx, UnpackImageTexel(ctx, mem, color), numeric_class,
|
||||||
mem);
|
false, mem);
|
||||||
}));
|
}));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -669,7 +674,7 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
const auto dimension = image.dimension;
|
const auto dimension = image.dimension;
|
||||||
const auto& dimension_info = ImageDimensionInfoFor(dimension);
|
const auto& dimension_info = ImageDimensionInfoFor(dimension);
|
||||||
const auto layout = Layout(mem, 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);
|
const bool dref = HasFlag(mem, Decoder::ImageSampleFlagCompare);
|
||||||
if (dref && state.program.info.images[mem.resource].conversion_format !=
|
if (dref && state.program.info.images[mem.resource].conversion_format !=
|
||||||
Prospero::BufferFormat::kInvalid) {
|
Prospero::BufferFormat::kInvalid) {
|
||||||
@@ -686,9 +691,9 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
ctx.Fail(inst, "has an unsupported 1D gather variant");
|
ctx.Fail(inst, "has an unsupported 1D gather variant");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const auto sample = EmitOneDimensionalGatherLz(ctx, mem, coord, image_class);
|
const auto sample = EmitOneDimensionalGatherLz(ctx, mem, coord, numeric_class);
|
||||||
ctx.Define(inst, ResultVector(ctx, UnpackImageGather(ctx, mem, sample), image_class,
|
ctx.Define(inst, ResultVector(ctx, UnpackImageGather(ctx, mem, sample),
|
||||||
false, mem, true));
|
numeric_class, false, mem, true));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (dimension == ImageDimension::Dim1DArray) {
|
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 sampled = MakeSampledImage(state, mem.resource, mem.sampler);
|
||||||
const auto sample = state.builder.AllocateId();
|
const auto sample = state.builder.AllocateId();
|
||||||
std::vector<uint32_t> words =
|
std::vector<uint32_t> words;
|
||||||
dref ? std::vector<uint32_t> {OpImageDrefGather,
|
if (dref) {
|
||||||
TypeF32Vector(state, 4),
|
auto dref_value = ZeroF32(state);
|
||||||
sample,
|
if (layout.dref != NoImageComponent) {
|
||||||
sampled,
|
dref_value = AddressF32(ctx, mem, *address, layout.dref);
|
||||||
coord,
|
}
|
||||||
layout.dref != NoImageComponent
|
words = {OpImageDrefGather, TypeF32Vector(state, 4), sample, sampled, coord,
|
||||||
? AddressF32(ctx, mem, *address, layout.dref)
|
dref_value};
|
||||||
: ZeroF32(state)}
|
} else {
|
||||||
: std::vector<uint32_t> {
|
uint32_t component = 0;
|
||||||
OpImageGather,
|
if (ImageConversionFormat(state, mem).format == Prospero::BufferFormat::kInvalid) {
|
||||||
SampledImageVectorType(state, image_class, 4),
|
component = ImageGatherComponent(mem.dmask);
|
||||||
sample,
|
}
|
||||||
sampled,
|
words = {OpImageGather, ImageVectorType(state, numeric_class, 4),
|
||||||
coord,
|
sample, sampled,
|
||||||
ConstantU32(state, ImageConversionFormat(state, mem).format ==
|
coord, ConstantU32(state, component)};
|
||||||
Prospero::BufferFormat::kInvalid
|
}
|
||||||
? ImageGatherComponent(mem.dmask)
|
|
||||||
: 0u)};
|
|
||||||
if (HasFlag(mem, Decoder::ImageSampleFlagGatherHorizontal)) {
|
if (HasFlag(mem, Decoder::ImageSampleFlagGatherHorizontal)) {
|
||||||
words.push_back(ImageOperandsConstOffsetsMask);
|
words.push_back(ImageOperandsConstOffsetsMask);
|
||||||
words.push_back(HorizontalOffsets(state, dimension));
|
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));
|
words.push_back(PackedOffset(ctx, mem, *address, layout, dimension));
|
||||||
}
|
}
|
||||||
state.builder.AddFunction(words);
|
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),
|
ctx.Define(inst, ResultVector(ctx, UnpackImageGather(ctx, mem, sample),
|
||||||
dref ? SampledImageClass::Float : image_class, false, mem,
|
result_numeric_class, false, mem, true));
|
||||||
true));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const bool explicit_lod = HasFlag(mem, Decoder::ImageSampleFlagDerivative) ||
|
const bool explicit_lod = HasFlag(mem, Decoder::ImageSampleFlagDerivative) ||
|
||||||
HasFlag(mem, Decoder::ImageSampleFlagLod) ||
|
HasFlag(mem, Decoder::ImageSampleFlagLod) ||
|
||||||
HasFlag(mem, Decoder::ImageSampleFlagLevelZero) ||
|
HasFlag(mem, Decoder::ImageSampleFlagLevelZero) ||
|
||||||
state.stage != ShaderType::Pixel;
|
state.stage != ShaderType::Pixel;
|
||||||
const auto opcode = explicit_lod
|
uint32_t opcode = OpImageSampleImplicitLod;
|
||||||
? (dref ? OpImageSampleDrefExplicitLod : OpImageSampleExplicitLod)
|
if (explicit_lod) {
|
||||||
: (dref ? OpImageSampleDrefImplicitLod : OpImageSampleImplicitLod);
|
opcode = dref ? OpImageSampleDrefExplicitLod : OpImageSampleExplicitLod;
|
||||||
const auto result_type =
|
} else if (dref) {
|
||||||
dref ? TypeF32(state) : SampledImageVectorType(state, image_class, 4);
|
opcode = OpImageSampleDrefImplicitLod;
|
||||||
const auto dref_value =
|
}
|
||||||
dref ? (layout.dref != NoImageComponent ? AddressF32(ctx, mem, *address, layout.dref)
|
uint32_t result_type = ImageVectorType(state, numeric_class, 4);
|
||||||
: ZeroF32(state))
|
uint32_t dref_value = 0;
|
||||||
: 0u;
|
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;
|
uint32_t operand_mask = 0;
|
||||||
std::vector<uint32_t> operands;
|
std::vector<uint32_t> operands;
|
||||||
if (HasFlag(mem, Decoder::ImageSampleFlagDerivative)) {
|
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));
|
CoordF32(ctx, mem, *address, layout.grad_y, dimension_info.spatial_components));
|
||||||
} else if (explicit_lod) {
|
} else if (explicit_lod) {
|
||||||
operand_mask |= ImageOperandsLodMask;
|
operand_mask |= ImageOperandsLodMask;
|
||||||
operands.push_back(HasFlag(mem, Decoder::ImageSampleFlagLod) &&
|
auto lod = ZeroF32(state);
|
||||||
layout.lod != NoImageComponent
|
if (HasFlag(mem, Decoder::ImageSampleFlagLod) && layout.lod != NoImageComponent) {
|
||||||
? AddressF32(ctx, mem, *address, layout.lod)
|
lod = AddressF32(ctx, mem, *address, layout.lod);
|
||||||
: ZeroF32(state));
|
}
|
||||||
|
operands.push_back(lod);
|
||||||
} else if (layout.bias != NoImageComponent) {
|
} else if (layout.bias != NoImageComponent) {
|
||||||
operand_mask |= ImageOperandsBiasMask;
|
operand_mask |= ImageOperandsBiasMask;
|
||||||
operands.push_back(AddressF32(ctx, mem, *address, layout.bias));
|
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) {
|
if (image.indirect_root != mem.resource) {
|
||||||
const auto sample = EmitSample(mem.resource);
|
const auto sample = EmitSample(mem.resource);
|
||||||
ctx.Define(inst, ResultVector(ctx, dref ? sample : UnpackImageTexel(ctx, mem, sample),
|
auto result = sample;
|
||||||
image_class, dref, mem));
|
if (!dref) {
|
||||||
|
result = UnpackImageTexel(ctx, mem, sample);
|
||||||
|
}
|
||||||
|
ctx.Define(inst, ResultVector(ctx, result, numeric_class, dref, mem));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const auto* handle = image_arg.ResolveInstruction();
|
const auto* handle = image_arg.ResolveInstruction();
|
||||||
@@ -868,9 +884,11 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
}
|
}
|
||||||
EmitLabel(state, merge_label);
|
EmitLabel(state, merge_label);
|
||||||
state.builder.AddFunction(phi_words);
|
state.builder.AddFunction(phi_words);
|
||||||
ctx.Define(inst,
|
auto result = phi_words[2];
|
||||||
ResultVector(ctx, dref ? phi_words[2] : UnpackImageTexel(ctx, mem, phi_words[2]),
|
if (!dref) {
|
||||||
image_class, dref, mem));
|
result = UnpackImageTexel(ctx, mem, result);
|
||||||
|
}
|
||||||
|
ctx.Define(inst, ResultVector(ctx, result, numeric_class, dref, mem));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const auto atomic_opcode = ImageAtomicOpcode(op);
|
const auto atomic_opcode = ImageAtomicOpcode(op);
|
||||||
|
|||||||
@@ -321,7 +321,6 @@ using ImageDimension = Decoder::ImageDimension;
|
|||||||
|
|
||||||
struct ImageDimensionInfo {
|
struct ImageDimensionInfo {
|
||||||
ImageDimension dimension;
|
ImageDimension dimension;
|
||||||
uint32_t ordinal;
|
|
||||||
uint32_t spirv_dimension;
|
uint32_t spirv_dimension;
|
||||||
uint32_t coordinate_components;
|
uint32_t coordinate_components;
|
||||||
uint32_t spatial_components;
|
uint32_t spatial_components;
|
||||||
@@ -330,29 +329,17 @@ struct ImageDimensionInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
constexpr std::array<ImageDimensionInfo, 7> ImageDimensions {{
|
constexpr std::array<ImageDimensionInfo, 7> ImageDimensions {{
|
||||||
{ImageDimension::Dim1D, 0, Dim1D, 1, 1, 0, 0},
|
{ImageDimension::Dim1D, Dim1D, 1, 1, 0, 0},
|
||||||
{ImageDimension::Dim1DArray, 1, Dim1D, 2, 1, 1, 0},
|
{ImageDimension::Dim1DArray, Dim1D, 2, 1, 1, 0},
|
||||||
{ImageDimension::Dim2D, 2, Dim2D, 2, 2, 0, 0},
|
{ImageDimension::Dim2D, Dim2D, 2, 2, 0, 0},
|
||||||
{ImageDimension::Dim2DArray, 3, Dim2D, 3, 2, 1, 0},
|
{ImageDimension::Dim2DArray, Dim2D, 3, 2, 1, 0},
|
||||||
{ImageDimension::Dim3D, 4, Dim3D, 3, 3, 0, 0},
|
{ImageDimension::Dim3D, Dim3D, 3, 3, 0, 0},
|
||||||
{ImageDimension::Dim2DMsaa, 5, Dim2D, 2, 2, 0, 1},
|
{ImageDimension::Dim2DMsaa, Dim2D, 2, 2, 0, 1},
|
||||||
{ImageDimension::Dim2DMsaaArray, 6, Dim2D, 3, 2, 1, 1},
|
{ImageDimension::Dim2DMsaaArray, Dim2D, 3, 2, 1, 1},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
constexpr uint32_t SampledImageDimensionCount = ImageDimensions.size();
|
|
||||||
constexpr uint32_t StorageImageDimensionCount = 5;
|
|
||||||
|
|
||||||
const ImageDimensionInfo& ImageDimensionInfoFor(ImageDimension dimension);
|
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 {
|
struct EmitterState {
|
||||||
EmitterState(const IR::Program& program_, const IR::ResourceSnapshot& resources_,
|
EmitterState(const IR::Program& program_, const IR::ResourceSnapshot& resources_,
|
||||||
ShaderStageInputInfo input_info_)
|
ShaderStageInputInfo input_info_)
|
||||||
@@ -378,12 +365,7 @@ struct EmitterState {
|
|||||||
uint32_t flattened_srt_variable = 0;
|
uint32_t flattened_srt_variable = 0;
|
||||||
uint32_t lds_variable = 0;
|
uint32_t lds_variable = 0;
|
||||||
uint32_t scratch_variable = 0;
|
uint32_t scratch_variable = 0;
|
||||||
std::array<uint32_t,
|
std::array<uint32_t, IR::ImageBindingCount> image_variables {};
|
||||||
static_cast<uint32_t>(SampledImageClass::Count) * SampledImageDimensionCount>
|
|
||||||
sampled_image_variables {};
|
|
||||||
std::array<uint32_t,
|
|
||||||
static_cast<uint32_t>(StorageImageClass::Count) * StorageImageDimensionCount>
|
|
||||||
storage_image_variables {};
|
|
||||||
uint32_t sampler_variable = 0;
|
uint32_t sampler_variable = 0;
|
||||||
uint32_t main_func = 0;
|
uint32_t main_func = 0;
|
||||||
uint32_t entry_label = 0;
|
uint32_t entry_label = 0;
|
||||||
@@ -482,113 +464,6 @@ struct ImageSampleLayout {
|
|||||||
uint32_t grad_y = NoImageComponent;
|
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 {
|
struct F32Class {
|
||||||
uint32_t bits = 0;
|
uint32_t bits = 0;
|
||||||
uint32_t nan = 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,
|
IR::DescriptorBindingKind kind, uint32_t resource,
|
||||||
const char* variable_name);
|
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 ImageVectorType(EmitterState& state, Prospero::TextureNumericClass numeric_class,
|
||||||
uint32_t components);
|
uint32_t components);
|
||||||
|
|
||||||
uint32_t ImageViewImageType(EmitterState& state, ImageDimension dimension,
|
uint32_t ImageType(EmitterState& state, const IR::ImageResource& image);
|
||||||
SampledImageClass image_class);
|
|
||||||
|
|
||||||
uint32_t ImageViewSampledImageType(EmitterState& state, ImageDimension dimension,
|
|
||||||
SampledImageClass image_class);
|
|
||||||
|
|
||||||
uint32_t ImageViewSizeType(EmitterState& state, ImageDimension dimension);
|
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 LoadSampledImageDescriptor(EmitterState& state, uint32_t resource);
|
||||||
|
|
||||||
uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler);
|
uint32_t LoadSamplerDescriptor(EmitterState& state, uint32_t sampler);
|
||||||
|
|||||||
@@ -187,38 +187,23 @@ void DefineDescriptorVariables(EmitterState& state) {
|
|||||||
state.flattened_srt_variable = state.builder.DefineGlobalVariable(
|
state.flattened_srt_variable = state.builder.DefineGlobalVariable(
|
||||||
TypeStorageBufferPointer(state), StorageClassStorageBuffer);
|
TypeStorageBufferPointer(state), StorageClassStorageBuffer);
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < state.sampled_image_variables.size(); i++) {
|
for (const auto& binding: state.program.bindings.descriptors) {
|
||||||
const auto dimension = ImageDimensions[i % SampledImageDimensionCount].dimension;
|
if (IR::ImageBindingResourceClass(binding.kind) == IR::ImageResourceClass::None) {
|
||||||
const auto image_class = static_cast<SampledImageClass>(i / SampledImageDimensionCount);
|
|
||||||
const auto kind = SampledBindingKind(image_class, dimension);
|
|
||||||
if (DescriptorBinding(state, kind) == nullptr) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto count = ConstantU32(state, DescriptorCount(state, kind));
|
const auto& image = state.program.info.images.at(binding.resources.front());
|
||||||
const auto image_type = ImageViewImageType(state, dimension, image_class);
|
const auto count = ConstantU32(state, DescriptorCount(state, binding.kind));
|
||||||
const auto array_type = state.builder.Type(OpTypeArray, {image_type, count});
|
const auto image_type = ImageType(state, image);
|
||||||
const auto pointer_type = TypePointer(state, StorageClassUniformConstant, array_type);
|
const auto array_type = state.builder.Type(OpTypeArray, {image_type, count});
|
||||||
state.sampled_image_variables[i] =
|
const auto pointer_type = TypePointer(state, StorageClassUniformConstant, array_type);
|
||||||
|
state.image_variables[IR::ImageBindingIndex(binding.kind)] =
|
||||||
state.builder.DefineGlobalVariable(pointer_type, StorageClassUniformConstant);
|
state.builder.DefineGlobalVariable(pointer_type, StorageClassUniformConstant);
|
||||||
if (dimension == ImageDimension::Dim1D || dimension == ImageDimension::Dim1DArray) {
|
if (image.dimension == ImageDimension::Dim1D ||
|
||||||
state.builder.RequireCapability(CapabilitySampled1D);
|
image.dimension == ImageDimension::Dim1DArray) {
|
||||||
}
|
const auto capability = image.resource_class == IR::ImageResourceClass::Sampled
|
||||||
}
|
? CapabilitySampled1D
|
||||||
for (uint32_t i = 0; i < state.storage_image_variables.size(); i++) {
|
: CapabilityImage1D;
|
||||||
const auto dimension = ImageDimensions[i % StorageImageDimensionCount].dimension;
|
state.builder.RequireCapability(capability);
|
||||||
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 (DescriptorBinding(state, IR::DescriptorBindingKind::Samplers) != nullptr) {
|
if (DescriptorBinding(state, IR::DescriptorBindingKind::Samplers) != nullptr) {
|
||||||
@@ -594,53 +579,13 @@ void AddDescriptorAnnotationsAndNames(EmitterState& state) {
|
|||||||
Decorate(state.fault_buffer_variable, "fault_buffer",
|
Decorate(state.fault_buffer_variable, "fault_buffer",
|
||||||
IR::DescriptorBindingKind::FaultBuffer);
|
IR::DescriptorBindingKind::FaultBuffer);
|
||||||
}
|
}
|
||||||
constexpr const char* SampledNames[] = {"sampled_1d",
|
for (const auto& binding: state.program.bindings.descriptors) {
|
||||||
"sampled_1d_array",
|
if (IR::ImageBindingResourceClass(binding.kind) == IR::ImageResourceClass::None) {
|
||||||
"sampled_2d",
|
continue;
|
||||||
"sampled_2d_array",
|
}
|
||||||
"sampled_3d",
|
const auto name = "image_" + std::to_string(static_cast<uint32_t>(binding.kind));
|
||||||
"sampled_2d_msaa",
|
Decorate(state.image_variables[IR::ImageBindingIndex(binding.kind)], name.c_str(),
|
||||||
"sampled_2d_msaa_array",
|
binding.kind);
|
||||||
"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));
|
|
||||||
}
|
}
|
||||||
if (state.sampler_variable != 0) {
|
if (state.sampler_variable != 0) {
|
||||||
Decorate(state.sampler_variable, "samplers", IR::DescriptorBindingKind::Samplers);
|
Decorate(state.sampler_variable, "samplers", IR::DescriptorBindingKind::Samplers);
|
||||||
|
|||||||
@@ -259,45 +259,13 @@ struct StageOutput {
|
|||||||
bool operator==(const StageOutput& other) const = default;
|
bool operator==(const StageOutput& other) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DescriptorBindingKind {
|
inline constexpr uint32_t FirstImageBinding = 1u;
|
||||||
Buffers,
|
inline constexpr uint32_t FirstStorageImageBinding = 22u;
|
||||||
Sampled1D,
|
inline constexpr uint32_t ImageBindingCount = 36u;
|
||||||
Sampled1DArray,
|
|
||||||
Sampled2D,
|
enum class DescriptorBindingKind : uint32_t {
|
||||||
Sampled2DArray,
|
Buffers = 0u,
|
||||||
Sampled2DMsaa,
|
Samplers = FirstImageBinding + ImageBindingCount,
|
||||||
Sampled2DMsaaArray,
|
|
||||||
Sampled3D,
|
|
||||||
SampledUint1D,
|
|
||||||
SampledUint1DArray,
|
|
||||||
SampledUint2D,
|
|
||||||
SampledUint2DArray,
|
|
||||||
SampledUint2DMsaa,
|
|
||||||
SampledUint2DMsaaArray,
|
|
||||||
SampledUint3D,
|
|
||||||
SampledSint1D,
|
|
||||||
SampledSint1DArray,
|
|
||||||
SampledSint2D,
|
|
||||||
SampledSint2DArray,
|
|
||||||
SampledSint2DMsaa,
|
|
||||||
SampledSint2DMsaaArray,
|
|
||||||
SampledSint3D,
|
|
||||||
Storage1D,
|
|
||||||
Storage1DArray,
|
|
||||||
Storage2D,
|
|
||||||
Storage2DArray,
|
|
||||||
Storage3D,
|
|
||||||
StorageUint1D,
|
|
||||||
StorageUint1DArray,
|
|
||||||
StorageUint2D,
|
|
||||||
StorageUint2DArray,
|
|
||||||
StorageUint3D,
|
|
||||||
StorageAtomic1D,
|
|
||||||
StorageAtomic1DArray,
|
|
||||||
StorageAtomic2D,
|
|
||||||
StorageAtomic2DArray,
|
|
||||||
StorageAtomic3D,
|
|
||||||
Samplers,
|
|
||||||
Gds,
|
Gds,
|
||||||
BdaPagetable,
|
BdaPagetable,
|
||||||
FaultBuffer,
|
FaultBuffer,
|
||||||
@@ -306,6 +274,9 @@ enum class DescriptorBindingKind {
|
|||||||
Count,
|
Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert(static_cast<uint32_t>(DescriptorBindingKind::Samplers) == 37u);
|
||||||
|
static_assert(static_cast<uint32_t>(DescriptorBindingKind::Count) == 43u);
|
||||||
|
|
||||||
constexpr uint32_t NativePushConstantSize = 128;
|
constexpr uint32_t NativePushConstantSize = 128;
|
||||||
|
|
||||||
[[nodiscard]] constexpr uint32_t NativeBinding(ShaderType stage, DescriptorBindingKind kind) {
|
[[nodiscard]] constexpr uint32_t NativeBinding(ShaderType stage, DescriptorBindingKind kind) {
|
||||||
@@ -313,88 +284,87 @@ constexpr uint32_t NativePushConstantSize = 128;
|
|||||||
(stage == ShaderType::Pixel ? static_cast<uint32_t>(DescriptorBindingKind::Count) : 0u);
|
(stage == ShaderType::Pixel ? static_cast<uint32_t>(DescriptorBindingKind::Count) : 0u);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline std::optional<DescriptorBindingKind>
|
[[nodiscard]] constexpr ImageResourceClass ImageBindingResourceClass(DescriptorBindingKind kind) {
|
||||||
DescriptorBindingForImage(const ImageResource& image) {
|
const auto value = static_cast<uint32_t>(kind);
|
||||||
using Dimension = Decoder::ImageDimension;
|
if (value >= FirstImageBinding && value < FirstStorageImageBinding) {
|
||||||
using Kind = DescriptorBindingKind;
|
return ImageResourceClass::Sampled;
|
||||||
|
}
|
||||||
|
if (value >= FirstStorageImageBinding &&
|
||||||
|
value < static_cast<uint32_t>(DescriptorBindingKind::Samplers)) {
|
||||||
|
return ImageResourceClass::Storage;
|
||||||
|
}
|
||||||
|
return ImageResourceClass::None;
|
||||||
|
}
|
||||||
|
|
||||||
switch (image.resource_class) {
|
[[nodiscard]] constexpr uint32_t ImageBindingIndex(DescriptorBindingKind kind) {
|
||||||
case ImageResourceClass::Sampled:
|
return static_cast<uint32_t>(kind) - FirstImageBinding;
|
||||||
switch (image.numeric_class) {
|
}
|
||||||
case Prospero::TextureNumericClass::Float: break;
|
|
||||||
case Prospero::TextureNumericClass::Uint:
|
[[nodiscard]] constexpr std::optional<DescriptorBindingKind>
|
||||||
switch (image.dimension) {
|
DescriptorBindingForImage(const ImageResource& image) {
|
||||||
case Dimension::Dim1D: return Kind::SampledUint1D;
|
constexpr uint32_t SampledFloatBinding = 1u;
|
||||||
case Dimension::Dim1DArray: return Kind::SampledUint1DArray;
|
constexpr uint32_t SampledUintBinding = 8u;
|
||||||
case Dimension::Dim2D: return Kind::SampledUint2D;
|
constexpr uint32_t SampledSintBinding = 15u;
|
||||||
case Dimension::Dim2DArray: return Kind::SampledUint2DArray;
|
constexpr uint32_t StorageFloatBinding = 22u;
|
||||||
case Dimension::Dim2DMsaa: return Kind::SampledUint2DMsaa;
|
constexpr uint32_t StorageUintBinding = 27u;
|
||||||
case Dimension::Dim2DMsaaArray: return Kind::SampledUint2DMsaaArray;
|
constexpr uint32_t AtomicUintBinding = 32u;
|
||||||
case Dimension::Dim3D: return Kind::SampledUint3D;
|
|
||||||
default: return std::nullopt;
|
uint32_t base = 0;
|
||||||
}
|
bool sampled = false;
|
||||||
case Prospero::TextureNumericClass::Sint:
|
if (image.resource_class == ImageResourceClass::Sampled) {
|
||||||
switch (image.dimension) {
|
if (image.atomic) {
|
||||||
case Dimension::Dim1D: return Kind::SampledSint1D;
|
return std::nullopt;
|
||||||
case Dimension::Dim1DArray: return Kind::SampledSint1DArray;
|
}
|
||||||
case Dimension::Dim2D: return Kind::SampledSint2D;
|
sampled = true;
|
||||||
case Dimension::Dim2DArray: return Kind::SampledSint2DArray;
|
switch (image.numeric_class) {
|
||||||
case Dimension::Dim2DMsaa: return Kind::SampledSint2DMsaa;
|
case Prospero::TextureNumericClass::Float: base = SampledFloatBinding; break;
|
||||||
case Dimension::Dim2DMsaaArray: return Kind::SampledSint2DMsaaArray;
|
case Prospero::TextureNumericClass::Uint: base = SampledUintBinding; break;
|
||||||
case Dimension::Dim3D: return Kind::SampledSint3D;
|
case Prospero::TextureNumericClass::Sint: base = SampledSintBinding; break;
|
||||||
default: return std::nullopt;
|
case Prospero::TextureNumericClass::Unsupported: return std::nullopt;
|
||||||
}
|
default: return std::nullopt;
|
||||||
case Prospero::TextureNumericClass::Unsupported: return std::nullopt;
|
}
|
||||||
|
} else if (image.resource_class == ImageResourceClass::Storage) {
|
||||||
|
if (image.atomic) {
|
||||||
|
if (image.numeric_class != Prospero::TextureNumericClass::Uint) {
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
switch (image.dimension) {
|
base = AtomicUintBinding;
|
||||||
case Dimension::Dim1D: return Kind::Sampled1D;
|
} else {
|
||||||
case Dimension::Dim1DArray: return Kind::Sampled1DArray;
|
switch (image.numeric_class) {
|
||||||
case Dimension::Dim2D: return Kind::Sampled2D;
|
case Prospero::TextureNumericClass::Float: base = StorageFloatBinding; break;
|
||||||
case Dimension::Dim2DArray: return Kind::Sampled2DArray;
|
case Prospero::TextureNumericClass::Uint: base = StorageUintBinding; break;
|
||||||
case Dimension::Dim2DMsaa: return Kind::Sampled2DMsaa;
|
case Prospero::TextureNumericClass::Sint:
|
||||||
case Dimension::Dim2DMsaaArray: return Kind::Sampled2DMsaaArray;
|
case Prospero::TextureNumericClass::Unsupported: return std::nullopt;
|
||||||
case Dimension::Dim3D: return Kind::Sampled3D;
|
|
||||||
default: return std::nullopt;
|
default: return std::nullopt;
|
||||||
}
|
}
|
||||||
case ImageResourceClass::Storage:
|
}
|
||||||
if (image.atomic) {
|
} else {
|
||||||
if (image.numeric_class != Prospero::TextureNumericClass::Uint) {
|
return std::nullopt;
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
switch (image.dimension) {
|
|
||||||
case Dimension::Dim1D: return Kind::StorageAtomic1D;
|
|
||||||
case Dimension::Dim1DArray: return Kind::StorageAtomic1DArray;
|
|
||||||
case Dimension::Dim2D: return Kind::StorageAtomic2D;
|
|
||||||
case Dimension::Dim2DArray: return Kind::StorageAtomic2DArray;
|
|
||||||
case Dimension::Dim3D: return Kind::StorageAtomic3D;
|
|
||||||
default: return std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (image.numeric_class) {
|
|
||||||
case Prospero::TextureNumericClass::Float:
|
|
||||||
switch (image.dimension) {
|
|
||||||
case Dimension::Dim1D: return Kind::Storage1D;
|
|
||||||
case Dimension::Dim1DArray: return Kind::Storage1DArray;
|
|
||||||
case Dimension::Dim2D: return Kind::Storage2D;
|
|
||||||
case Dimension::Dim2DArray: return Kind::Storage2DArray;
|
|
||||||
case Dimension::Dim3D: return Kind::Storage3D;
|
|
||||||
default: return std::nullopt;
|
|
||||||
}
|
|
||||||
case Prospero::TextureNumericClass::Uint:
|
|
||||||
switch (image.dimension) {
|
|
||||||
case Dimension::Dim1D: return Kind::StorageUint1D;
|
|
||||||
case Dimension::Dim1DArray: return Kind::StorageUint1DArray;
|
|
||||||
case Dimension::Dim2D: return Kind::StorageUint2D;
|
|
||||||
case Dimension::Dim2DArray: return Kind::StorageUint2DArray;
|
|
||||||
case Dimension::Dim3D: return Kind::StorageUint3D;
|
|
||||||
default: return std::nullopt;
|
|
||||||
}
|
|
||||||
case Prospero::TextureNumericClass::Sint:
|
|
||||||
case Prospero::TextureNumericClass::Unsupported: return std::nullopt;
|
|
||||||
}
|
|
||||||
case ImageResourceClass::None: return std::nullopt;
|
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
|
||||||
|
uint32_t dimension = 0;
|
||||||
|
switch (image.dimension) {
|
||||||
|
case Decoder::ImageDimension::Dim1D: break;
|
||||||
|
case Decoder::ImageDimension::Dim1DArray: dimension = 1u; break;
|
||||||
|
case Decoder::ImageDimension::Dim2D: dimension = 2u; break;
|
||||||
|
case Decoder::ImageDimension::Dim2DArray: dimension = 3u; break;
|
||||||
|
case Decoder::ImageDimension::Dim2DMsaa:
|
||||||
|
if (!sampled) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
dimension = 4u;
|
||||||
|
break;
|
||||||
|
case Decoder::ImageDimension::Dim2DMsaaArray:
|
||||||
|
if (!sampled) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
dimension = 5u;
|
||||||
|
break;
|
||||||
|
case Decoder::ImageDimension::Dim3D: dimension = sampled ? 6u : 4u; break;
|
||||||
|
case Decoder::ImageDimension::Unknown: return std::nullopt;
|
||||||
|
default: return std::nullopt;
|
||||||
|
}
|
||||||
|
return static_cast<DescriptorBindingKind>(base + dimension);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DescriptorBinding {
|
struct DescriptorBinding {
|
||||||
|
|||||||
@@ -10,11 +10,6 @@
|
|||||||
namespace Libs::Graphics::ShaderRecompiler::IR {
|
namespace Libs::Graphics::ShaderRecompiler::IR {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto FirstImageBinding = DescriptorBindingKind::Sampled1D;
|
|
||||||
constexpr uint32_t ImageBindingCount =
|
|
||||||
static_cast<uint32_t>(DescriptorBindingKind::StorageAtomic3D) -
|
|
||||||
static_cast<uint32_t>(FirstImageBinding) + 1u;
|
|
||||||
|
|
||||||
[[noreturn]] void BindingFail(const char* message) {
|
[[noreturn]] void BindingFail(const char* message) {
|
||||||
EXIT("shader binding layout failed: %s", message);
|
EXIT("shader binding layout failed: %s", message);
|
||||||
std::abort();
|
std::abort();
|
||||||
@@ -107,7 +102,7 @@ void AllocateBindings(Program& program, uint32_t push_constant_offset) {
|
|||||||
if (!kind.has_value()) {
|
if (!kind.has_value()) {
|
||||||
EXIT("shader binding layout failed: image %u has an invalid binding class", i);
|
EXIT("shader binding layout failed: image %u has an invalid binding class", i);
|
||||||
}
|
}
|
||||||
const auto group = static_cast<uint32_t>(*kind) - static_cast<uint32_t>(FirstImageBinding);
|
const auto group = ImageBindingIndex(*kind);
|
||||||
if (group >= image_groups.size()) {
|
if (group >= image_groups.size()) {
|
||||||
EXIT("shader binding layout failed: image %u has an unmapped binding class", i);
|
EXIT("shader binding layout failed: image %u has an unmapped binding class", i);
|
||||||
}
|
}
|
||||||
@@ -122,10 +117,8 @@ void AllocateBindings(Program& program, uint32_t push_constant_offset) {
|
|||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < image_groups.size(); i++) {
|
for (uint32_t i = 0; i < image_groups.size(); i++) {
|
||||||
if (!image_groups[i].empty()) {
|
if (!image_groups[i].empty()) {
|
||||||
AddBinding(
|
AddBinding(next, static_cast<DescriptorBindingKind>(FirstImageBinding + i),
|
||||||
next,
|
std::move(image_groups[i]));
|
||||||
static_cast<DescriptorBindingKind>(static_cast<uint32_t>(FirstImageBinding) + i),
|
|
||||||
std::move(image_groups[i]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -767,8 +767,10 @@ void TestDynamicStorageMipTracking() {
|
|||||||
ShaderComputeInputInfo compute{};
|
ShaderComputeInputInfo compute{};
|
||||||
CollectShaderInfo(fixture.program, {.compute = &compute});
|
CollectShaderInfo(fixture.program, {.compute = &compute});
|
||||||
AllocateBindings(fixture.program, 0);
|
AllocateBindings(fixture.program, 0);
|
||||||
|
const auto storage_kind = DescriptorBindingForImage(images[0]);
|
||||||
|
Check(storage_kind.has_value(), "storage image has no descriptor binding");
|
||||||
const auto *storage_binding =
|
const auto *storage_binding =
|
||||||
FindBinding(fixture.program.bindings, DescriptorBindingKind::Storage2D);
|
FindBinding(fixture.program.bindings, *storage_kind);
|
||||||
Check(storage_binding != nullptr &&
|
Check(storage_binding != nullptr &&
|
||||||
storage_binding->resources == std::vector<uint32_t>({0, 1, 1, 1}),
|
storage_binding->resources == std::vector<uint32_t>({0, 1, 1, 1}),
|
||||||
"dynamic storage mip descriptors were not expanded consecutively");
|
"dynamic storage mip descriptors were not expanded consecutively");
|
||||||
@@ -1168,6 +1170,113 @@ void TestShaderInfoAndBindingLayout() {
|
|||||||
"binding layout did not collect live typed user-data values");
|
"binding layout did not collect live typed user-data values");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestImageBindingAbi() {
|
||||||
|
using NumericClass = Libs::Graphics::Prospero::TextureNumericClass;
|
||||||
|
|
||||||
|
Check(ImageBindingCount == 36u &&
|
||||||
|
static_cast<uint32_t>(DescriptorBindingKind::Buffers) == 0u &&
|
||||||
|
static_cast<uint32_t>(DescriptorBindingKind::Samplers) == 37u &&
|
||||||
|
static_cast<uint32_t>(DescriptorBindingKind::Gds) == 38u &&
|
||||||
|
static_cast<uint32_t>(DescriptorBindingKind::BdaPagetable) == 39u &&
|
||||||
|
static_cast<uint32_t>(DescriptorBindingKind::FaultBuffer) == 40u &&
|
||||||
|
static_cast<uint32_t>(DescriptorBindingKind::FlattenedSrt) == 41u &&
|
||||||
|
static_cast<uint32_t>(DescriptorBindingKind::UserData) == 42u &&
|
||||||
|
static_cast<uint32_t>(DescriptorBindingKind::Count) == 43u,
|
||||||
|
"native descriptor binding anchors changed");
|
||||||
|
|
||||||
|
const std::array sampled_dimensions{
|
||||||
|
Decoder::ImageDimension::Dim1D,
|
||||||
|
Decoder::ImageDimension::Dim1DArray,
|
||||||
|
Decoder::ImageDimension::Dim2D,
|
||||||
|
Decoder::ImageDimension::Dim2DArray,
|
||||||
|
Decoder::ImageDimension::Dim2DMsaa,
|
||||||
|
Decoder::ImageDimension::Dim2DMsaaArray,
|
||||||
|
Decoder::ImageDimension::Dim3D,
|
||||||
|
};
|
||||||
|
const std::array storage_dimensions{
|
||||||
|
Decoder::ImageDimension::Dim1D, Decoder::ImageDimension::Dim1DArray,
|
||||||
|
Decoder::ImageDimension::Dim2D, Decoder::ImageDimension::Dim2DArray,
|
||||||
|
Decoder::ImageDimension::Dim3D,
|
||||||
|
};
|
||||||
|
const std::array sampled_classes{NumericClass::Float, NumericClass::Uint,
|
||||||
|
NumericClass::Sint};
|
||||||
|
const std::array storage_classes{NumericClass::Float, NumericClass::Uint};
|
||||||
|
uint32_t index = 0;
|
||||||
|
const auto CheckBinding =
|
||||||
|
[&](ImageResourceClass resource_class, NumericClass numeric_class,
|
||||||
|
Decoder::ImageDimension dimension, bool atomic) {
|
||||||
|
ImageResource image;
|
||||||
|
image.resource_class = resource_class;
|
||||||
|
image.numeric_class = numeric_class;
|
||||||
|
image.dimension = dimension;
|
||||||
|
image.atomic = atomic;
|
||||||
|
const auto kind = DescriptorBindingForImage(image);
|
||||||
|
Check(kind.has_value() &&
|
||||||
|
static_cast<uint32_t>(*kind) == FirstImageBinding + index &&
|
||||||
|
ImageBindingIndex(*kind) == index &&
|
||||||
|
ImageBindingResourceClass(*kind) == resource_class &&
|
||||||
|
NativeBinding(ShaderType::Compute, *kind) ==
|
||||||
|
FirstImageBinding + index &&
|
||||||
|
NativeBinding(ShaderType::Pixel, *kind) ==
|
||||||
|
static_cast<uint32_t>(DescriptorBindingKind::Count) +
|
||||||
|
FirstImageBinding + index,
|
||||||
|
"generated image descriptor binding changed ABI");
|
||||||
|
index++;
|
||||||
|
};
|
||||||
|
for (const auto numeric_class : sampled_classes) {
|
||||||
|
for (const auto dimension : sampled_dimensions) {
|
||||||
|
CheckBinding(ImageResourceClass::Sampled, numeric_class, dimension,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto numeric_class : storage_classes) {
|
||||||
|
for (const auto dimension : storage_dimensions) {
|
||||||
|
CheckBinding(ImageResourceClass::Storage, numeric_class, dimension,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto dimension : storage_dimensions) {
|
||||||
|
CheckBinding(ImageResourceClass::Storage, NumericClass::Uint, dimension,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
Check(index == ImageBindingCount, "image descriptor ABI case count changed");
|
||||||
|
|
||||||
|
const auto Invalid = [](ImageResource image) {
|
||||||
|
return !DescriptorBindingForImage(image).has_value();
|
||||||
|
};
|
||||||
|
ImageResource image;
|
||||||
|
Check(Invalid(image), "untyped image received a descriptor binding");
|
||||||
|
image.resource_class = ImageResourceClass::Sampled;
|
||||||
|
image.numeric_class = NumericClass::Float;
|
||||||
|
image.dimension = Decoder::ImageDimension::Unknown;
|
||||||
|
Check(Invalid(image),
|
||||||
|
"unknown sampled dimension received a descriptor binding");
|
||||||
|
image.dimension = Decoder::ImageDimension::Dim2D;
|
||||||
|
image.numeric_class = NumericClass::Unsupported;
|
||||||
|
Check(Invalid(image),
|
||||||
|
"unsupported sampled class received a descriptor binding");
|
||||||
|
image.numeric_class = static_cast<NumericClass>(UINT32_MAX);
|
||||||
|
Check(Invalid(image), "invalid sampled class received a descriptor binding");
|
||||||
|
image.numeric_class = NumericClass::Float;
|
||||||
|
image.dimension = static_cast<Decoder::ImageDimension>(UINT32_MAX);
|
||||||
|
Check(Invalid(image),
|
||||||
|
"invalid sampled dimension received a descriptor binding");
|
||||||
|
image.dimension = Decoder::ImageDimension::Dim2D;
|
||||||
|
image.atomic = true;
|
||||||
|
Check(Invalid(image), "atomic sampled image received a descriptor binding");
|
||||||
|
image.resource_class = ImageResourceClass::Storage;
|
||||||
|
image.atomic = false;
|
||||||
|
image.numeric_class = NumericClass::Sint;
|
||||||
|
Check(Invalid(image), "signed storage image received a descriptor binding");
|
||||||
|
image.numeric_class = NumericClass::Float;
|
||||||
|
image.dimension = Decoder::ImageDimension::Dim2DMsaa;
|
||||||
|
Check(Invalid(image),
|
||||||
|
"multisampled storage image received a descriptor binding");
|
||||||
|
image.dimension = Decoder::ImageDimension::Dim2D;
|
||||||
|
image.atomic = true;
|
||||||
|
Check(Invalid(image), "float atomic image received a descriptor binding");
|
||||||
|
}
|
||||||
|
|
||||||
void TestGraphicsPushConstantLayout() {
|
void TestGraphicsPushConstantLayout() {
|
||||||
const auto AddUserData = [](Fixture &fixture, uint32_t count) {
|
const auto AddUserData = [](Fixture &fixture, uint32_t count) {
|
||||||
for (uint32_t index = 0; index < count; index++) {
|
for (uint32_t index = 0; index < count; index++) {
|
||||||
@@ -1312,6 +1421,7 @@ int main() {
|
|||||||
Run("dynamic FLAT address", TestDynamicFlatAddressesUseDma);
|
Run("dynamic FLAT address", TestDynamicFlatAddressesUseDma);
|
||||||
Run("buffer swizzle specialization", TestBufferSwizzleSpecialization);
|
Run("buffer swizzle specialization", TestBufferSwizzleSpecialization);
|
||||||
Run("shader info and bindings", TestShaderInfoAndBindingLayout);
|
Run("shader info and bindings", TestShaderInfoAndBindingLayout);
|
||||||
|
Run("image binding ABI", TestImageBindingAbi);
|
||||||
Run("graphics push constants", TestGraphicsPushConstantLayout);
|
Run("graphics push constants", TestGraphicsPushConstantLayout);
|
||||||
Run("resource limit", TestResourceLimitIsTransactional);
|
Run("resource limit", TestResourceLimitIsTransactional);
|
||||||
Run("malformed memory kinds", TestMalformedMemoryKindsRejected);
|
Run("malformed memory kinds", TestMalformedMemoryKindsRejected);
|
||||||
|
|||||||
@@ -9534,36 +9534,26 @@ public:
|
|||||||
auto Native = [](Kind kind) {
|
auto Native = [](Kind kind) {
|
||||||
return ShaderRecompiler::IR::NativeBinding(ShaderType::Compute, kind);
|
return ShaderRecompiler::IR::NativeBinding(ShaderType::Compute, kind);
|
||||||
};
|
};
|
||||||
auto Count = [&](Kind kind) {
|
for (const auto &binding : layout.descriptors) {
|
||||||
const auto *binding = Binding(kind);
|
const auto resource_class =
|
||||||
if (binding == nullptr) {
|
ShaderRecompiler::IR::ImageBindingResourceClass(binding.kind);
|
||||||
return 0u;
|
if (resource_class == ShaderRecompiler::IR::ImageResourceClass::None) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (kind == Kind::Gds) {
|
const auto &image =
|
||||||
return 1u;
|
compiled.program.info.images.at(binding.resources.front());
|
||||||
|
bool supported =
|
||||||
|
image.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||||
|
if (resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled) {
|
||||||
|
supported = supported ||
|
||||||
|
image.dimension ==
|
||||||
|
ShaderRecompiler::Decoder::ImageDimension::Dim1D ||
|
||||||
|
image.dimension ==
|
||||||
|
ShaderRecompiler::Decoder::ImageDimension::Dim1DArray;
|
||||||
}
|
}
|
||||||
return static_cast<u32>(binding->resources.size());
|
Require(test.name, "dispatch", supported,
|
||||||
};
|
"unsupported image dimension needs a matching Vulkan test view");
|
||||||
Require(
|
}
|
||||||
test.name, "dispatch",
|
|
||||||
Count(Kind::Sampled2DArray) == 0 && Count(Kind::Sampled3D) == 0 &&
|
|
||||||
Count(Kind::SampledUint2DArray) == 0 &&
|
|
||||||
Count(Kind::SampledUint3D) == 0 &&
|
|
||||||
Count(Kind::SampledSint2DArray) == 0 &&
|
|
||||||
Count(Kind::SampledSint3D) == 0 && Count(Kind::Storage1D) == 0 &&
|
|
||||||
Count(Kind::Storage1DArray) == 0 &&
|
|
||||||
Count(Kind::Storage2DArray) == 0 && Count(Kind::Storage3D) == 0 &&
|
|
||||||
Count(Kind::StorageUint1D) == 0 &&
|
|
||||||
Count(Kind::StorageUint1DArray) == 0 &&
|
|
||||||
Count(Kind::StorageUint2DArray) == 0 &&
|
|
||||||
Count(Kind::StorageUint3D) == 0 &&
|
|
||||||
Count(Kind::StorageAtomic1D) == 0 &&
|
|
||||||
Count(Kind::StorageAtomic1DArray) == 0 &&
|
|
||||||
Count(Kind::StorageAtomic2DArray) == 0 &&
|
|
||||||
Count(Kind::StorageAtomic3D) == 0,
|
|
||||||
"unsupported array/3D image cases must provide matching Vulkan test "
|
|
||||||
"views "
|
|
||||||
"before dispatch");
|
|
||||||
|
|
||||||
vk::ShaderModuleCreateInfo module_info{};
|
vk::ShaderModuleCreateInfo module_info{};
|
||||||
module_info.sType = vk::StructureType::eShaderModuleCreateInfo;
|
module_info.sType = vk::StructureType::eShaderModuleCreateInfo;
|
||||||
@@ -9652,34 +9642,10 @@ public:
|
|||||||
}
|
}
|
||||||
pool_sizes.push_back({type, count});
|
pool_sizes.push_back({type, count});
|
||||||
};
|
};
|
||||||
add_pool_size(vk::DescriptorType::eStorageBuffer,
|
for (const auto &binding : layout.descriptors) {
|
||||||
Count(Kind::Buffers) +
|
add_pool_size(NativeDescriptorType(binding.kind),
|
||||||
(Binding(Kind::BdaPagetable) != nullptr ? 1u : 0u) +
|
NativeDescriptorCount(binding));
|
||||||
(Binding(Kind::FaultBuffer) != nullptr ? 1u : 0u) +
|
}
|
||||||
Count(Kind::Gds) +
|
|
||||||
(Binding(Kind::FlattenedSrt) != nullptr ? 1u : 0u) +
|
|
||||||
(Binding(Kind::UserData) != nullptr ? 1u : 0u));
|
|
||||||
add_pool_size(
|
|
||||||
vk::DescriptorType::eSampledImage,
|
|
||||||
Count(Kind::Sampled1D) + Count(Kind::Sampled1DArray) +
|
|
||||||
Count(Kind::Sampled2D) + Count(Kind::Sampled2DArray) +
|
|
||||||
Count(Kind::Sampled3D) + Count(Kind::SampledUint1D) +
|
|
||||||
Count(Kind::SampledUint1DArray) + Count(Kind::SampledUint2D) +
|
|
||||||
Count(Kind::SampledUint2DArray) + Count(Kind::SampledUint3D) +
|
|
||||||
Count(Kind::SampledSint1D) + Count(Kind::SampledSint1DArray) +
|
|
||||||
Count(Kind::SampledSint2D) + Count(Kind::SampledSint2DArray) +
|
|
||||||
Count(Kind::SampledSint3D));
|
|
||||||
add_pool_size(
|
|
||||||
vk::DescriptorType::eStorageImage,
|
|
||||||
Count(Kind::Storage1D) + Count(Kind::Storage1DArray) +
|
|
||||||
Count(Kind::Storage2D) + Count(Kind::Storage2DArray) +
|
|
||||||
Count(Kind::Storage3D) + Count(Kind::StorageUint1D) +
|
|
||||||
Count(Kind::StorageUint1DArray) + Count(Kind::StorageUint2D) +
|
|
||||||
Count(Kind::StorageUint2DArray) + Count(Kind::StorageUint3D) +
|
|
||||||
Count(Kind::StorageAtomic1D) + Count(Kind::StorageAtomic1DArray) +
|
|
||||||
Count(Kind::StorageAtomic2D) + Count(Kind::StorageAtomic2DArray) +
|
|
||||||
Count(Kind::StorageAtomic3D));
|
|
||||||
add_pool_size(vk::DescriptorType::eSampler, Count(Kind::Samplers));
|
|
||||||
vk::DescriptorPoolCreateInfo pool_info{};
|
vk::DescriptorPoolCreateInfo pool_info{};
|
||||||
pool_info.sType = vk::StructureType::eDescriptorPoolCreateInfo;
|
pool_info.sType = vk::StructureType::eDescriptorPoolCreateInfo;
|
||||||
pool_info.maxSets = 1;
|
pool_info.maxSets = 1;
|
||||||
@@ -9810,17 +9776,28 @@ public:
|
|||||||
writes.push_back(write);
|
writes.push_back(write);
|
||||||
}
|
}
|
||||||
const ShaderRecompiler::IR::DescriptorBinding *sampled = nullptr;
|
const ShaderRecompiler::IR::DescriptorBinding *sampled = nullptr;
|
||||||
constexpr std::array sampled_kinds{
|
const ShaderRecompiler::IR::DescriptorBinding *storage = nullptr;
|
||||||
Kind::Sampled1D, Kind::Sampled1DArray, Kind::Sampled2D,
|
const ShaderRecompiler::IR::DescriptorBinding *storage_uint = nullptr;
|
||||||
Kind::SampledUint1D, Kind::SampledUint1DArray, Kind::SampledUint2D,
|
const ShaderRecompiler::IR::DescriptorBinding *storage_atomic = nullptr;
|
||||||
Kind::SampledSint1D, Kind::SampledSint1DArray, Kind::SampledSint2D,
|
for (const auto &binding : layout.descriptors) {
|
||||||
};
|
const auto resource_class =
|
||||||
for (const auto kind : sampled_kinds) {
|
ShaderRecompiler::IR::ImageBindingResourceClass(binding.kind);
|
||||||
if (const auto *candidate = Binding(kind); candidate != nullptr) {
|
if (resource_class == ShaderRecompiler::IR::ImageResourceClass::None) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto &image =
|
||||||
|
compiled.program.info.images.at(binding.resources.front());
|
||||||
|
if (resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled) {
|
||||||
Require(test.name, "dispatch", sampled == nullptr,
|
Require(test.name, "dispatch", sampled == nullptr,
|
||||||
"Vulkan test harness needs separate sampled images for mixed "
|
"Vulkan test harness needs separate sampled images for mixed "
|
||||||
"descriptor classes");
|
"descriptor classes");
|
||||||
sampled = candidate;
|
sampled = &binding;
|
||||||
|
} else if (image.atomic) {
|
||||||
|
storage_atomic = &binding;
|
||||||
|
} else if (image.numeric_class == Prospero::TextureNumericClass::Float) {
|
||||||
|
storage = &binding;
|
||||||
|
} else {
|
||||||
|
storage_uint = &binding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sampled != nullptr) {
|
if (sampled != nullptr) {
|
||||||
@@ -9841,9 +9818,6 @@ public:
|
|||||||
write.pImageInfo = sampled_infos.data();
|
write.pImageInfo = sampled_infos.data();
|
||||||
writes.push_back(write);
|
writes.push_back(write);
|
||||||
}
|
}
|
||||||
const auto *storage = Binding(Kind::Storage2D);
|
|
||||||
const auto *storage_uint = Binding(Kind::StorageUint2D);
|
|
||||||
const auto *storage_atomic = Binding(Kind::StorageAtomic2D);
|
|
||||||
const auto BindStorage =
|
const auto BindStorage =
|
||||||
[&](const ShaderRecompiler::IR::DescriptorBinding *binding,
|
[&](const ShaderRecompiler::IR::DescriptorBinding *binding,
|
||||||
const Image *image, std::vector<vk::DescriptorImageInfo> *infos) {
|
const Image *image, std::vector<vk::DescriptorImageInfo> *infos) {
|
||||||
@@ -11837,24 +11811,18 @@ void RunCase(VulkanHarness *vulkan, const TestCase &test) {
|
|||||||
VulkanHarness::Image storage_image_uint;
|
VulkanHarness::Image storage_image_uint;
|
||||||
VulkanHarness::Buffer gds_buffer;
|
VulkanHarness::Buffer gds_buffer;
|
||||||
vk::Sampler sampler = nullptr;
|
vk::Sampler sampler = nullptr;
|
||||||
const bool needs_sampled_image =
|
bool needs_sampled_image = false;
|
||||||
Has(Kind::Sampled1D) || Has(Kind::Sampled1DArray) ||
|
bool needs_storage_image = false;
|
||||||
Has(Kind::Sampled2D) || Has(Kind::Sampled2DArray) ||
|
for (const auto &binding : compiled.program.bindings.descriptors) {
|
||||||
Has(Kind::Sampled3D) || Has(Kind::SampledUint2D) ||
|
const auto resource_class =
|
||||||
Has(Kind::SampledUint1D) || Has(Kind::SampledUint1DArray) ||
|
ShaderRecompiler::IR::ImageBindingResourceClass(binding.kind);
|
||||||
Has(Kind::SampledUint2DArray) || Has(Kind::SampledUint3D) ||
|
if (resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled) {
|
||||||
Has(Kind::SampledSint2D) || Has(Kind::SampledSint1D) ||
|
needs_sampled_image = true;
|
||||||
Has(Kind::SampledSint1DArray) || Has(Kind::SampledSint2DArray) ||
|
} else if (resource_class ==
|
||||||
Has(Kind::SampledSint3D);
|
ShaderRecompiler::IR::ImageResourceClass::Storage) {
|
||||||
const bool needs_storage_image =
|
needs_storage_image = true;
|
||||||
Has(Kind::Storage1D) || Has(Kind::Storage1DArray) ||
|
}
|
||||||
Has(Kind::Storage2D) || Has(Kind::Storage2DArray) ||
|
}
|
||||||
Has(Kind::Storage3D) || Has(Kind::StorageUint2D) ||
|
|
||||||
Has(Kind::StorageUint1D) || Has(Kind::StorageUint1DArray) ||
|
|
||||||
Has(Kind::StorageUint2DArray) || Has(Kind::StorageUint3D) ||
|
|
||||||
Has(Kind::StorageAtomic1D) || Has(Kind::StorageAtomic1DArray) ||
|
|
||||||
Has(Kind::StorageAtomic2D) || Has(Kind::StorageAtomic2DArray) ||
|
|
||||||
Has(Kind::StorageAtomic3D);
|
|
||||||
const bool needs_sampler = Has(Kind::Samplers);
|
const bool needs_sampler = Has(Kind::Samplers);
|
||||||
const bool needs_gds = Has(Kind::Gds);
|
const bool needs_gds = Has(Kind::Gds);
|
||||||
if (needs_gds) {
|
if (needs_gds) {
|
||||||
@@ -19760,7 +19728,7 @@ TestCase ImageLoadR32UintUsesIntegerSampledImage() {
|
|||||||
test.sampled_image_dwords_per_pixel = 1;
|
test.sampled_image_dwords_per_pixel = 1;
|
||||||
test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k32UInt);
|
test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k32UInt);
|
||||||
test.has_user_data = true;
|
test.has_user_data = true;
|
||||||
test.required_spirv = {"sampled_uint_2d", "OpTypeImage %uint",
|
test.required_spirv = {"image_10", "OpTypeImage %uint",
|
||||||
"OpImageFetch %v4uint"};
|
"OpImageFetch %v4uint"};
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
@@ -19788,8 +19756,8 @@ TestCase ImageLoadR32SintUsesSignedSampledImage() {
|
|||||||
test.sampled_image_dwords_per_pixel = 1;
|
test.sampled_image_dwords_per_pixel = 1;
|
||||||
test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k32SInt);
|
test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k32SInt);
|
||||||
test.has_user_data = true;
|
test.has_user_data = true;
|
||||||
test.required_spirv = {"sampled_sint_2d", "OpTypeImage %int",
|
test.required_spirv = {"image_17", "OpTypeImage %int", "OpImageFetch %v4int",
|
||||||
"OpImageFetch %v4int", "OpBitcast %uint"};
|
"OpBitcast %uint"};
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19914,7 +19882,7 @@ TestCase ImageLoad1DUsesScalarCoordinate() {
|
|||||||
test.user_data[3] = static_cast<uint32_t>(Prospero::ImageType::kColor1D)
|
test.user_data[3] = static_cast<uint32_t>(Prospero::ImageType::kColor1D)
|
||||||
<< 28u;
|
<< 28u;
|
||||||
test.has_user_data = true;
|
test.has_user_data = true;
|
||||||
test.required_spirv = {"sampled_uint_1d"};
|
test.required_spirv = {"image_8"};
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19950,7 +19918,7 @@ TestCase ImageGather2DInstructionWith1DDescriptor() {
|
|||||||
test.user_data[3] = static_cast<uint32_t>(Prospero::ImageType::kColor1D)
|
test.user_data[3] = static_cast<uint32_t>(Prospero::ImageType::kColor1D)
|
||||||
<< 28u;
|
<< 28u;
|
||||||
test.has_user_data = true;
|
test.has_user_data = true;
|
||||||
test.required_spirv = {"sampled_1d", "OpImageQuerySizeLod",
|
test.required_spirv = {"image_1", "OpImageQuerySizeLod",
|
||||||
"OpImageSampleExplicitLod", "Floor"};
|
"OpImageSampleExplicitLod", "Floor"};
|
||||||
test.forbidden_spirv = {"OpImageGather"};
|
test.forbidden_spirv = {"OpImageGather"};
|
||||||
return test;
|
return test;
|
||||||
@@ -19985,7 +19953,7 @@ TestCase ImageLoad1DArrayUsesLayerCoordinate() {
|
|||||||
test.user_data[3] = static_cast<uint32_t>(Prospero::ImageType::kColor1DArray)
|
test.user_data[3] = static_cast<uint32_t>(Prospero::ImageType::kColor1DArray)
|
||||||
<< 28u;
|
<< 28u;
|
||||||
test.has_user_data = true;
|
test.has_user_data = true;
|
||||||
test.required_spirv = {"sampled_uint_1d_array"};
|
test.required_spirv = {"image_9"};
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20022,7 +19990,7 @@ TestCase ImageLoad1DArrayDescriptorUsesSelectedLayer() {
|
|||||||
<< 28u;
|
<< 28u;
|
||||||
test.user_data[4] = 1u | (1u << 16u);
|
test.user_data[4] = 1u | (1u << 16u);
|
||||||
test.has_user_data = true;
|
test.has_user_data = true;
|
||||||
test.required_spirv = {"sampled_uint_1d"};
|
test.required_spirv = {"image_8"};
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20767,7 +20735,7 @@ TestCase ImageStoreR32SintUsesRawUintView() {
|
|||||||
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
||||||
test.expected_storage_image_r32ui = expected_image;
|
test.expected_storage_image_r32ui = expected_image;
|
||||||
test.required_spirv = {"OpCapability StorageImageWriteWithoutFormat",
|
test.required_spirv = {"OpCapability StorageImageWriteWithoutFormat",
|
||||||
"storage_uint_2d"};
|
"image_29"};
|
||||||
test.forbidden_spirv = {"R32ui"};
|
test.forbidden_spirv = {"R32ui"};
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
@@ -20797,7 +20765,7 @@ TestCase ImageStoreR32UintUsesFormatlessStorageImage() {
|
|||||||
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
||||||
test.expected_storage_image_r32ui = expected_image;
|
test.expected_storage_image_r32ui = expected_image;
|
||||||
test.required_spirv = {"OpCapability StorageImageWriteWithoutFormat",
|
test.required_spirv = {"OpCapability StorageImageWriteWithoutFormat",
|
||||||
"storage_uint_2d"};
|
"image_29"};
|
||||||
test.forbidden_spirv = {"R32ui"};
|
test.forbidden_spirv = {"R32ui"};
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
@@ -20831,7 +20799,7 @@ TestCase ImageStorePackedUintSaturatesChannels() {
|
|||||||
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
||||||
test.expected_storage_image_r32ui = std::move(expected_image);
|
test.expected_storage_image_r32ui = std::move(expected_image);
|
||||||
test.required_spirv = {"OpCapability StorageImageWriteWithoutFormat",
|
test.required_spirv = {"OpCapability StorageImageWriteWithoutFormat",
|
||||||
"storage_uint_2d", "OpULessThan", "OpSelect"};
|
"image_29", "OpULessThan", "OpSelect"};
|
||||||
test.forbidden_spirv = {"R32ui"};
|
test.forbidden_spirv = {"R32ui"};
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
@@ -20863,7 +20831,7 @@ TestCase ImageStorePackedUintHonorsSparseDmask() {
|
|||||||
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
||||||
test.expected_storage_image_r32ui = std::move(expected_image);
|
test.expected_storage_image_r32ui = std::move(expected_image);
|
||||||
test.required_spirv = {"OpCapability StorageImageWriteWithoutFormat",
|
test.required_spirv = {"OpCapability StorageImageWriteWithoutFormat",
|
||||||
"storage_uint_2d"};
|
"image_29"};
|
||||||
test.forbidden_spirv = {"R32ui"};
|
test.forbidden_spirv = {"R32ui"};
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
@@ -20924,9 +20892,9 @@ TestCase ImageStoreAndAtomicShareTypedBinding() {
|
|||||||
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
||||||
test.expected_storage_image_r32ui = std::move(expected_image);
|
test.expected_storage_image_r32ui = std::move(expected_image);
|
||||||
test.required_spirv = {"OpImageWrite", "OpImageTexelPointer", "R32ui",
|
test.required_spirv = {"OpImageWrite", "OpImageTexelPointer", "R32ui",
|
||||||
"storage_atomic_2d"};
|
"image_34"};
|
||||||
test.forbidden_spirv = {"StorageImageReadWithoutFormat",
|
test.forbidden_spirv = {"StorageImageReadWithoutFormat",
|
||||||
"StorageImageWriteWithoutFormat", "storage_uint_2d"};
|
"StorageImageWriteWithoutFormat", "image_29"};
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20965,8 +20933,8 @@ TestCase ImageStoreAndAtomicUseSeparateBindings() {
|
|||||||
"OpImageWrite",
|
"OpImageWrite",
|
||||||
"OpImageTexelPointer",
|
"OpImageTexelPointer",
|
||||||
"R32ui",
|
"R32ui",
|
||||||
"storage_uint_2d",
|
"image_29",
|
||||||
"storage_atomic_2d"};
|
"image_34"};
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20997,10 +20965,10 @@ TestCase ImageAtomicVariants() {
|
|||||||
O::IMAGE_ATOMIC_UMIN, O::IMAGE_ATOMIC_AND,
|
O::IMAGE_ATOMIC_UMIN, O::IMAGE_ATOMIC_AND,
|
||||||
O::IMAGE_ATOMIC_OR, O::IMAGE_ATOMIC_XOR,
|
O::IMAGE_ATOMIC_OR, O::IMAGE_ATOMIC_XOR,
|
||||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||||
test.required_spirv = {"OpImageTexelPointer", "R32ui", "storage_atomic_2d"};
|
test.required_spirv = {"OpImageTexelPointer", "R32ui", "image_34"};
|
||||||
test.forbidden_spirv = {"OpTypeSampler", "OpTypeSampledImage",
|
test.forbidden_spirv = {"OpTypeSampler", "OpTypeSampledImage",
|
||||||
"StorageImageReadWithoutFormat",
|
"StorageImageReadWithoutFormat",
|
||||||
"StorageImageWriteWithoutFormat", "storage_uint_2d"};
|
"StorageImageWriteWithoutFormat", "image_29"};
|
||||||
test.storage_image_rgba = MakeRgbaImage(4, 4);
|
test.storage_image_rgba = MakeRgbaImage(4, 4);
|
||||||
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
||||||
for (u32 i = 0; i < static_cast<u32>(std::size(initial)); i++) {
|
for (u32 i = 0; i < static_cast<u32>(std::size(initial)); i++) {
|
||||||
@@ -23756,8 +23724,48 @@ void CheckImageSamplerSpecialization() {
|
|||||||
std::printf("[host] %-32s ok\n", "ImageSpecializationPipelineId");
|
std::printf("[host] %-32s ok\n", "ImageSpecializationPipelineId");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckNativeImageDescriptorTypes() {
|
||||||
|
using ShaderRecompiler::IR::DescriptorBindingKind;
|
||||||
|
using ShaderRecompiler::IR::FirstImageBinding;
|
||||||
|
using ShaderRecompiler::IR::FirstStorageImageBinding;
|
||||||
|
|
||||||
|
for (uint32_t value = FirstImageBinding;
|
||||||
|
value < static_cast<uint32_t>(DescriptorBindingKind::Samplers);
|
||||||
|
value++) {
|
||||||
|
const auto expected = value < FirstStorageImageBinding
|
||||||
|
? vk::DescriptorType::eSampledImage
|
||||||
|
: vk::DescriptorType::eStorageImage;
|
||||||
|
Require("NativeImageDescriptorTypes", "image binding",
|
||||||
|
NativeDescriptorType(static_cast<DescriptorBindingKind>(value)) ==
|
||||||
|
expected,
|
||||||
|
"generated image binding has the wrong Vulkan descriptor type");
|
||||||
|
}
|
||||||
|
Require("NativeImageDescriptorTypes", "non-image bindings",
|
||||||
|
NativeDescriptorType(DescriptorBindingKind::Samplers) ==
|
||||||
|
vk::DescriptorType::eSampler &&
|
||||||
|
NativeDescriptorType(DescriptorBindingKind::Buffers) ==
|
||||||
|
vk::DescriptorType::eStorageBuffer &&
|
||||||
|
NativeDescriptorType(DescriptorBindingKind::Gds) ==
|
||||||
|
vk::DescriptorType::eStorageBuffer &&
|
||||||
|
NativeDescriptorType(DescriptorBindingKind::BdaPagetable) ==
|
||||||
|
vk::DescriptorType::eStorageBuffer &&
|
||||||
|
NativeDescriptorType(DescriptorBindingKind::FaultBuffer) ==
|
||||||
|
vk::DescriptorType::eStorageBuffer &&
|
||||||
|
NativeDescriptorType(DescriptorBindingKind::FlattenedSrt) ==
|
||||||
|
vk::DescriptorType::eStorageBuffer &&
|
||||||
|
NativeDescriptorType(DescriptorBindingKind::UserData) ==
|
||||||
|
vk::DescriptorType::eStorageBuffer,
|
||||||
|
"non-image binding has the wrong Vulkan descriptor type");
|
||||||
|
std::printf("[host] %-32s ok\n", "NativeImageDescriptorTypes");
|
||||||
|
}
|
||||||
|
|
||||||
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
|
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
|
||||||
void CheckShaderRecompilerFatalContracts() {
|
void CheckShaderRecompilerFatalContracts() {
|
||||||
|
ExpectFatal("InvalidDescriptorBindingRejection", [] {
|
||||||
|
(void)NativeDescriptorType(
|
||||||
|
ShaderRecompiler::IR::DescriptorBindingKind::Count);
|
||||||
|
});
|
||||||
|
|
||||||
ExpectFatal("WritableFlatStoreRejection", [] {
|
ExpectFatal("WritableFlatStoreRejection", [] {
|
||||||
const auto test = FlatStoreVariants();
|
const auto test = FlatStoreVariants();
|
||||||
(void)CompileCase(test);
|
(void)CompileCase(test);
|
||||||
@@ -25827,6 +25835,7 @@ int main(int argc, char **argv) {
|
|||||||
VulkanHarness vulkan;
|
VulkanHarness vulkan;
|
||||||
#endif
|
#endif
|
||||||
CheckImageSamplerSpecialization();
|
CheckImageSamplerSpecialization();
|
||||||
|
CheckNativeImageDescriptorTypes();
|
||||||
CheckClipControlDepthClipState();
|
CheckClipControlDepthClipState();
|
||||||
CheckReferenceClockScale();
|
CheckReferenceClockScale();
|
||||||
CheckVulkan13FeatureRequirements();
|
CheckVulkan13FeatureRequirements();
|
||||||
|
|||||||
+34
-24
@@ -5086,8 +5086,7 @@ void TestNewShaderRecompilerImageViewDimensions() {
|
|||||||
"1D derivative sample did not emit scalar SPIR-V gradients");
|
"1D derivative sample did not emit scalar SPIR-V gradients");
|
||||||
Check(Common::ContainsStr(source, "OpImageQuerySizeLod"),
|
Check(Common::ContainsStr(source, "OpImageQuerySizeLod"),
|
||||||
"1D resource query did not emit a scalar size query");
|
"1D resource query did not emit a scalar size query");
|
||||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain",
|
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_8 "),
|
||||||
"sampled_uint_1d"),
|
|
||||||
"integer 1D load did not access the uint 1D descriptor binding");
|
"integer 1D load did not access the uint 1D descriptor binding");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5124,11 +5123,10 @@ void TestNewShaderRecompilerStorageImage1DDescriptorVariants() {
|
|||||||
CheckSpirvBinaryValidates(result.spirv);
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
|
|
||||||
const auto source = DisassembleSpirvBinary(result.spirv);
|
const auto source = DisassembleSpirvBinary(result.spirv);
|
||||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "storage_1d "),
|
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_22 "),
|
||||||
"1D store did not access the 1D storage descriptor binding");
|
"1D store did not access the 1D storage descriptor binding");
|
||||||
Check(
|
Check(
|
||||||
SpirvSourceHasInstructionUsing(source, "OpAccessChain",
|
SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_23 "),
|
||||||
"storage_1d_array"),
|
|
||||||
"1D-array store did not access the 1D-array storage descriptor binding");
|
"1D-array store did not access the 1D-array storage descriptor binding");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5146,9 +5144,9 @@ void TestNewShaderRecompilerNullImageUsesCanonical2DView() {
|
|||||||
auto result = ShaderRecompiler::Recompile(shader, options);
|
auto result = ShaderRecompiler::Recompile(shader, options);
|
||||||
CheckSpirvBinaryValidates(result.spirv);
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
const auto source = DisassembleSpirvBinary(result.spirv);
|
const auto source = DisassembleSpirvBinary(result.spirv);
|
||||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "sampled_2d "),
|
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_3 "),
|
||||||
"null image did not use the canonical 2D sampled descriptor binding");
|
"null image did not use the canonical 2D sampled descriptor binding");
|
||||||
Check(!SpirvSourceHasInstructionUsing(source, "OpAccessChain", "sampled_1d "),
|
Check(!SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_1 "),
|
||||||
"null image retained the decoded 1D descriptor binding");
|
"null image retained the decoded 1D descriptor binding");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5315,17 +5313,17 @@ void TestNewShaderRecompilerImageLoad2DMsaa() {
|
|||||||
result.program.info.images[0].dimension ==
|
result.program.info.images[0].dimension ==
|
||||||
ShaderRecompiler::Decoder::ImageDimension::Dim2DMsaa,
|
ShaderRecompiler::Decoder::ImageDimension::Dim2DMsaa,
|
||||||
"2D-MSAA descriptor specialization lost the multisample dimension");
|
"2D-MSAA descriptor specialization lost the multisample dimension");
|
||||||
Check(ShaderRecompiler::IR::FindBinding(
|
const auto binding_kind = ShaderRecompiler::IR::DescriptorBindingForImage(
|
||||||
result.program.bindings,
|
result.program.info.images[0]);
|
||||||
ShaderRecompiler::IR::DescriptorBindingKind::Sampled2DMsaa) !=
|
Check(binding_kind.has_value() &&
|
||||||
nullptr,
|
ShaderRecompiler::IR::FindBinding(result.program.bindings,
|
||||||
|
*binding_kind) != nullptr,
|
||||||
"2D-MSAA image did not receive a multisampled descriptor binding");
|
"2D-MSAA image did not receive a multisampled descriptor binding");
|
||||||
Check(SpirvContainsTypeImage(result.spirv, 1, 0, 1, 1),
|
Check(SpirvContainsTypeImage(result.spirv, 1, 0, 1, 1),
|
||||||
"SPIR-V binary does not contain a multisampled 2D image type");
|
"SPIR-V binary does not contain a multisampled 2D image type");
|
||||||
CheckSpirvBinaryValidates(result.spirv);
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
const auto source = DisassembleSpirvBinary(result.spirv);
|
const auto source = DisassembleSpirvBinary(result.spirv);
|
||||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain",
|
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_5 "),
|
||||||
"sampled_2d_msaa"),
|
|
||||||
"2D-MSAA load did not access its multisampled descriptor");
|
"2D-MSAA load did not access its multisampled descriptor");
|
||||||
Check(SpirvSourceHasInstructionUsing(source, "OpImageFetch", " Sample "),
|
Check(SpirvSourceHasInstructionUsing(source, "OpImageFetch", " Sample "),
|
||||||
"2D-MSAA load did not emit the fragment ID as a SPIR-V Sample operand");
|
"2D-MSAA load did not emit the fragment ID as a SPIR-V Sample operand");
|
||||||
@@ -5424,7 +5422,7 @@ void TestNewShaderRecompilerStorageImage3DDescriptorVariant() {
|
|||||||
CheckSpirvBinaryValidates(result.spirv);
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
|
|
||||||
const auto source = DisassembleSpirvBinary(result.spirv);
|
const auto source = DisassembleSpirvBinary(result.spirv);
|
||||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "storage_3d"),
|
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_26 "),
|
||||||
"storage image store did not access the 3D storage descriptor binding");
|
"storage image store did not access the 3D storage descriptor binding");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5460,14 +5458,13 @@ void TestNewShaderRecompilerStorageImage2DDescriptorOverridesMimg3D() {
|
|||||||
CheckSpirvBinaryValidates(result.spirv);
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
|
|
||||||
const auto source = DisassembleSpirvBinary(result.spirv);
|
const auto source = DisassembleSpirvBinary(result.spirv);
|
||||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "storage_2d"),
|
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_24 "),
|
||||||
"2D descriptor storage image store did not access the base storage "
|
"2D descriptor storage image store did not access the base storage "
|
||||||
"binding");
|
"binding");
|
||||||
Check(!SpirvSourceHasInstructionUsing(source, "OpAccessChain",
|
Check(!SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_25 "),
|
||||||
"storage_2d_array"),
|
|
||||||
"2D descriptor storage image store unexpectedly used the array storage "
|
"2D descriptor storage image store unexpectedly used the array storage "
|
||||||
"binding");
|
"binding");
|
||||||
Check(!SpirvSourceHasInstructionUsing(source, "OpAccessChain", "storage_3d"),
|
Check(!SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_26 "),
|
||||||
"2D descriptor storage image store unexpectedly used the 3D storage "
|
"2D descriptor storage image store unexpectedly used the 3D storage "
|
||||||
"binding");
|
"binding");
|
||||||
}
|
}
|
||||||
@@ -10342,12 +10339,25 @@ void TestNewShaderRecompilerNativeBindingPlan() {
|
|||||||
auto result = ShaderRecompiler::Recompile(shader, options);
|
auto result = ShaderRecompiler::Recompile(shader, options);
|
||||||
const auto *buffers = ShaderRecompiler::IR::FindBinding(
|
const auto *buffers = ShaderRecompiler::IR::FindBinding(
|
||||||
result.program.bindings, BindingKind::Buffers);
|
result.program.bindings, BindingKind::Buffers);
|
||||||
const auto *sampled = ShaderRecompiler::IR::FindBinding(
|
const ShaderRecompiler::IR::DescriptorBinding *sampled = nullptr;
|
||||||
result.program.bindings, BindingKind::Sampled2D);
|
const ShaderRecompiler::IR::DescriptorBinding *storage = nullptr;
|
||||||
const auto *storage = ShaderRecompiler::IR::FindBinding(
|
const ShaderRecompiler::IR::DescriptorBinding *atomic_storage = nullptr;
|
||||||
result.program.bindings, BindingKind::Storage2D);
|
for (const auto &image : result.program.info.images) {
|
||||||
const auto *atomic_storage = ShaderRecompiler::IR::FindBinding(
|
const auto kind = ShaderRecompiler::IR::DescriptorBindingForImage(image);
|
||||||
result.program.bindings, BindingKind::StorageAtomic2D);
|
if (!kind.has_value()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto *binding =
|
||||||
|
ShaderRecompiler::IR::FindBinding(result.program.bindings, *kind);
|
||||||
|
if (image.resource_class ==
|
||||||
|
ShaderRecompiler::IR::ImageResourceClass::Sampled) {
|
||||||
|
sampled = binding;
|
||||||
|
} else if (image.atomic) {
|
||||||
|
atomic_storage = binding;
|
||||||
|
} else {
|
||||||
|
storage = binding;
|
||||||
|
}
|
||||||
|
}
|
||||||
const auto *samplers = ShaderRecompiler::IR::FindBinding(
|
const auto *samplers = ShaderRecompiler::IR::FindBinding(
|
||||||
result.program.bindings, BindingKind::Samplers);
|
result.program.bindings, BindingKind::Samplers);
|
||||||
Check(buffers != nullptr && buffers->resources.size() == 2,
|
Check(buffers != nullptr && buffers->resources.size() == 2,
|
||||||
|
|||||||
Reference in New Issue
Block a user