Commit ca9de964 by Nicolas Capens Committed by Nicolas Capens

Fix ordering of descriptor set bindings

The Vulkan spec states that for vkCmdBindDescriptorSets(): "If any of the sets being bound include dynamic uniform or storage buffers, then pDynamicOffsets includes one element for each array element in each dynamic descriptor type binding in each set. Values are taken from pDynamicOffsets in an order such that all entries for set N come before set N+1; within a set, entries are ordered by the binding numbers in the descriptor set layouts; and within a binding array, elements are in order." Using a direct-mapped array of bindings ensures we can easily compute which descriptor each dynamic offset applies to. This is also supported by the spec: "The above layout definition allows the descriptor bindings to be specified sparsely such that not all binding numbers between 0 and the maximum binding number need to be specified in the pBindings array. Bindings that are not specified have a descriptorCount and stageFlags of zero, and the value of descriptorType is undefined. However, all binding numbers between 0 and the maximum binding number in the VkDescriptorSetLayoutCreateInfo::pBindings array may consume memory in the descriptor set layout even if not all descriptor bindings are used, though it should not consume additional memory from the descriptor pool. The maximum binding number specified should be as compact as possible to avoid wasted memory." In addition, the spec states that for vkUpdateDescriptorSets(): "If the dstBinding has fewer than descriptorCount array elements remaining starting from dstArrayElement, then the remainder will be used to update the subsequent binding - dstBinding+1 starting at array element zero." Which also demands that the bindings in the descriptor set are sorted by binding number. Bug: b/154241029 Change-Id: Iae550a02bc9fa1132473c6ba4c5840440f970155 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/44308 Presubmit-Ready: Nicolas Capens <nicolascapens@google.com> Tested-by: 's avatarNicolas Capens <nicolascapens@google.com> Reviewed-by: 's avatarAlexis Hétu <sugoi@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com>
parent 7483e56f
...@@ -172,20 +172,11 @@ SpirvShader::EmitResult SpirvShader::EmitVariable(InsnIterator insn, EmitState * ...@@ -172,20 +172,11 @@ SpirvShader::EmitResult SpirvShader::EmitVariable(InsnIterator insn, EmitState *
uint32_t arrayIndex = 0; // TODO(b/129523279) uint32_t arrayIndex = 0; // TODO(b/129523279)
auto setLayout = routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet); auto setLayout = routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet);
if(setLayout->hasBinding(d.Binding)) uint32_t bindingOffset = static_cast<uint32_t>(setLayout->getBindingOffset(d.Binding, arrayIndex));
{ Pointer<Byte> set = routine->descriptorSets[d.DescriptorSet]; // DescriptorSet*
uint32_t bindingOffset = static_cast<uint32_t>(setLayout->getBindingOffset(d.Binding, arrayIndex)); Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset); // vk::SampledImageDescriptor*
Pointer<Byte> set = routine->descriptorSets[d.DescriptorSet]; // DescriptorSet* auto size = 0; // Not required as this pointer is not directly used by SIMD::Read or SIMD::Write.
Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset); // vk::SampledImageDescriptor* state->createPointer(resultId, SIMD::Pointer(binding, size));
auto size = 0; // Not required as this pointer is not directly used by SIMD::Read or SIMD::Write.
state->createPointer(resultId, SIMD::Pointer(binding, size));
}
else
{
// TODO: Error if the variable with the non-existant binding is
// used? Or perhaps strip these unused variable declarations as
// a preprocess on the SPIR-V?
}
break; break;
} }
case spv::StorageClassUniform: case spv::StorageClassUniform:
...@@ -402,7 +393,6 @@ SIMD::Pointer SpirvShader::GetPointerToData(Object::ID id, int arrayIndex, EmitS ...@@ -402,7 +393,6 @@ SIMD::Pointer SpirvShader::GetPointerToData(Object::ID id, int arrayIndex, EmitS
auto set = state->getPointer(id); auto set = state->getPointer(id);
auto setLayout = routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet); auto setLayout = routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet);
ASSERT_MSG(setLayout->hasBinding(d.Binding), "Descriptor set %d does not contain binding %d", int(d.DescriptorSet), int(d.Binding));
int bindingOffset = static_cast<int>(setLayout->getBindingOffset(d.Binding, arrayIndex)); int bindingOffset = static_cast<int>(setLayout->getBindingOffset(d.Binding, arrayIndex));
Pointer<Byte> descriptor = set.base + bindingOffset; // BufferDescriptor* Pointer<Byte> descriptor = set.base + bindingOffset; // BufferDescriptor*
......
...@@ -31,7 +31,7 @@ struct alignas(16) SampledImageDescriptor ...@@ -31,7 +31,7 @@ struct alignas(16) SampledImageDescriptor
{ {
~SampledImageDescriptor() = delete; ~SampledImageDescriptor() = delete;
void updateSampler(VkSampler sampler); void updateSampler(const vk::Sampler *sampler);
// TODO(b/129523279): Minimize to the data actually needed. // TODO(b/129523279): Minimize to the data actually needed.
vk::Sampler sampler; vk::Sampler sampler;
...@@ -78,6 +78,15 @@ struct alignas(16) BufferDescriptor ...@@ -78,6 +78,15 @@ struct alignas(16) BufferDescriptor
class DescriptorSetLayout : public Object<DescriptorSetLayout, VkDescriptorSetLayout> class DescriptorSetLayout : public Object<DescriptorSetLayout, VkDescriptorSetLayout>
{ {
struct Binding
{
VkDescriptorType descriptorType;
uint32_t descriptorCount;
const vk::Sampler **immutableSamplers;
uint32_t offset; // Offset in bytes in the descriptor set data.
};
public: public:
DescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo *pCreateInfo, void *mem); DescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo *pCreateInfo, void *mem);
void destroy(const VkAllocationCallbacks *pAllocator); void destroy(const VkAllocationCallbacks *pAllocator);
...@@ -96,12 +105,6 @@ public: ...@@ -96,12 +105,6 @@ public:
// Returns the total size of the descriptor set in bytes. // Returns the total size of the descriptor set in bytes.
size_t getDescriptorSetAllocationSize() const; size_t getDescriptorSetAllocationSize() const;
// Returns the number of bindings in the descriptor set.
size_t getBindingCount() const;
// Returns true iff the given binding exists.
bool hasBinding(uint32_t binding) const;
// Returns the byte offset from the base address of the descriptor set for // Returns the byte offset from the base address of the descriptor set for
// the given binding and array element within that binding. // the given binding and array element within that binding.
size_t getBindingOffset(uint32_t binding, size_t arrayElement) const; size_t getBindingOffset(uint32_t binding, size_t arrayElement) const;
...@@ -131,13 +134,11 @@ public: ...@@ -131,13 +134,11 @@ public:
private: private:
size_t getDescriptorSetDataSize() const; size_t getDescriptorSetDataSize() const;
uint32_t getBindingIndex(uint32_t binding) const;
static bool isDynamic(VkDescriptorType type); static bool isDynamic(VkDescriptorType type);
VkDescriptorSetLayoutCreateFlags flags; const VkDescriptorSetLayoutCreateFlags flags;
uint32_t bindingCount; uint32_t bindingsArraySize = 0;
VkDescriptorSetLayoutBinding *bindings; Binding *const bindings; // Direct-indexed array of bindings.
size_t *bindingOffsets;
}; };
static inline DescriptorSetLayout *Cast(VkDescriptorSetLayout object) static inline DescriptorSetLayout *Cast(VkDescriptorSetLayout object)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment