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