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