Implement dynamic descriptor array indexing
Bug: b/146166966
Bug: angleproject:4071
Tests: dEQP-VK.*
Change-Id: I07008936fbb09f134283a21a6d3bba881f97fe09
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/40668
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 6f2a9b0..3ffc4c4 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -1094,14 +1094,23 @@
Decorations d = {};
ApplyDecorationsForId(&d, baseObject.typeId());
- uint32_t arrayIndex = 0;
+ Int arrayIndex = 0;
if(baseObject.kind == Object::Kind::DescriptorSet)
{
auto type = getType(typeId).definition.opcode();
if(type == spv::OpTypeArray || type == spv::OpTypeRuntimeArray)
{
- ASSERT(getObject(indexIds[0]).kind == Object::Kind::Constant);
- arrayIndex = GetConstScalarInt(indexIds[0]);
+ auto &obj = getObject(indexIds[0]);
+ ASSERT(obj.kind == Object::Kind::Constant || obj.kind == Object::Kind::Intermediate);
+ if(obj.kind == Object::Kind::Constant)
+ {
+ arrayIndex = GetConstScalarInt(indexIds[0]);
+ }
+ else
+ {
+ // Note: the value of indexIds[0] must be dynamically uniform.
+ arrayIndex = Extract(state->getIntermediate(indexIds[0]).Int(0), 0);
+ }
numIndexes--;
indexIds++;
@@ -1223,21 +1232,25 @@
case spv::OpTypeArray:
case spv::OpTypeRuntimeArray:
{
- // TODO: b/127950082: Check bounds.
+ // TODO(b/127950082): Check bounds.
if(getType(baseObject).storageClass == spv::StorageClassUniformConstant)
{
// indexing into an array of descriptors.
- auto &obj = getObject(indexIds[i]);
- if(obj.kind != Object::Kind::Constant)
- {
- UNSUPPORTED("SPIR-V SampledImageArrayDynamicIndexing Capability");
- }
-
auto d = descriptorDecorations.at(baseId);
ASSERT(d.DescriptorSet >= 0);
ASSERT(d.Binding >= 0);
uint32_t descriptorSize = routine->pipelineLayout->getDescriptorSize(d.DescriptorSet, d.Binding);
- ptr.base += descriptorSize * GetConstScalarInt(indexIds[i]);
+
+ auto &obj = getObject(indexIds[i]);
+ if(obj.kind == Object::Kind::Constant)
+ {
+ ptr.base += descriptorSize * GetConstScalarInt(indexIds[i]);
+ }
+ else
+ {
+ // Note: the value of indexIds[i] must be dynamically uniform.
+ ptr.base += descriptorSize * Extract(state->getIntermediate(indexIds[i]).Int(0), 0);
+ }
}
else
{
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 04ca7c6..4e2d726 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -1120,12 +1120,11 @@
// Returns a SIMD::Pointer to the underlying data for the given pointer
// object.
// Handles objects of the following kinds:
- // • DescriptorSet
- // • DivergentPointer
- // • InterfaceVariable
- // • NonDivergentPointer
+ // - DescriptorSet
+ // - Pointer
+ // - InterfaceVariable
// Calling GetPointerToData with objects of any other kind will assert.
- SIMD::Pointer GetPointerToData(Object::ID id, int arrayIndex, EmitState const *state) const;
+ SIMD::Pointer GetPointerToData(Object::ID id, Int arrayIndex, EmitState const *state) const;
SIMD::Pointer WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, EmitState const *state) const;
SIMD::Pointer WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, EmitState const *state) const;
diff --git a/src/Pipeline/SpirvShaderMemory.cpp b/src/Pipeline/SpirvShaderMemory.cpp
index 5eab8c9..df16f0c 100644
--- a/src/Pipeline/SpirvShaderMemory.cpp
+++ b/src/Pipeline/SpirvShaderMemory.cpp
@@ -372,7 +372,7 @@
}
}
-SIMD::Pointer SpirvShader::GetPointerToData(Object::ID id, int arrayIndex, EmitState const *state) const
+SIMD::Pointer SpirvShader::GetPointerToData(Object::ID id, Int arrayIndex, EmitState const *state) const
{
auto routine = state->routine;
auto &object = getObject(id);
@@ -390,7 +390,7 @@
uint32_t bindingOffset = routine->pipelineLayout->getBindingOffset(d.DescriptorSet, d.Binding);
uint32_t descriptorSize = routine->pipelineLayout->getDescriptorSize(d.DescriptorSet, d.Binding);
- uint32_t descriptorOffset = bindingOffset + descriptorSize * arrayIndex;
+ Int descriptorOffset = bindingOffset + descriptorSize * arrayIndex;
auto set = state->getPointer(id);
Pointer<Byte> descriptor = set.base + descriptorOffset; // BufferDescriptor*
@@ -399,7 +399,7 @@
if(routine->pipelineLayout->isDescriptorDynamic(d.DescriptorSet, d.Binding))
{
- uint32_t dynamicOffsetIndex =
+ Int dynamicOffsetIndex =
routine->pipelineLayout->getDynamicOffsetIndex(d.DescriptorSet, d.Binding) +
arrayIndex;
Int offset = routine->descriptorDynamicOffsets[dynamicOffsetIndex];