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