xref: /aosp_15_r20/external/swiftshader/src/Vulkan/VkDescriptorPool.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker // Copyright 2018 The SwiftShader Authors. All Rights Reserved.
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker //
7*03ce13f7SAndroid Build Coastguard Worker //    http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker //
9*03ce13f7SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker // limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker 
15*03ce13f7SAndroid Build Coastguard Worker #include "VkDescriptorPool.hpp"
16*03ce13f7SAndroid Build Coastguard Worker 
17*03ce13f7SAndroid Build Coastguard Worker #include "VkDescriptorSet.hpp"
18*03ce13f7SAndroid Build Coastguard Worker #include "VkDescriptorSetLayout.hpp"
19*03ce13f7SAndroid Build Coastguard Worker 
20*03ce13f7SAndroid Build Coastguard Worker #include <algorithm>
21*03ce13f7SAndroid Build Coastguard Worker #include <memory>
22*03ce13f7SAndroid Build Coastguard Worker 
23*03ce13f7SAndroid Build Coastguard Worker namespace {
24*03ce13f7SAndroid Build Coastguard Worker 
asMemory(VkDescriptorSet descriptorSet)25*03ce13f7SAndroid Build Coastguard Worker inline uint8_t *asMemory(VkDescriptorSet descriptorSet)
26*03ce13f7SAndroid Build Coastguard Worker {
27*03ce13f7SAndroid Build Coastguard Worker 	return reinterpret_cast<uint8_t *>(vk::Cast(descriptorSet));
28*03ce13f7SAndroid Build Coastguard Worker }
29*03ce13f7SAndroid Build Coastguard Worker 
30*03ce13f7SAndroid Build Coastguard Worker }  // anonymous namespace
31*03ce13f7SAndroid Build Coastguard Worker 
32*03ce13f7SAndroid Build Coastguard Worker namespace vk {
33*03ce13f7SAndroid Build Coastguard Worker 
DescriptorPool(const VkDescriptorPoolCreateInfo * pCreateInfo,void * mem)34*03ce13f7SAndroid Build Coastguard Worker DescriptorPool::DescriptorPool(const VkDescriptorPoolCreateInfo *pCreateInfo, void *mem)
35*03ce13f7SAndroid Build Coastguard Worker     : pool(static_cast<uint8_t *>(mem))
36*03ce13f7SAndroid Build Coastguard Worker     , poolSize(ComputeRequiredAllocationSize(pCreateInfo))
37*03ce13f7SAndroid Build Coastguard Worker {
38*03ce13f7SAndroid Build Coastguard Worker }
39*03ce13f7SAndroid Build Coastguard Worker 
destroy(const VkAllocationCallbacks * pAllocator)40*03ce13f7SAndroid Build Coastguard Worker void DescriptorPool::destroy(const VkAllocationCallbacks *pAllocator)
41*03ce13f7SAndroid Build Coastguard Worker {
42*03ce13f7SAndroid Build Coastguard Worker 	vk::freeHostMemory(pool, pAllocator);
43*03ce13f7SAndroid Build Coastguard Worker }
44*03ce13f7SAndroid Build Coastguard Worker 
ComputeRequiredAllocationSize(const VkDescriptorPoolCreateInfo * pCreateInfo)45*03ce13f7SAndroid Build Coastguard Worker size_t DescriptorPool::ComputeRequiredAllocationSize(const VkDescriptorPoolCreateInfo *pCreateInfo)
46*03ce13f7SAndroid Build Coastguard Worker {
47*03ce13f7SAndroid Build Coastguard Worker 	size_t size = pCreateInfo->maxSets * sw::align(sizeof(DescriptorSetHeader), 16);
48*03ce13f7SAndroid Build Coastguard Worker 
49*03ce13f7SAndroid Build Coastguard Worker 	for(uint32_t i = 0; i < pCreateInfo->poolSizeCount; i++)
50*03ce13f7SAndroid Build Coastguard Worker 	{
51*03ce13f7SAndroid Build Coastguard Worker 		uint32_t descriptorSize = DescriptorSetLayout::GetDescriptorSize(pCreateInfo->pPoolSizes[i].type);
52*03ce13f7SAndroid Build Coastguard Worker 		if(pCreateInfo->pPoolSizes[i].type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
53*03ce13f7SAndroid Build Coastguard Worker 		{
54*03ce13f7SAndroid Build Coastguard Worker 			// If type is VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK then descriptorCount
55*03ce13f7SAndroid Build Coastguard Worker 			// is the number of bytes to allocate for descriptors of this type.
56*03ce13f7SAndroid Build Coastguard Worker 			size += sw::align(pCreateInfo->pPoolSizes[i].descriptorCount, 16);
57*03ce13f7SAndroid Build Coastguard Worker 		}
58*03ce13f7SAndroid Build Coastguard Worker 		else
59*03ce13f7SAndroid Build Coastguard Worker 		{
60*03ce13f7SAndroid Build Coastguard Worker 			size += pCreateInfo->pPoolSizes[i].descriptorCount * sw::align(descriptorSize, 16);
61*03ce13f7SAndroid Build Coastguard Worker 		}
62*03ce13f7SAndroid Build Coastguard Worker 	}
63*03ce13f7SAndroid Build Coastguard Worker 
64*03ce13f7SAndroid Build Coastguard Worker 	return size;
65*03ce13f7SAndroid Build Coastguard Worker }
66*03ce13f7SAndroid Build Coastguard Worker 
allocateSets(uint32_t descriptorSetCount,const VkDescriptorSetLayout * pSetLayouts,VkDescriptorSet * pDescriptorSets,const VkDescriptorSetVariableDescriptorCountAllocateInfo * variableDescriptorCountAllocateInfo)67*03ce13f7SAndroid Build Coastguard Worker VkResult DescriptorPool::allocateSets(uint32_t descriptorSetCount, const VkDescriptorSetLayout *pSetLayouts, VkDescriptorSet *pDescriptorSets, const VkDescriptorSetVariableDescriptorCountAllocateInfo *variableDescriptorCountAllocateInfo)
68*03ce13f7SAndroid Build Coastguard Worker {
69*03ce13f7SAndroid Build Coastguard Worker 	const uint32_t *variableDescriptorCounts =
70*03ce13f7SAndroid Build Coastguard Worker 	    (variableDescriptorCountAllocateInfo && (variableDescriptorCountAllocateInfo->descriptorSetCount == descriptorSetCount)) ? variableDescriptorCountAllocateInfo->pDescriptorCounts : nullptr;
71*03ce13f7SAndroid Build Coastguard Worker 
72*03ce13f7SAndroid Build Coastguard Worker 	// FIXME (b/119409619): use an allocator here so we can control all memory allocations
73*03ce13f7SAndroid Build Coastguard Worker 	std::unique_ptr<size_t[]> layoutSizes(new size_t[descriptorSetCount]);
74*03ce13f7SAndroid Build Coastguard Worker 	for(uint32_t i = 0; i < descriptorSetCount; i++)
75*03ce13f7SAndroid Build Coastguard Worker 	{
76*03ce13f7SAndroid Build Coastguard Worker 		pDescriptorSets[i] = VK_NULL_HANDLE;
77*03ce13f7SAndroid Build Coastguard Worker 		layoutSizes[i] = vk::Cast(pSetLayouts[i])->getDescriptorSetAllocationSize(variableDescriptorCounts ? variableDescriptorCounts[i] : 0);
78*03ce13f7SAndroid Build Coastguard Worker 	}
79*03ce13f7SAndroid Build Coastguard Worker 
80*03ce13f7SAndroid Build Coastguard Worker 	VkResult result = allocateSets(&(layoutSizes[0]), descriptorSetCount, pDescriptorSets);
81*03ce13f7SAndroid Build Coastguard Worker 	if(result == VK_SUCCESS)
82*03ce13f7SAndroid Build Coastguard Worker 	{
83*03ce13f7SAndroid Build Coastguard Worker 		for(uint32_t i = 0; i < descriptorSetCount; i++)
84*03ce13f7SAndroid Build Coastguard Worker 		{
85*03ce13f7SAndroid Build Coastguard Worker 			vk::Cast(pSetLayouts[i])->initialize(vk::Cast(pDescriptorSets[i]), variableDescriptorCounts ? variableDescriptorCounts[i] : 0);
86*03ce13f7SAndroid Build Coastguard Worker 		}
87*03ce13f7SAndroid Build Coastguard Worker 	}
88*03ce13f7SAndroid Build Coastguard Worker 	return result;
89*03ce13f7SAndroid Build Coastguard Worker }
90*03ce13f7SAndroid Build Coastguard Worker 
findAvailableMemory(size_t size)91*03ce13f7SAndroid Build Coastguard Worker uint8_t *DescriptorPool::findAvailableMemory(size_t size)
92*03ce13f7SAndroid Build Coastguard Worker {
93*03ce13f7SAndroid Build Coastguard Worker 	if(nodes.empty())
94*03ce13f7SAndroid Build Coastguard Worker 	{
95*03ce13f7SAndroid Build Coastguard Worker 		return pool;
96*03ce13f7SAndroid Build Coastguard Worker 	}
97*03ce13f7SAndroid Build Coastguard Worker 
98*03ce13f7SAndroid Build Coastguard Worker 	// First, look for space at the end of the pool
99*03ce13f7SAndroid Build Coastguard Worker 	const auto itLast = nodes.rbegin();
100*03ce13f7SAndroid Build Coastguard Worker 	ptrdiff_t itemStart = itLast->set - pool;
101*03ce13f7SAndroid Build Coastguard Worker 	ptrdiff_t nextItemStart = itemStart + itLast->size;
102*03ce13f7SAndroid Build Coastguard Worker 	size_t freeSpace = poolSize - nextItemStart;
103*03ce13f7SAndroid Build Coastguard Worker 	if(freeSpace >= size)
104*03ce13f7SAndroid Build Coastguard Worker 	{
105*03ce13f7SAndroid Build Coastguard Worker 		return pool + nextItemStart;
106*03ce13f7SAndroid Build Coastguard Worker 	}
107*03ce13f7SAndroid Build Coastguard Worker 
108*03ce13f7SAndroid Build Coastguard Worker 	// Second, look for space at the beginning of the pool
109*03ce13f7SAndroid Build Coastguard Worker 	const auto itBegin = nodes.begin();
110*03ce13f7SAndroid Build Coastguard Worker 	freeSpace = itBegin->set - pool;
111*03ce13f7SAndroid Build Coastguard Worker 	if(freeSpace >= size)
112*03ce13f7SAndroid Build Coastguard Worker 	{
113*03ce13f7SAndroid Build Coastguard Worker 		return pool;
114*03ce13f7SAndroid Build Coastguard Worker 	}
115*03ce13f7SAndroid Build Coastguard Worker 
116*03ce13f7SAndroid Build Coastguard Worker 	// Finally, look between existing pool items
117*03ce13f7SAndroid Build Coastguard Worker 	const auto itEnd = nodes.end();
118*03ce13f7SAndroid Build Coastguard Worker 	auto nextIt = itBegin;
119*03ce13f7SAndroid Build Coastguard Worker 	++nextIt;
120*03ce13f7SAndroid Build Coastguard Worker 	for(auto it = itBegin; nextIt != itEnd; ++it, ++nextIt)
121*03ce13f7SAndroid Build Coastguard Worker 	{
122*03ce13f7SAndroid Build Coastguard Worker 		uint8_t *freeSpaceStart = it->set + it->size;
123*03ce13f7SAndroid Build Coastguard Worker 		freeSpace = nextIt->set - freeSpaceStart;
124*03ce13f7SAndroid Build Coastguard Worker 		if(freeSpace >= size)
125*03ce13f7SAndroid Build Coastguard Worker 		{
126*03ce13f7SAndroid Build Coastguard Worker 			return freeSpaceStart;
127*03ce13f7SAndroid Build Coastguard Worker 		}
128*03ce13f7SAndroid Build Coastguard Worker 	}
129*03ce13f7SAndroid Build Coastguard Worker 
130*03ce13f7SAndroid Build Coastguard Worker 	return nullptr;
131*03ce13f7SAndroid Build Coastguard Worker }
132*03ce13f7SAndroid Build Coastguard Worker 
allocateSets(size_t * sizes,uint32_t numAllocs,VkDescriptorSet * pDescriptorSets)133*03ce13f7SAndroid Build Coastguard Worker VkResult DescriptorPool::allocateSets(size_t *sizes, uint32_t numAllocs, VkDescriptorSet *pDescriptorSets)
134*03ce13f7SAndroid Build Coastguard Worker {
135*03ce13f7SAndroid Build Coastguard Worker 	size_t totalSize = 0;
136*03ce13f7SAndroid Build Coastguard Worker 	for(uint32_t i = 0; i < numAllocs; i++)
137*03ce13f7SAndroid Build Coastguard Worker 	{
138*03ce13f7SAndroid Build Coastguard Worker 		totalSize += sizes[i];
139*03ce13f7SAndroid Build Coastguard Worker 	}
140*03ce13f7SAndroid Build Coastguard Worker 
141*03ce13f7SAndroid Build Coastguard Worker 	if(totalSize > poolSize)
142*03ce13f7SAndroid Build Coastguard Worker 	{
143*03ce13f7SAndroid Build Coastguard Worker 		return VK_ERROR_OUT_OF_POOL_MEMORY;
144*03ce13f7SAndroid Build Coastguard Worker 	}
145*03ce13f7SAndroid Build Coastguard Worker 
146*03ce13f7SAndroid Build Coastguard Worker 	// Attempt to allocate single chunk of memory
147*03ce13f7SAndroid Build Coastguard Worker 	{
148*03ce13f7SAndroid Build Coastguard Worker 		uint8_t *memory = findAvailableMemory(totalSize);
149*03ce13f7SAndroid Build Coastguard Worker 		if(memory)
150*03ce13f7SAndroid Build Coastguard Worker 		{
151*03ce13f7SAndroid Build Coastguard Worker 			for(uint32_t i = 0; i < numAllocs; i++)
152*03ce13f7SAndroid Build Coastguard Worker 			{
153*03ce13f7SAndroid Build Coastguard Worker 				pDescriptorSets[i] = *(new(memory) DescriptorSet());
154*03ce13f7SAndroid Build Coastguard Worker 				nodes.insert(Node(memory, sizes[i]));
155*03ce13f7SAndroid Build Coastguard Worker 				memory += sizes[i];
156*03ce13f7SAndroid Build Coastguard Worker 			}
157*03ce13f7SAndroid Build Coastguard Worker 
158*03ce13f7SAndroid Build Coastguard Worker 			return VK_SUCCESS;
159*03ce13f7SAndroid Build Coastguard Worker 		}
160*03ce13f7SAndroid Build Coastguard Worker 	}
161*03ce13f7SAndroid Build Coastguard Worker 
162*03ce13f7SAndroid Build Coastguard Worker 	// Attempt to allocate each descriptor set separately
163*03ce13f7SAndroid Build Coastguard Worker 	for(uint32_t i = 0; i < numAllocs; i++)
164*03ce13f7SAndroid Build Coastguard Worker 	{
165*03ce13f7SAndroid Build Coastguard Worker 		uint8_t *memory = findAvailableMemory(sizes[i]);
166*03ce13f7SAndroid Build Coastguard Worker 		if(memory)
167*03ce13f7SAndroid Build Coastguard Worker 		{
168*03ce13f7SAndroid Build Coastguard Worker 			pDescriptorSets[i] = *(new(memory) DescriptorSet());
169*03ce13f7SAndroid Build Coastguard Worker 		}
170*03ce13f7SAndroid Build Coastguard Worker 		else
171*03ce13f7SAndroid Build Coastguard Worker 		{
172*03ce13f7SAndroid Build Coastguard Worker 			// vkAllocateDescriptorSets can be used to create multiple descriptor sets. If the
173*03ce13f7SAndroid Build Coastguard Worker 			// creation of any of those descriptor sets fails, then the implementation must
174*03ce13f7SAndroid Build Coastguard Worker 			// destroy all successfully created descriptor set objects from this command, set
175*03ce13f7SAndroid Build Coastguard Worker 			// all entries of the pDescriptorSets array to VK_NULL_HANDLE and return the error.
176*03ce13f7SAndroid Build Coastguard Worker 			for(uint32_t j = 0; j < i; j++)
177*03ce13f7SAndroid Build Coastguard Worker 			{
178*03ce13f7SAndroid Build Coastguard Worker 				freeSet(pDescriptorSets[j]);
179*03ce13f7SAndroid Build Coastguard Worker 				pDescriptorSets[j] = VK_NULL_HANDLE;
180*03ce13f7SAndroid Build Coastguard Worker 			}
181*03ce13f7SAndroid Build Coastguard Worker 			return (computeTotalFreeSize() > totalSize) ? VK_ERROR_FRAGMENTED_POOL : VK_ERROR_OUT_OF_POOL_MEMORY;
182*03ce13f7SAndroid Build Coastguard Worker 		}
183*03ce13f7SAndroid Build Coastguard Worker 		nodes.insert(Node(memory, sizes[i]));
184*03ce13f7SAndroid Build Coastguard Worker 	}
185*03ce13f7SAndroid Build Coastguard Worker 
186*03ce13f7SAndroid Build Coastguard Worker 	return VK_SUCCESS;
187*03ce13f7SAndroid Build Coastguard Worker }
188*03ce13f7SAndroid Build Coastguard Worker 
freeSets(uint32_t descriptorSetCount,const VkDescriptorSet * pDescriptorSets)189*03ce13f7SAndroid Build Coastguard Worker void DescriptorPool::freeSets(uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets)
190*03ce13f7SAndroid Build Coastguard Worker {
191*03ce13f7SAndroid Build Coastguard Worker 	for(uint32_t i = 0; i < descriptorSetCount; i++)
192*03ce13f7SAndroid Build Coastguard Worker 	{
193*03ce13f7SAndroid Build Coastguard Worker 		freeSet(pDescriptorSets[i]);
194*03ce13f7SAndroid Build Coastguard Worker 	}
195*03ce13f7SAndroid Build Coastguard Worker }
196*03ce13f7SAndroid Build Coastguard Worker 
freeSet(const VkDescriptorSet descriptorSet)197*03ce13f7SAndroid Build Coastguard Worker void DescriptorPool::freeSet(const VkDescriptorSet descriptorSet)
198*03ce13f7SAndroid Build Coastguard Worker {
199*03ce13f7SAndroid Build Coastguard Worker 	const auto itEnd = nodes.end();
200*03ce13f7SAndroid Build Coastguard Worker 	auto it = std::find(nodes.begin(), itEnd, asMemory(descriptorSet));
201*03ce13f7SAndroid Build Coastguard Worker 	if(it != itEnd)
202*03ce13f7SAndroid Build Coastguard Worker 	{
203*03ce13f7SAndroid Build Coastguard Worker 		nodes.erase(it);
204*03ce13f7SAndroid Build Coastguard Worker 	}
205*03ce13f7SAndroid Build Coastguard Worker }
206*03ce13f7SAndroid Build Coastguard Worker 
reset()207*03ce13f7SAndroid Build Coastguard Worker VkResult DescriptorPool::reset()
208*03ce13f7SAndroid Build Coastguard Worker {
209*03ce13f7SAndroid Build Coastguard Worker 	nodes.clear();
210*03ce13f7SAndroid Build Coastguard Worker 
211*03ce13f7SAndroid Build Coastguard Worker 	return VK_SUCCESS;
212*03ce13f7SAndroid Build Coastguard Worker }
213*03ce13f7SAndroid Build Coastguard Worker 
computeTotalFreeSize() const214*03ce13f7SAndroid Build Coastguard Worker size_t DescriptorPool::computeTotalFreeSize() const
215*03ce13f7SAndroid Build Coastguard Worker {
216*03ce13f7SAndroid Build Coastguard Worker 	size_t totalFreeSize = 0;
217*03ce13f7SAndroid Build Coastguard Worker 
218*03ce13f7SAndroid Build Coastguard Worker 	// Compute space at the end of the pool
219*03ce13f7SAndroid Build Coastguard Worker 	const auto itLast = nodes.rbegin();
220*03ce13f7SAndroid Build Coastguard Worker 	totalFreeSize += poolSize - ((itLast->set - pool) + itLast->size);
221*03ce13f7SAndroid Build Coastguard Worker 
222*03ce13f7SAndroid Build Coastguard Worker 	// Compute space at the beginning of the pool
223*03ce13f7SAndroid Build Coastguard Worker 	const auto itBegin = nodes.begin();
224*03ce13f7SAndroid Build Coastguard Worker 	totalFreeSize += itBegin->set - pool;
225*03ce13f7SAndroid Build Coastguard Worker 
226*03ce13f7SAndroid Build Coastguard Worker 	// Finally, look between existing pool items
227*03ce13f7SAndroid Build Coastguard Worker 	const auto itEnd = nodes.end();
228*03ce13f7SAndroid Build Coastguard Worker 	auto nextIt = itBegin;
229*03ce13f7SAndroid Build Coastguard Worker 	++nextIt;
230*03ce13f7SAndroid Build Coastguard Worker 	for(auto it = itBegin; nextIt != itEnd; ++it, ++nextIt)
231*03ce13f7SAndroid Build Coastguard Worker 	{
232*03ce13f7SAndroid Build Coastguard Worker 		totalFreeSize += (nextIt->set - it->set) - it->size;
233*03ce13f7SAndroid Build Coastguard Worker 	}
234*03ce13f7SAndroid Build Coastguard Worker 
235*03ce13f7SAndroid Build Coastguard Worker 	return totalFreeSize;
236*03ce13f7SAndroid Build Coastguard Worker }
237*03ce13f7SAndroid Build Coastguard Worker 
238*03ce13f7SAndroid Build Coastguard Worker }  // namespace vk