Home | History | Annotate | Download | only in Vulkan
      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 
     23 DescriptorPool::DescriptorPool(const VkDescriptorPoolCreateInfo* pCreateInfo, void* mem) :
     24 	pool(reinterpret_cast<VkDescriptorSet>(mem)),
     25 	poolSize(ComputeRequiredAllocationSize(pCreateInfo))
     26 {
     27 }
     28 
     29 void DescriptorPool::destroy(const VkAllocationCallbacks* pAllocator)
     30 {
     31 	vk::deallocate(pool, pAllocator);
     32 }
     33 
     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 
     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 
     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 
    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 
    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 
    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 
    168 VkResult DescriptorPool::reset()
    169 {
    170 	nodes.clear();
    171 
    172 	return VK_SUCCESS;
    173 }
    174 
    175 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