• 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 #include "VkDescriptorSetLayout.hpp"
17 #include <algorithm>
18 #include <memory>
19 
20 namespace vk
21 {
22 
DescriptorPool(const VkDescriptorPoolCreateInfo * pCreateInfo,void * mem)23 DescriptorPool::DescriptorPool(const VkDescriptorPoolCreateInfo* pCreateInfo, void* mem) :
24 	pool(reinterpret_cast<VkDescriptorSet>(mem)),
25 	poolSize(ComputeRequiredAllocationSize(pCreateInfo))
26 {
27 }
28 
destroy(const VkAllocationCallbacks * pAllocator)29 void DescriptorPool::destroy(const VkAllocationCallbacks* pAllocator)
30 {
31 	vk::deallocate(pool, pAllocator);
32 }
33 
ComputeRequiredAllocationSize(const VkDescriptorPoolCreateInfo * pCreateInfo)34 size_t DescriptorPool::ComputeRequiredAllocationSize(const VkDescriptorPoolCreateInfo* pCreateInfo)
35 {
36 	size_t size = 0;
37 
38 	for(uint32_t i = 0; i < pCreateInfo->poolSizeCount; i++)
39 	{
40 		size += pCreateInfo->pPoolSizes[i].descriptorCount * DescriptorSetLayout::GetDescriptorSize(pCreateInfo->pPoolSizes[i].type);
41 	}
42 
43 	return size;
44 }
45 
allocateSets(uint32_t descriptorSetCount,const VkDescriptorSetLayout * pSetLayouts,VkDescriptorSet * pDescriptorSets)46 VkResult DescriptorPool::allocateSets(uint32_t descriptorSetCount, const VkDescriptorSetLayout* pSetLayouts, VkDescriptorSet* pDescriptorSets)
47 {
48 	std::unique_ptr<size_t[]> layoutSizes(new size_t[descriptorSetCount]);
49 	for(uint32_t i = 0; i < descriptorSetCount; i++)
50 	{
51 		pDescriptorSets[i] = VK_NULL_HANDLE;
52 		layoutSizes[i] = Cast(pSetLayouts[i])->getSize();
53 	}
54 
55 	return allocateSets(&(layoutSizes[0]), descriptorSetCount, pDescriptorSets);
56 }
57 
findAvailableMemory(size_t size)58 VkDescriptorSet DescriptorPool::findAvailableMemory(size_t size)
59 {
60 	if(nodes.empty())
61 	{
62 		return pool;
63 	}
64 
65 	// First, look for space at the end of the pool
66 	const auto itLast = nodes.rbegin();
67 	ptrdiff_t itemStart = reinterpret_cast<char*>(itLast->set) - reinterpret_cast<char*>(pool);
68 	ptrdiff_t nextItemStart = itemStart + itLast->size;
69 	size_t freeSpace = poolSize - nextItemStart;
70 	if(freeSpace >= size)
71 	{
72 		return reinterpret_cast<VkDescriptorSet>(nextItemStart);
73 	}
74 
75 	// Second, look for space at the beginning of the pool
76 	const auto itBegin = nodes.end();
77 	freeSpace = reinterpret_cast<char*>(itBegin->set) - reinterpret_cast<char*>(pool);
78 	if(freeSpace >= size)
79 	{
80 		return pool;
81 	}
82 
83 	// Finally, look between existing pool items
84 	const auto itEnd = nodes.end();
85 	auto nextIt = itBegin;
86 	++nextIt;
87 	for(auto it = itBegin; nextIt != itEnd; ++it, ++nextIt)
88 	{
89 		VkDescriptorSet freeSpaceStart = reinterpret_cast<VkDescriptorSet>(reinterpret_cast<char*>(it->set) + it->size);
90 		freeSpace = reinterpret_cast<char*>(nextIt->set) - reinterpret_cast<char*>(freeSpaceStart);
91 		if(freeSpace >= size)
92 		{
93 			return freeSpaceStart;
94 		}
95 	}
96 
97 	return VK_NULL_HANDLE;
98 }
99 
allocateSets(size_t * sizes,uint32_t numAllocs,VkDescriptorSet * pDescriptorSets)100 VkResult DescriptorPool::allocateSets(size_t* sizes, uint32_t numAllocs, VkDescriptorSet* pDescriptorSets)
101 {
102 	size_t totalSize = 0;
103 	for(uint32_t i = 0; i < numAllocs; i++)
104 	{
105 		totalSize += sizes[i];
106 	}
107 
108 	if(totalSize > poolSize)
109 	{
110 		return VK_ERROR_OUT_OF_POOL_MEMORY;
111 	}
112 
113 	// Attempt to allocate single chunk of memory
114 	VkDescriptorSet memory = findAvailableMemory(totalSize);
115 	if(memory != VK_NULL_HANDLE)
116 	{
117 		pDescriptorSets[0] = memory;
118 		for(uint32_t i = 1; i < numAllocs; i++)
119 		{
120 			pDescriptorSets[i] =
121 				reinterpret_cast<VkDescriptorSet>(reinterpret_cast<char*>(memory) + sizes[i - 1]);
122 			nodes.insert(Node(pDescriptorSets[i], sizes[i]));
123 		}
124 		return VK_SUCCESS;
125 	}
126 
127 	// Atttempt to allocate each descriptor set separately
128 	for(uint32_t i = 0; i < numAllocs; i++)
129 	{
130 		pDescriptorSets[i] = findAvailableMemory(sizes[i]);
131 		if(pDescriptorSets[i] == VK_NULL_HANDLE)
132 		{
133 			// vkAllocateDescriptorSets can be used to create multiple descriptor sets. If the
134 			// creation of any of those descriptor sets fails, then the implementation must
135 			// destroy all successfully created descriptor set objects from this command, set
136 			// all entries of the pDescriptorSets array to VK_NULL_HANDLE and return the error.
137 			for(uint32_t j = 0; j < i; j++)
138 			{
139 				freeSet(pDescriptorSets[j]);
140 				pDescriptorSets[j] = VK_NULL_HANDLE;
141 			}
142 			return (computeTotalFreeSize() > totalSize) ? VK_ERROR_FRAGMENTED_POOL : VK_ERROR_OUT_OF_POOL_MEMORY;
143 		}
144 		nodes.insert(Node(pDescriptorSets[i], sizes[i]));
145 	}
146 
147 	return VK_SUCCESS;
148 }
149 
freeSets(uint32_t descriptorSetCount,const VkDescriptorSet * pDescriptorSets)150 void DescriptorPool::freeSets(uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets)
151 {
152 	for(uint32_t i = 0; i < descriptorSetCount; i++)
153 	{
154 		freeSet(pDescriptorSets[i]);
155 	}
156 }
157 
freeSet(const VkDescriptorSet descriptorSet)158 void DescriptorPool::freeSet(const VkDescriptorSet descriptorSet)
159 {
160 	const auto itEnd = nodes.end();
161 	auto it = std::find(nodes.begin(), itEnd, descriptorSet);
162 	if(it != itEnd)
163 	{
164 		nodes.erase(it);
165 	}
166 }
167 
reset()168 VkResult DescriptorPool::reset()
169 {
170 	nodes.clear();
171 
172 	return VK_SUCCESS;
173 }
174 
computeTotalFreeSize() const175 size_t DescriptorPool::computeTotalFreeSize() const
176 {
177 	size_t totalFreeSize = 0;
178 
179 	// Compute space at the end of the pool
180 	const auto itLast = nodes.rbegin();
181 	totalFreeSize += poolSize - ((reinterpret_cast<char*>(itLast->set) - reinterpret_cast<char*>(pool)) + itLast->size);
182 
183 	// Compute space at the beginning of the pool
184 	const auto itBegin = nodes.end();
185 	totalFreeSize += reinterpret_cast<char*>(itBegin->set) - reinterpret_cast<char*>(pool);
186 
187 	// Finally, look between existing pool items
188 	const auto itEnd = nodes.end();
189 	auto nextIt = itBegin;
190 	++nextIt;
191 	for(auto it = itBegin; nextIt != itEnd; ++it, ++nextIt)
192 	{
193 		totalFreeSize += (reinterpret_cast<char*>(nextIt->set) - reinterpret_cast<char*>(it->set)) - it->size;
194 	}
195 
196 	return totalFreeSize;
197 }
198 
199 } // namespace vk