SpirvShader: Implement descriptor set arrays
Introduce a new Object::Kind - DescriptorSet.
This represents a pointer to a vk::DescriptorSet*, which is now
dereferenced to access the buffer data in OpAccessChain or OpLoad / OpStore.
This shuffling is required to handle descriptor array access
as the array index is only known at OpAccessChain time.
Tests: *dynamic*
Bug: b/126330097
Change-Id: Id754d966d8945f4e4fcf7895ed2210ce4f6ba713
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/28391
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 4db352a..e6662e5 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -203,6 +203,9 @@
case spv::StorageClassUniform:
case spv::StorageClassStorageBuffer:
+ object.kind = Object::Kind::DescriptorSet;
+ break;
+
case spv::StorageClassPushConstant:
case spv::StorageClassPrivate:
case spv::StorageClassFunction:
@@ -818,6 +821,33 @@
case Object::Kind::DivergentPointer:
return std::make_pair(routine->getPointer(id), routine->getIntermediate(id).Int(0));
+ case Object::Kind::DescriptorSet:
+ {
+ Decorations d = {};
+ ApplyDecorationsForId(&d, id);
+
+ ASSERT(d.DescriptorSet >= 0);
+ ASSERT(d.Binding >= 0);
+
+ auto set = routine->getPointer(id);
+ auto setLayout = routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet);
+ size_t bindingOffset = setLayout->getBindingOffset(d.Binding, arrayIndex);
+
+ Pointer<Byte> bufferInfo = Pointer<Byte>(set + bindingOffset); // VkDescriptorBufferInfo*
+ Pointer<Byte> buffer = *Pointer<Pointer<Byte>>(bufferInfo + OFFSET(VkDescriptorBufferInfo, buffer)); // vk::Buffer*
+ Pointer<Byte> data = *Pointer<Pointer<Byte>>(buffer + vk::Buffer::DataOffset); // void*
+ Int offset = *Pointer<Int>(bufferInfo + OFFSET(VkDescriptorBufferInfo, offset));
+ if (setLayout->isBindingDynamic(d.Binding))
+ {
+ uint32_t dynamicBindingIndex =
+ routine->pipelineLayout->getDynamicOffsetBase(d.DescriptorSet) +
+ setLayout->getDynamicDescriptorOffset(d.Binding) +
+ arrayIndex;
+ offset += routine->descriptorDynamicOffsets[dynamicBindingIndex];
+ }
+ return std::make_pair(data + offset, SIMD::Int(0));
+ }
+
default:
UNREACHABLE("Invalid pointer kind %d", int(object.kind));
return std::make_pair(Pointer<Byte>(), SIMD::Int(0));
@@ -833,9 +863,24 @@
Decorations d = {};
ApplyDecorationsForId(&d, baseObject.type);
+ size_t 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 = GetConstantInt(indexIds[0]);
+
+ numIndexes--;
+ indexIds++;
+ typeId = getType(typeId).element;
+ }
+ }
+
SIMD::Int dynamicOffset;
Pointer<Byte> pointerBase;
- std::tie(pointerBase, dynamicOffset) = GetPointerToData(id, 0, routine);
+ std::tie(pointerBase, dynamicOffset) = GetPointerToData(id, arrayIndex, routine);
int constantOffset = 0;
@@ -1735,27 +1780,7 @@
Decorations d{};
ApplyDecorationsForId(&d, resultId);
ASSERT(d.DescriptorSet >= 0);
- ASSERT(d.Binding >= 0);
-
- auto set = routine->descriptorSets[d.DescriptorSet]; // DescriptorSet*
- auto setLayout = routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet);
- size_t arrayIndex = 0; // TODO: descriptor arrays
- size_t bindingOffset = setLayout->getBindingOffset(d.Binding, arrayIndex);
-
- Pointer<Byte> bufferInfo = Pointer<Byte>(set + bindingOffset); // VkDescriptorBufferInfo*
- Pointer<Byte> buffer = *Pointer<Pointer<Byte>>(bufferInfo + OFFSET(VkDescriptorBufferInfo, buffer)); // vk::Buffer*
- Pointer<Byte> data = *Pointer<Pointer<Byte>>(buffer + vk::Buffer::DataOffset); // void*
- Int offset = *Pointer<Int>(bufferInfo + OFFSET(VkDescriptorBufferInfo, offset));
- if (setLayout->isBindingDynamic(d.Binding))
- {
- uint32_t dynamicBindingIndex =
- routine->pipelineLayout->getDynamicOffsetBase(d.DescriptorSet) +
- setLayout->getDynamicDescriptorOffset(d.Binding) +
- arrayIndex;
- offset += routine->descriptorDynamicOffsets[dynamicBindingIndex];
- }
-
- routine->createPointer(resultId, data + offset);
+ routine->createPointer(resultId, routine->descriptorSets[d.DescriptorSet]);
break;
}
case spv::StorageClassPushConstant:
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 6b91160..7831401 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -263,6 +263,10 @@
// Pointer held by SpirvRoutine::pointers
NonDivergentPointer,
+ // A pointer to a vk::DescriptorSet*.
+ // Pointer held by SpirvRoutine::pointers.
+ DescriptorSet,
+
} kind = Kind::Unknown;
};
@@ -560,6 +564,7 @@
// Returns a base pointer and per-lane offset to the underlying data for
// the given pointer object. Handles objects of the following kinds:
+ // • DescriptorSet
// • DivergentPointer
// • InterfaceVariable
// • NonDivergentPointer