Refactor preallocated descriptor handling.

Add MVKBitArray class.
Consolidate MVKPreallocatedDescriptors into MVKDescriptorPool
and remove MVKPreallocatedDescriptors.
This commit is contained in:
Bill Hollings 2021-03-11 18:10:22 -05:00
parent 20b5067ee5
commit 984a74fffd
4 changed files with 331 additions and 286 deletions

View File

@ -325,6 +325,9 @@
A9C96DD31DDC20C20053187F /* MVKMTLBufferAllocation.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9C96DCF1DDC20C20053187F /* MVKMTLBufferAllocation.mm */; };
A9CEAAD5227378D400FAF779 /* mvk_datatypes.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A9CEAAD1227378D400FAF779 /* mvk_datatypes.hpp */; };
A9CEAAD6227378D400FAF779 /* mvk_datatypes.hpp in Headers */ = {isa = PBXBuildFile; fileRef = A9CEAAD1227378D400FAF779 /* mvk_datatypes.hpp */; };
A9D7104F25CDE05E00E38106 /* MVKBitArray.h in Headers */ = {isa = PBXBuildFile; fileRef = A9D7104E25CDE05E00E38106 /* MVKBitArray.h */; };
A9D7105025CDE05E00E38106 /* MVKBitArray.h in Headers */ = {isa = PBXBuildFile; fileRef = A9D7104E25CDE05E00E38106 /* MVKBitArray.h */; };
A9D7105125CDE05E00E38106 /* MVKBitArray.h in Headers */ = {isa = PBXBuildFile; fileRef = A9D7104E25CDE05E00E38106 /* MVKBitArray.h */; };
A9E4B7891E1D8AF10046A4CE /* MVKMTLResourceBindings.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E4B7881E1D8AF10046A4CE /* MVKMTLResourceBindings.h */; };
A9E4B78A1E1D8AF10046A4CE /* MVKMTLResourceBindings.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E4B7881E1D8AF10046A4CE /* MVKMTLResourceBindings.h */; };
A9E53DD72100B197002781DD /* MTLSamplerDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DCD2100B197002781DD /* MTLSamplerDescriptor+MoltenVK.m */; };
@ -523,6 +526,7 @@
A9C96DCF1DDC20C20053187F /* MVKMTLBufferAllocation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKMTLBufferAllocation.mm; sourceTree = "<group>"; };
A9CBEE011B6299D800E45FDC /* libMoltenVK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMoltenVK.a; sourceTree = BUILT_PRODUCTS_DIR; };
A9CEAAD1227378D400FAF779 /* mvk_datatypes.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = mvk_datatypes.hpp; sourceTree = "<group>"; };
A9D7104E25CDE05E00E38106 /* MVKBitArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKBitArray.h; sourceTree = "<group>"; };
A9DE1083200598C500F18F80 /* icd */ = {isa = PBXFileReference; lastKnownFileType = folder; path = icd; sourceTree = "<group>"; };
A9E4B7881E1D8AF10046A4CE /* MVKMTLResourceBindings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKMTLResourceBindings.h; sourceTree = "<group>"; };
A9E53DCD2100B197002781DD /* MTLSamplerDescriptor+MoltenVK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MTLSamplerDescriptor+MoltenVK.m"; sourceTree = "<group>"; };
@ -678,6 +682,7 @@
children = (
A98149421FB6A3F7005F00B4 /* MVKBaseObject.h */,
A98149411FB6A3F7005F00B4 /* MVKBaseObject.mm */,
A9D7104E25CDE05E00E38106 /* MVKBitArray.h */,
4553AEFA2251617100E8EBCD /* MVKBlockObserver.h */,
4553AEF62251617100E8EBCD /* MVKBlockObserver.m */,
45557A4D21C9EFF3008868BD /* MVKCodec.cpp */,
@ -792,6 +797,7 @@
2FEA0A4624902F9F00EEF3AD /* MVKSurface.h in Headers */,
2FEA0A4724902F9F00EEF3AD /* MTLRenderPipelineDescriptor+MoltenVK.h in Headers */,
2FEA0A4824902F9F00EEF3AD /* MVKInstance.h in Headers */,
A9D7105025CDE05E00E38106 /* MVKBitArray.h in Headers */,
2FEA0A4924902F9F00EEF3AD /* MVKCommandResourceFactory.h in Headers */,
2FEA0A4A24902F9F00EEF3AD /* MVKQueryPool.h in Headers */,
2FEA0A4B24902F9F00EEF3AD /* MVKCommandEncoderState.h in Headers */,
@ -868,6 +874,7 @@
A95B7D691D3EE486003183D3 /* MVKCommandEncoderState.h in Headers */,
A94FB7D81C7DFB4800632CA3 /* MVKCommandPipelineStateFactoryShaderSource.h in Headers */,
A94FB7E01C7DFB4800632CA3 /* MVKDescriptorSet.h in Headers */,
A9D7104F25CDE05E00E38106 /* MVKBitArray.h in Headers */,
A9E53DE12100B197002781DD /* NSString+MoltenVK.h in Headers */,
A9E53DDF2100B197002781DD /* CAMetalLayer+MoltenVK.h in Headers */,
45557A5421C9EFF3008868BD /* MVKCodec.h in Headers */,
@ -940,6 +947,7 @@
A95B7D6A1D3EE486003183D3 /* MVKCommandEncoderState.h in Headers */,
A94FB7D91C7DFB4800632CA3 /* MVKCommandPipelineStateFactoryShaderSource.h in Headers */,
A94FB7E11C7DFB4800632CA3 /* MVKDescriptorSet.h in Headers */,
A9D7105125CDE05E00E38106 /* MVKBitArray.h in Headers */,
A9E53DE22100B197002781DD /* NSString+MoltenVK.h in Headers */,
A9E53DE02100B197002781DD /* CAMetalLayer+MoltenVK.h in Headers */,
45557A5521C9EFF3008868BD /* MVKCodec.h in Headers */,

View File

@ -20,6 +20,7 @@
#include "MVKDescriptor.h"
#include "MVKSmallVector.h"
#include "MVKBitArray.h"
#include <unordered_set>
#include <unordered_map>
#include <vector>
@ -155,59 +156,20 @@ class MVKDescriptorTypePreallocation : public MVKBaseObject {
public:
/** Returns the Vulkan API opaque object controlling this object. */
MVKVulkanAPIObject* getVulkanAPIObject() override { return nullptr; };
MVKDescriptorTypePreallocation(const VkDescriptorPoolCreateInfo* pCreateInfo,
VkDescriptorType descriptorType);
protected:
friend class MVKPreallocatedDescriptors;
VkResult allocateDescriptor(MVKDescriptor** pMVKDesc);
bool findDescriptor(uint32_t endIndex, MVKDescriptor** pMVKDesc);
void freeDescriptor(MVKDescriptor* mvkDesc);
void reset();
MVKSmallVector<DescriptorClass> _descriptors;
MVKSmallVector<bool> _availability;
uint32_t _nextAvailableIndex;
bool _supportAvailability;
};
#pragma mark -
#pragma mark MVKPreallocatedDescriptors
/** Support class for MVKDescriptorPool that holds preallocated instances of all concrete descriptor classes. */
class MVKPreallocatedDescriptors : public MVKBaseObject {
public:
/** Returns the Vulkan API opaque object controlling this object. */
MVKVulkanAPIObject* getVulkanAPIObject() override { return nullptr; };
MVKPreallocatedDescriptors(const VkDescriptorPoolCreateInfo* pCreateInfo);
MVKDescriptorTypePreallocation(size_t poolSize);
protected:
friend class MVKDescriptorPool;
VkResult allocateDescriptor(VkDescriptorType descriptorType, MVKDescriptor** pMVKDesc);
inline bool isPreallocated() { return _availability.size() > 0; }
VkResult allocateDescriptor(MVKDescriptor** pMVKDesc);
void freeDescriptor(MVKDescriptor* mvkDesc);
void reset();
MVKDescriptorTypePreallocation<MVKUniformBufferDescriptor> _uniformBufferDescriptors;
MVKDescriptorTypePreallocation<MVKStorageBufferDescriptor> _storageBufferDescriptors;
MVKDescriptorTypePreallocation<MVKUniformBufferDynamicDescriptor> _uniformBufferDynamicDescriptors;
MVKDescriptorTypePreallocation<MVKStorageBufferDynamicDescriptor> _storageBufferDynamicDescriptors;
MVKDescriptorTypePreallocation<MVKInlineUniformBlockDescriptor> _inlineUniformBlockDescriptors;
MVKDescriptorTypePreallocation<MVKSampledImageDescriptor> _sampledImageDescriptors;
MVKDescriptorTypePreallocation<MVKStorageImageDescriptor> _storageImageDescriptors;
MVKDescriptorTypePreallocation<MVKInputAttachmentDescriptor> _inputAttachmentDescriptors;
MVKDescriptorTypePreallocation<MVKSamplerDescriptor> _samplerDescriptors;
MVKDescriptorTypePreallocation<MVKCombinedImageSamplerDescriptor> _combinedImageSamplerDescriptors;
MVKDescriptorTypePreallocation<MVKUniformTexelBufferDescriptor> _uniformTexelBufferDescriptors;
MVKDescriptorTypePreallocation<MVKStorageTexelBufferDescriptor> _storageTexelBufferDescriptors;
MVKSmallVector<DescriptorClass> _descriptors;
MVKBitArray _availability;
};
@ -251,7 +213,19 @@ protected:
uint32_t _maxSets;
std::unordered_set<MVKDescriptorSet*> _allocatedSets;
MVKPreallocatedDescriptors* _preallocatedDescriptors;
MVKDescriptorTypePreallocation<MVKUniformBufferDescriptor> _uniformBufferDescriptors;
MVKDescriptorTypePreallocation<MVKStorageBufferDescriptor> _storageBufferDescriptors;
MVKDescriptorTypePreallocation<MVKUniformBufferDynamicDescriptor> _uniformBufferDynamicDescriptors;
MVKDescriptorTypePreallocation<MVKStorageBufferDynamicDescriptor> _storageBufferDynamicDescriptors;
MVKDescriptorTypePreallocation<MVKInlineUniformBlockDescriptor> _inlineUniformBlockDescriptors;
MVKDescriptorTypePreallocation<MVKSampledImageDescriptor> _sampledImageDescriptors;
MVKDescriptorTypePreallocation<MVKStorageImageDescriptor> _storageImageDescriptors;
MVKDescriptorTypePreallocation<MVKInputAttachmentDescriptor> _inputAttachmentDescriptors;
MVKDescriptorTypePreallocation<MVKSamplerDescriptor> _samplerDescriptors;
MVKDescriptorTypePreallocation<MVKCombinedImageSamplerDescriptor> _combinedImageSamplerDescriptors;
MVKDescriptorTypePreallocation<MVKUniformTexelBufferDescriptor> _uniformTexelBufferDescriptors;
MVKDescriptorTypePreallocation<MVKStorageTexelBufferDescriptor> _storageTexelBufferDescriptors;
};

View File

@ -312,217 +312,47 @@ MVKDescriptorSet::~MVKDescriptorSet() {
#pragma mark -
#pragma mark MVKDescriptorTypePreallocation
// If preallocated, find the next availalble descriptor.
// If not preallocated, create one on the fly.
template<class DescriptorClass>
VkResult MVKDescriptorTypePreallocation<DescriptorClass>::allocateDescriptor(MVKDescriptor** pMVKDesc) {
uint32_t descCnt = (uint32_t)_descriptors.size();
// Preallocated descriptors that CANNOT be freed.
// Next available index can only monotonically increase towards the limit.
if ( !_supportAvailability ) {
if (_nextAvailableIndex < descCnt) {
*pMVKDesc = &_descriptors[_nextAvailableIndex++];
return VK_SUCCESS;
} else {
return VK_ERROR_OUT_OF_POOL_MEMORY;
}
DescriptorClass* mvkDesc;
if (isPreallocated()) {
size_t availDescIdx = _availability.getIndexOfFirstSetBit(true);
if (availDescIdx >= _availability.size()) { return VK_ERROR_OUT_OF_POOL_MEMORY; }
mvkDesc = &_descriptors[availDescIdx];
mvkDesc->reset(); // Clear before reusing.
} else {
mvkDesc = new DescriptorClass();
}
// Descriptors that CAN be freed.
// An available index might exist anywhere in the pool of descriptors.
uint32_t origNextAvailPoolIdx = _nextAvailableIndex;
// First start looking from most recently found available slot
if (findDescriptor(descCnt, pMVKDesc)) { return VK_SUCCESS; }
// Then look from beginning of the collection, in case any previous descriptors were freed
_nextAvailableIndex = 0;
if (findDescriptor(origNextAvailPoolIdx, pMVKDesc)) { return VK_SUCCESS; }
return VK_ERROR_OUT_OF_POOL_MEMORY;
*pMVKDesc = mvkDesc;
return VK_SUCCESS;
}
// Find a descriptor within a range in a preallocated collection based on availability,
// and return true if found, false if not
template<typename DescriptorClass>
bool MVKDescriptorTypePreallocation<DescriptorClass>::findDescriptor(uint32_t endIndex,
MVKDescriptor** pMVKDesc) {
while (_nextAvailableIndex < endIndex) {
if (_availability[_nextAvailableIndex]) {
_availability[_nextAvailableIndex] = false;
*pMVKDesc = &_descriptors[_nextAvailableIndex];
_nextAvailableIndex++;
return true;
}
_nextAvailableIndex++;
}
return false;
}
// Reset a descriptor and mark it available, if applicable
// If preallocated, descriptors are held in contiguous memory, so the index of the returning
// descriptor can be calculated by pointer differences, and it can be marked as available.
// The descriptor will be reset when it is re-allocated. This streamlines the reset() of this pool.
// If not preallocated, simply destroy returning descriptor.
template<typename DescriptorClass>
void MVKDescriptorTypePreallocation<DescriptorClass>::freeDescriptor(MVKDescriptor* mvkDesc) {
mvkDesc->reset();
if (_supportAvailability) {
bool found = false;
size_t descCnt = _descriptors.size();
for (uint32_t descIdx = 0; !found && descIdx < descCnt; descIdx++) {
if (&_descriptors[descIdx] == mvkDesc) {
found = true;
_availability[descIdx] = true;
}
}
if (isPreallocated()) {
size_t descIdx = (DescriptorClass*)mvkDesc - _descriptors.data();
_availability.setBit(descIdx);
} else {
mvkDesc->destroy();
}
}
// Preallocated descriptors will be reset when they are reused
template<typename DescriptorClass>
void MVKDescriptorTypePreallocation<DescriptorClass>::reset() {
_nextAvailableIndex = 0;
_availability.setAllBits();
}
template<typename DescriptorClass>
MVKDescriptorTypePreallocation<DescriptorClass>::MVKDescriptorTypePreallocation(const VkDescriptorPoolCreateInfo* pCreateInfo,
VkDescriptorType descriptorType) {
// There may be more than one poolSizeCount instance for the desired VkDescriptorType.
// Accumulate the descriptor count for the desired VkDescriptorType, and size the collections accordingly.
uint32_t descriptorCount = 0;
uint32_t poolCnt = pCreateInfo->poolSizeCount;
for (uint32_t poolIdx = 0; poolIdx < poolCnt; poolIdx++) {
auto& poolSize = pCreateInfo->pPoolSizes[poolIdx];
if (poolSize.type == descriptorType) { descriptorCount += poolSize.descriptorCount; }
}
_descriptors.resize(descriptorCount);
// Determine whether we need to track the availability of previously freed descriptors.
_supportAvailability = mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT);
if (_supportAvailability) { _availability.resize(descriptorCount, true); }
_nextAvailableIndex = 0;
}
#pragma mark -
#pragma mark MVKPreallocatedDescriptors
// Allocate a descriptor of the specified type
VkResult MVKPreallocatedDescriptors::allocateDescriptor(VkDescriptorType descriptorType,
MVKDescriptor** pMVKDesc) {
switch (descriptorType) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
return _uniformBufferDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
return _storageBufferDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
return _uniformBufferDynamicDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
return _storageBufferDynamicDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
return _inlineUniformBlockDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
return _sampledImageDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
return _storageImageDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
return _inputAttachmentDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_SAMPLER:
return _samplerDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
return _combinedImageSamplerDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
return _uniformTexelBufferDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
return _storageTexelBufferDescriptors.allocateDescriptor(pMVKDesc);
default:
return reportError(VK_ERROR_INITIALIZATION_FAILED, "Unrecognized VkDescriptorType %d.", descriptorType);
}
}
void MVKPreallocatedDescriptors::freeDescriptor(MVKDescriptor* mvkDesc) {
VkDescriptorType descriptorType = mvkDesc->getDescriptorType();
switch (descriptorType) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
return _uniformBufferDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
return _storageBufferDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
return _uniformBufferDynamicDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
return _storageBufferDynamicDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
return _inlineUniformBlockDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
return _sampledImageDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
return _storageImageDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
return _inputAttachmentDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_SAMPLER:
return _samplerDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
return _combinedImageSamplerDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
return _uniformTexelBufferDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
return _storageTexelBufferDescriptors.freeDescriptor(mvkDesc);
default:
reportError(VK_ERROR_INITIALIZATION_FAILED, "Unrecognized VkDescriptorType %d.", descriptorType);
}
}
void MVKPreallocatedDescriptors::reset() {
_uniformBufferDescriptors.reset();
_storageBufferDescriptors.reset();
_uniformBufferDynamicDescriptors.reset();
_storageBufferDynamicDescriptors.reset();
_inlineUniformBlockDescriptors.reset();
_sampledImageDescriptors.reset();
_storageImageDescriptors.reset();
_inputAttachmentDescriptors.reset();
_samplerDescriptors.reset();
_combinedImageSamplerDescriptors.reset();
_uniformTexelBufferDescriptors.reset();
_storageTexelBufferDescriptors.reset();
}
MVKPreallocatedDescriptors::MVKPreallocatedDescriptors(const VkDescriptorPoolCreateInfo* pCreateInfo) :
_uniformBufferDescriptors(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER),
_storageBufferDescriptors(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER),
_uniformBufferDynamicDescriptors(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC),
_storageBufferDynamicDescriptors(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC),
_inlineUniformBlockDescriptors(pCreateInfo, VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT),
_sampledImageDescriptors(pCreateInfo, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE),
_storageImageDescriptors(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE),
_inputAttachmentDescriptors(pCreateInfo, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT),
_samplerDescriptors(pCreateInfo, VK_DESCRIPTOR_TYPE_SAMPLER),
_combinedImageSamplerDescriptors(pCreateInfo, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER),
_uniformTexelBufferDescriptors(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER),
_storageTexelBufferDescriptors(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) {
}
MVKDescriptorTypePreallocation<DescriptorClass>::MVKDescriptorTypePreallocation(size_t poolSize) :
_descriptors(poolSize),
_availability(poolSize, true) {}
#pragma mark -
@ -578,11 +408,24 @@ VkResult MVKDescriptorPool::freeDescriptorSets(uint32_t count, const VkDescripto
return VK_SUCCESS;
}
// Destroy all allocated descriptor sets
// Destroy all allocated descriptor sets and reset descriptor pools
VkResult MVKDescriptorPool::reset(VkDescriptorPoolResetFlags flags) {
for (auto& mvkDS : _allocatedSets) { freeDescriptorSet(mvkDS); }
_allocatedSets.clear();
if (_preallocatedDescriptors) { _preallocatedDescriptors->reset(); }
_uniformBufferDescriptors.reset();
_storageBufferDescriptors.reset();
_uniformBufferDynamicDescriptors.reset();
_storageBufferDynamicDescriptors.reset();
_inlineUniformBlockDescriptors.reset();
_sampledImageDescriptors.reset();
_storageImageDescriptors.reset();
_inputAttachmentDescriptors.reset();
_samplerDescriptors.reset();
_combinedImageSamplerDescriptors.reset();
_uniformTexelBufferDescriptors.reset();
_storageTexelBufferDescriptors.reset();
return VK_SUCCESS;
}
@ -606,87 +449,126 @@ void MVKDescriptorPool::freeDescriptorSet(MVKDescriptorSet* mvkDS) { mvkDS->dest
// Allocate a descriptor of the specified type
VkResult MVKDescriptorPool::allocateDescriptor(VkDescriptorType descriptorType,
MVKDescriptor** pMVKDesc) {
// If descriptors are preallocated allocate from the preallocated pools
if (_preallocatedDescriptors) {
return _preallocatedDescriptors->allocateDescriptor(descriptorType, pMVKDesc);
}
// Otherwise instantiate one of the appropriate type now
switch (descriptorType) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
*pMVKDesc = new MVKUniformBufferDescriptor();
break;
return _uniformBufferDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
*pMVKDesc = new MVKStorageBufferDescriptor();
break;
return _storageBufferDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
*pMVKDesc = new MVKUniformBufferDynamicDescriptor();
break;
return _uniformBufferDynamicDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
*pMVKDesc = new MVKStorageBufferDynamicDescriptor();
break;
return _storageBufferDynamicDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
*pMVKDesc = new MVKInlineUniformBlockDescriptor();
break;
return _inlineUniformBlockDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
*pMVKDesc = new MVKSampledImageDescriptor();
break;
return _sampledImageDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
*pMVKDesc = new MVKStorageImageDescriptor();
break;
return _storageImageDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
*pMVKDesc = new MVKInputAttachmentDescriptor();
break;
return _inputAttachmentDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_SAMPLER:
*pMVKDesc = new MVKSamplerDescriptor();
break;
return _samplerDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
*pMVKDesc = new MVKCombinedImageSamplerDescriptor();
break;
return _combinedImageSamplerDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
*pMVKDesc = new MVKUniformTexelBufferDescriptor();
break;
return _uniformTexelBufferDescriptors.allocateDescriptor(pMVKDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
*pMVKDesc = new MVKStorageTexelBufferDescriptor();
break;
return _storageTexelBufferDescriptors.allocateDescriptor(pMVKDesc);
default:
return reportError(VK_ERROR_INITIALIZATION_FAILED, "Unrecognized VkDescriptorType %d.", descriptorType);
}
return VK_SUCCESS;
}
// Free a descriptor, either through the preallocated pool, or directly destroy it
void MVKDescriptorPool::freeDescriptor(MVKDescriptor* mvkDesc) {
if (_preallocatedDescriptors) {
_preallocatedDescriptors->freeDescriptor(mvkDesc);
} else {
mvkDesc->destroy();
VkDescriptorType descriptorType = mvkDesc->getDescriptorType();
switch (descriptorType) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
return _uniformBufferDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
return _storageBufferDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
return _uniformBufferDynamicDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
return _storageBufferDynamicDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
return _inlineUniformBlockDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
return _sampledImageDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
return _storageImageDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
return _inputAttachmentDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_SAMPLER:
return _samplerDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
return _combinedImageSamplerDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
return _uniformTexelBufferDescriptors.freeDescriptor(mvkDesc);
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
return _storageTexelBufferDescriptors.freeDescriptor(mvkDesc);
default:
reportError(VK_ERROR_INITIALIZATION_FAILED, "Unrecognized VkDescriptorType %d.", descriptorType);
}
}
MVKDescriptorPool::MVKDescriptorPool(MVKDevice* device,
const VkDescriptorPoolCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
_maxSets = pCreateInfo->maxSets;
_preallocatedDescriptors = mvkGetMVKConfiguration()->preallocateDescriptors ? new MVKPreallocatedDescriptors(pCreateInfo) : nullptr;
// Return the size of the preallocated pool for descriptors of the specified type,
// or zero if we are not preallocating descriptors in the pool.
// There may be more than one poolSizeCount instance for the desired VkDescriptorType.
// Accumulate the descriptor count for the desired VkDescriptorType accordingly.
static size_t getPoolSize(const VkDescriptorPoolCreateInfo* pCreateInfo, VkDescriptorType descriptorType) {
uint32_t descCnt = 0;
if (mvkGetMVKConfiguration()->preallocateDescriptors) {
uint32_t poolCnt = pCreateInfo->poolSizeCount;
for (uint32_t poolIdx = 0; poolIdx < poolCnt; poolIdx++) {
auto& poolSize = pCreateInfo->pPoolSizes[poolIdx];
if (poolSize.type == descriptorType) { descCnt += poolSize.descriptorCount; }
}
}
return descCnt;
}
// Destroy all allocated descriptor sets and preallocated descriptors
MVKDescriptorPool::MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo) :
MVKVulkanAPIDeviceObject(device),
_uniformBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)),
_storageBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)),
_uniformBufferDynamicDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC)),
_storageBufferDynamicDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)),
_inlineUniformBlockDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT)),
_sampledImageDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)),
_storageImageDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)),
_inputAttachmentDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)),
_samplerDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_SAMPLER)),
_combinedImageSamplerDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)),
_uniformTexelBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER)),
_storageTexelBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)),
_maxSets(pCreateInfo->maxSets) {}
MVKDescriptorPool::~MVKDescriptorPool() {
reset(0);
if (_preallocatedDescriptors) { _preallocatedDescriptors->destroy(); }
}

View File

@ -0,0 +1,181 @@
/*
* MVKBitArray.h
*
* Copyright (c) 2020-2020 The Brenwill Workshop Ltd. (http://www.brenwill.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "MVKFoundation.h"
#pragma mark -
#pragma mark MVKBitArray
/** Represents an array of bits, optimized for reduced storage and fast scanning for bits that are set. */
class MVKBitArray {
static constexpr size_t SectionMaskSize = 6; // 64 bits
static constexpr size_t SectionBitCount = 1U << SectionMaskSize;
static constexpr size_t SectionByteCount = SectionBitCount / 8;
static constexpr uint64_t SectionMask = SectionBitCount - 1;
public:
/** Returns the value of the bit. */
inline bool getBit(size_t bitIndex) {
return mvkIsAnyFlagEnabled(_pSections[getIndexOfSection(bitIndex)], getSectionSetMask(bitIndex));
}
/** Sets the value of the bit to 1. */
inline void setBit(size_t bitIndex) {
size_t secIdx = getIndexOfSection(bitIndex);
mvkEnableFlags(_pSections[secIdx], getSectionSetMask(bitIndex));
if (secIdx < _minUnclearedSectionIndex) { _minUnclearedSectionIndex = secIdx; }
}
/** Sets the value of the bit to 0. */
inline void clearBit(size_t bitIndex) {
size_t secIdx = getIndexOfSection(bitIndex);
mvkDisableFlags(_pSections[secIdx], getSectionSetMask(bitIndex));
if (secIdx == _minUnclearedSectionIndex && !_pSections[secIdx]) { _minUnclearedSectionIndex++; }
}
/** Sets the value of the bit to the value. */
inline void setBit(size_t bitIndex, bool val) {
if (val) {
setBit(bitIndex);
} else {
clearBit(bitIndex);
}
}
/** Sets all bits in the array to 1. */
inline void setAllBits() { setAllSections(~0); }
/** Clears all bits in the array to 0. */
inline void clearAllBits() { setAllSections(0); }
/**
* Returns the index of the first bit that is set, at or after the specified index,
* and optionally clears that bit. If no bits are set, returns the size() of this bit array.
*/
size_t getIndexOfFirstSetBit(size_t startIndex, bool shouldClear) {
size_t startSecIdx = std::max(getIndexOfSection(startIndex), _minUnclearedSectionIndex);
size_t bitIdx = startSecIdx << SectionMaskSize;
size_t secCnt = getSectionCount();
for (size_t secIdx = startSecIdx; secIdx < secCnt; secIdx++) {
size_t lclBitIdx = getIndexOfFirstSetBitInSection(_pSections[secIdx], getBitIndexInSection(startIndex));
bitIdx += lclBitIdx;
if (lclBitIdx < SectionBitCount) {
if (startSecIdx == _minUnclearedSectionIndex && !_pSections[startSecIdx]) { _minUnclearedSectionIndex = secIdx; }
if (shouldClear) { clearBit(bitIdx); }
return bitIdx;
}
}
return std::min(bitIdx, _bitCount);
}
/**
* Returns the index of the first bit that is set, at or after the specified index.
* If no bits are set, returns the size() of this bit array.
*/
inline size_t getIndexOfFirstSetBit(size_t startIndex) {
return getIndexOfFirstSetBit(startIndex, false);
}
/**
* Returns the index of the first bit that is set and optionally clears that bit.
* If no bits are set, returns the size() of this bit array.
*/
inline size_t getIndexOfFirstSetBit(bool shouldClear) {
return getIndexOfFirstSetBit(0, shouldClear);
}
/**
* Returns the index of the first bit that is set.
* If no bits are set, returns the size() of this bit array.
*/
inline size_t getIndexOfFirstSetBit() {
return getIndexOfFirstSetBit(0, false);
}
/** Returns the number of bits in this array. */
inline size_t size() { return _bitCount; }
/** Returns whether this array is empty. */
inline bool empty() { return !_bitCount; }
/** Constructs an instance for the specified number of bits, and sets the initial value of all the bits. */
MVKBitArray(size_t size, bool val = false) {
_bitCount = size;
_pSections = _bitCount ? (uint64_t*)malloc(getSectionCount() * SectionByteCount) : nullptr;
if (val) {
setAllBits();
} else {
clearAllBits();
}
}
~MVKBitArray() { free(_pSections); }
protected:
// Returns the number of sections.
inline size_t getSectionCount() {
return _bitCount ? getIndexOfSection(_bitCount - 1) + 1 : 0;
}
// Returns the index of the section that contains the specified bit.
static inline size_t getIndexOfSection(size_t bitIndex) {
return bitIndex >> SectionMaskSize;
}
// Converts the bit index to a local bit index within a section, and returns that local bit index.
static inline size_t getBitIndexInSection(size_t bitIndex) {
return bitIndex & SectionMask;
}
// Returns a section mask containing a single 1 value in the bit in the section that
// corresponds to the specified global bit index, and 0 values in all other bits.
static inline uint64_t getSectionSetMask(size_t bitIndex) {
return (uint64_t)1U << ((SectionBitCount - 1) - getBitIndexInSection(bitIndex));
}
// Returns the local index of the first set bit in the section, starting from the highest order bit.
// Clears all bits ahead of the start bit so they will be ignored, then counts the number of zeros
// ahead of the set bit. If there are no set bits, returns the number of bits in a section.
static size_t getIndexOfFirstSetBitInSection(uint64_t section, size_t lclStartBitIndex) {
uint64_t lclStartMask = ~(uint64_t)0;
lclStartMask >>= lclStartBitIndex;
section &= lclStartMask;
return section ? __builtin_clzll(section) : SectionBitCount;
}
// Sets the content of all sections to the value
void setAllSections(uint64_t sectionValue) {
size_t secCnt = getSectionCount();
for (size_t secIdx = 0; secIdx < secCnt; secIdx++) {
_pSections[secIdx] = sectionValue;
}
_minUnclearedSectionIndex = sectionValue ? 0 : secCnt;
}
uint64_t* _pSections;
size_t _bitCount;
size_t _minUnclearedSectionIndex; // Tracks where to start looking for bits that are set
};