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];