Refactor preallocated descriptor handling.
Add MVKBitArray class.
Consolidate MVKPreallocatedDescriptors into MVKDescriptorPool
and remove MVKPreallocatedDescriptors.
diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
index 6f2da81..7c72906 100644
--- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
+++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
@@ -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 */,
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index ae6048e..82287ef 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -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 @@
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 @@
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;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index b7a5f96..5630f4e 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -312,217 +312,47 @@
#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 @@
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 @@
// 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(); }
}
diff --git a/MoltenVK/MoltenVK/Utility/MVKBitArray.h b/MoltenVK/MoltenVK/Utility/MVKBitArray.h
new file mode 100755
index 0000000..b6e1ecb
--- /dev/null
+++ b/MoltenVK/MoltenVK/Utility/MVKBitArray.h
@@ -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
+};