Store binding information in the pipeline layout

Descriptor set layout binding information needed by the pipeline layout
has to persist after the descriptor set layout object has been
destroyed.

The spec states:
"VkDescriptorSetLayout objects may be accessed by commands that operate
on descriptor sets allocated using that layout, and those descriptor
sets must not be updated with vkUpdateDescriptorSets after the
descriptor set layout has been destroyed. Otherwise, a
VkDescriptorSetLayout object passed as a parameter to create another
object is not further accessed by that object after the duration of the
command it is passed into."

Bug: b/154522740
Change-Id: Ia6349383139ae0fceac328a685b06e2ec253a589
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/44328
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
index 4acabff..3efc4d2 100644
--- a/src/Vulkan/VkCommandBuffer.cpp
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -1105,12 +1105,12 @@
 	{
 		ASSERT_OR_RETURN((pipelineBindPoint < VK_PIPELINE_BIND_POINT_RANGE_SIZE) && (setNumber < vk::MAX_BOUND_DESCRIPTOR_SETS));
 		auto &pipelineState = executionState.pipelineState[pipelineBindPoint];
-		auto dynamicBindingBaseIndex = pipelineLayout->getDynamicOffsetBaseIndex(setNumber);
-		ASSERT_OR_RETURN(dynamicBindingBaseIndex + dynamicOffsetCount <= vk::MAX_DESCRIPTOR_SET_COMBINED_BUFFERS_DYNAMIC);
-
 		pipelineState.descriptorSets[setNumber] = descriptorSet->data;
+
 		for(uint32_t i = 0; i < dynamicOffsetCount; i++)
 		{
+			auto dynamicBindingBaseIndex = pipelineLayout->getDynamicOffsetIndex(setNumber, 0);
+			ASSERT_OR_RETURN(dynamicBindingBaseIndex + dynamicOffsetCount <= vk::MAX_DESCRIPTOR_SET_COMBINED_BUFFERS_DYNAMIC);
 			pipelineState.descriptorDynamicOffsets[dynamicBindingBaseIndex + i] = dynamicOffsets[i];
 		}
 	}
diff --git a/src/Vulkan/VkDescriptorSetLayout.cpp b/src/Vulkan/VkDescriptorSetLayout.cpp
index 102a024..12bf32b 100644
--- a/src/Vulkan/VkDescriptorSetLayout.cpp
+++ b/src/Vulkan/VkDescriptorSetLayout.cpp
@@ -188,6 +188,12 @@
 	return bindings[bindingNumber].offset;
 }
 
+uint32_t DescriptorSetLayout::getDescriptorCount(uint32_t bindingNumber) const
+{
+	ASSERT(bindingNumber < bindingsArraySize);
+	return bindings[bindingNumber].descriptorCount;
+}
+
 uint32_t DescriptorSetLayout::getDynamicDescriptorCount() const
 {
 	uint32_t count = 0;
diff --git a/src/Vulkan/VkDescriptorSetLayout.hpp b/src/Vulkan/VkDescriptorSetLayout.hpp
index 5fd4d79..b82490a 100644
--- a/src/Vulkan/VkDescriptorSetLayout.hpp
+++ b/src/Vulkan/VkDescriptorSetLayout.hpp
@@ -110,21 +110,28 @@
 	size_t getDescriptorSetAllocationSize() const;
 
 	// Returns the byte offset from the base address of the descriptor set for
-	// the given binding.
+	// the given binding number.
 	uint32_t getBindingOffset(uint32_t bindingNumber) const;
 
+	// Returns the number of descriptors for the given binding number.
+	uint32_t getDescriptorCount(uint32_t bindingNumber) const;
+
 	// Returns the number of descriptors across all bindings that are dynamic.
 	uint32_t getDynamicDescriptorCount() const;
 
 	// Returns the relative index into the pipeline's dynamic offsets array for
-	// the given binding. This index should be added to the base index
+	// the given binding number. This index should be added to the base index
 	// returned by PipelineLayout::getDynamicOffsetBase() to produce the
 	// starting index for dynamic descriptors.
 	uint32_t getDynamicOffsetIndex(uint32_t bindingNumber) const;
 
-	// Returns the descriptor type for the given binding.
+	// Returns the descriptor type for the given binding number.
 	VkDescriptorType getDescriptorType(uint32_t bindingNumber) const;
 
+	// Returns the number of entries in the direct-indexed array of bindings.
+	// It equals the highest binding number + 1.
+	uint32_t getBindingsArraySize() const { return bindingsArraySize; }
+
 private:
 	uint8_t *getDescriptorPointer(DescriptorSet *descriptorSet, uint32_t bindingNumber, uint32_t arrayElement, uint32_t count, size_t *typeSize) const;
 	size_t getDescriptorSetDataSize() const;
diff --git a/src/Vulkan/VkPipelineLayout.cpp b/src/Vulkan/VkPipelineLayout.cpp
index 9288a92..b724c34 100644
--- a/src/Vulkan/VkPipelineLayout.cpp
+++ b/src/Vulkan/VkPipelineLayout.cpp
@@ -26,42 +26,51 @@
     , descriptorSetCount(pCreateInfo->setLayoutCount)
     , pushConstantRangeCount(pCreateInfo->pushConstantRangeCount)
 {
-	char *hostMem = reinterpret_cast<char *>(mem);
-
-	size_t setLayoutsSize = pCreateInfo->setLayoutCount * sizeof(DescriptorSetLayout *);
-	descriptorSetLayouts = reinterpret_cast<const DescriptorSetLayout **>(hostMem);
+	Binding *bindingStorage = reinterpret_cast<Binding *>(mem);
+	uint32_t dynamicOffsetIndex = 0;
 	for(uint32_t i = 0; i < pCreateInfo->setLayoutCount; i++)
 	{
-		descriptorSetLayouts[i] = vk::Cast(pCreateInfo->pSetLayouts[i]);
+		const vk::DescriptorSetLayout *setLayout = vk::Cast(pCreateInfo->pSetLayouts[i]);
+		uint32_t bindingsArraySize = setLayout->getBindingsArraySize();
+		descriptorSets[i].bindings = bindingStorage;
+		bindingStorage += bindingsArraySize;
+
+		descriptorSets[i].dynamicDescriptorCount = setLayout->getDynamicDescriptorCount();
+		descriptorSets[i].bindingCount = bindingsArraySize;
+
+		for(uint32_t j = 0; j < bindingsArraySize; j++)
+		{
+			descriptorSets[i].bindings[j].descriptorType = setLayout->getDescriptorType(j);
+			descriptorSets[i].bindings[j].offset = setLayout->getBindingOffset(j);
+			descriptorSets[i].bindings[j].dynamicOffsetIndex = dynamicOffsetIndex;
+
+			if(DescriptorSetLayout::IsDescriptorDynamic(descriptorSets[i].bindings[j].descriptorType))
+			{
+				dynamicOffsetIndex += setLayout->getDescriptorCount(j);
+			}
+		}
 	}
-	hostMem += setLayoutsSize;
 
 	size_t pushConstantRangesSize = pCreateInfo->pushConstantRangeCount * sizeof(VkPushConstantRange);
-	pushConstantRanges = reinterpret_cast<VkPushConstantRange *>(hostMem);
+	pushConstantRanges = reinterpret_cast<VkPushConstantRange *>(bindingStorage);
 	memcpy(pushConstantRanges, pCreateInfo->pPushConstantRanges, pushConstantRangesSize);
-	hostMem += pushConstantRangesSize;
-
-	dynamicOffsetBaseIndices = reinterpret_cast<uint32_t *>(hostMem);
-	uint32_t dynamicOffsetBase = 0;
-	for(uint32_t i = 0; i < descriptorSetCount; i++)
-	{
-		uint32_t dynamicDescriptorCount = descriptorSetLayouts[i]->getDynamicDescriptorCount();
-		ASSERT_OR_RETURN((dynamicOffsetBase + dynamicDescriptorCount) <= MAX_DESCRIPTOR_SET_COMBINED_BUFFERS_DYNAMIC);
-		dynamicOffsetBaseIndices[i] = dynamicOffsetBase;
-		dynamicOffsetBase += dynamicDescriptorCount;
-	}
 }
 
 void PipelineLayout::destroy(const VkAllocationCallbacks *pAllocator)
 {
-	vk::deallocate(descriptorSetLayouts, pAllocator);  // pushConstantRanges are in the same allocation
+	vk::deallocate(descriptorSets[0].bindings, pAllocator);  // pushConstantRanges are in the same allocation
 }
 
 size_t PipelineLayout::ComputeRequiredAllocationSize(const VkPipelineLayoutCreateInfo *pCreateInfo)
 {
-	return (pCreateInfo->setLayoutCount * sizeof(DescriptorSetLayout *)) +        // descriptorSetLayouts[]
-	       (pCreateInfo->pushConstantRangeCount * sizeof(VkPushConstantRange)) +  // pushConstantRanges[]
-	       (pCreateInfo->setLayoutCount * sizeof(uint32_t));                      // dynamicOffsetBaseIndices[]
+	uint32_t bindingsCount = 0;
+	for(uint32_t i = 0; i < pCreateInfo->setLayoutCount; i++)
+	{
+		bindingsCount += vk::Cast(pCreateInfo->pSetLayouts[i])->getBindingsArraySize();
+	}
+
+	return bindingsCount * sizeof(Binding) +                                   // descriptorSets[]
+	       pCreateInfo->pushConstantRangeCount * sizeof(VkPushConstantRange);  // pushConstantRanges[]
 }
 
 size_t PipelineLayout::getDescriptorSetCount() const
@@ -71,27 +80,26 @@
 
 uint32_t PipelineLayout::getDynamicDescriptorCount(uint32_t setNumber) const
 {
-	return getDescriptorSetLayout(setNumber)->getDynamicDescriptorCount();
-}
-
-uint32_t PipelineLayout::getDynamicOffsetBaseIndex(uint32_t setNumber) const
-{
-	return dynamicOffsetBaseIndices[setNumber];
+	ASSERT(setNumber < descriptorSetCount);
+	return descriptorSets[setNumber].dynamicDescriptorCount;
 }
 
 uint32_t PipelineLayout::getDynamicOffsetIndex(uint32_t setNumber, uint32_t bindingNumber) const
 {
-	return getDynamicOffsetBaseIndex(setNumber) + getDescriptorSetLayout(setNumber)->getDynamicOffsetIndex(bindingNumber);
+	ASSERT(setNumber < descriptorSetCount && bindingNumber < descriptorSets[setNumber].bindingCount);
+	return descriptorSets[setNumber].bindings[bindingNumber].dynamicOffsetIndex;
 }
 
 uint32_t PipelineLayout::getBindingOffset(uint32_t setNumber, uint32_t bindingNumber) const
 {
-	return getDescriptorSetLayout(setNumber)->getBindingOffset(bindingNumber);
+	ASSERT(setNumber < descriptorSetCount && bindingNumber < descriptorSets[setNumber].bindingCount);
+	return descriptorSets[setNumber].bindings[bindingNumber].offset;
 }
 
 VkDescriptorType PipelineLayout::getDescriptorType(uint32_t setNumber, uint32_t bindingNumber) const
 {
-	return getDescriptorSetLayout(setNumber)->getDescriptorType(bindingNumber);
+	ASSERT(setNumber < descriptorSetCount && bindingNumber < descriptorSets[setNumber].bindingCount);
+	return descriptorSets[setNumber].bindings[bindingNumber].descriptorType;
 }
 
 uint32_t PipelineLayout::getDescriptorSize(uint32_t setNumber, uint32_t bindingNumber) const
@@ -104,10 +112,4 @@
 	return DescriptorSetLayout::IsDescriptorDynamic(getDescriptorType(setNumber, bindingNumber));
 }
 
-DescriptorSetLayout const *PipelineLayout::getDescriptorSetLayout(size_t descriptorSet) const
-{
-	ASSERT(descriptorSet < descriptorSetCount);
-	return descriptorSetLayouts[descriptorSet];
-}
-
 }  // namespace vk
diff --git a/src/Vulkan/VkPipelineLayout.hpp b/src/Vulkan/VkPipelineLayout.hpp
index 3d7ae29..247f8a7 100644
--- a/src/Vulkan/VkPipelineLayout.hpp
+++ b/src/Vulkan/VkPipelineLayout.hpp
@@ -15,6 +15,7 @@
 #ifndef VK_PIPELINE_LAYOUT_HPP_
 #define VK_PIPELINE_LAYOUT_HPP_
 
+#include "VkConfig.h"
 #include "VkDescriptorSetLayout.hpp"
 
 namespace vk {
@@ -31,8 +32,7 @@
 	uint32_t getDynamicDescriptorCount(uint32_t setNumber) const;
 
 	// Returns the index into the pipeline's dynamic offsets array for
-	// the given descriptor set (and binding number).
-	uint32_t getDynamicOffsetBaseIndex(uint32_t setNumber) const;
+	// the given descriptor set and binding number.
 	uint32_t getDynamicOffsetIndex(uint32_t setNumber, uint32_t bindingNumber) const;
 
 	uint32_t getBindingOffset(uint32_t setNumber, uint32_t bindingNumber) const;
@@ -43,13 +43,25 @@
 	const uint32_t identifier;
 
 private:
-	DescriptorSetLayout const *getDescriptorSetLayout(size_t descriptorSet) const;
+	struct Binding
+	{
+		VkDescriptorType descriptorType;
+		uint32_t offset;              // Offset in bytes in the descriptor set data.
+		uint32_t dynamicOffsetIndex;  // TODO(b/154914395): Debug only.
+	};
+
+	struct DescriptorSet
+	{
+		Binding *bindings;
+		uint32_t dynamicDescriptorCount;
+		uint32_t bindingCount;
+	};
+
+	DescriptorSet descriptorSets[MAX_BOUND_DESCRIPTOR_SETS];
 
 	const uint32_t descriptorSetCount = 0;
-	const DescriptorSetLayout **descriptorSetLayouts = nullptr;
 	const uint32_t pushConstantRangeCount = 0;
 	VkPushConstantRange *pushConstantRanges = nullptr;
-	uint32_t *dynamicOffsetBaseIndices = nullptr;  // Base index per descriptor set for dynamic buffer offsets.
 };
 
 static inline PipelineLayout *Cast(VkPipelineLayout object)