Support preallocated descriptor pooling via VkDescriptorPoolSize.

Add MVK_CONFIG_PREALLOCATE_DESCRIPTORS env var to enable descriptor preallocation
in pool. Add MVKDescriptor subclasses for all used VkDescriptorType values.
Support allocating MVKDescriptor subclasses via direct instantiation,
or referencing preallocated instances held in a fixed collection.
MVKDescriptor subclasses support resetting and reuse from preallocated collection.
MVKDescriptorPool optionally holds collections of preallocated descriptors,
one collection per VkDescriptorType value.
Support VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT to mark preallocated
descriptors as available when freed.
This commit is contained in:
Bill Hollings 2020-01-21 09:18:18 -05:00
parent e53e582639
commit 6abf4a6e2f
4 changed files with 489 additions and 45 deletions

View File

@ -140,6 +140,8 @@ public:
/** Returns the Vulkan API opaque object controlling this object. */ /** Returns the Vulkan API opaque object controlling this object. */
MVKVulkanAPIObject* getVulkanAPIObject() override { return nullptr; }; MVKVulkanAPIObject* getVulkanAPIObject() override { return nullptr; };
virtual VkDescriptorType getDescriptorType() = 0;
/** Encodes this descriptor (based on its layout binding index) on the the command encoder. */ /** Encodes this descriptor (based on its layout binding index) on the the command encoder. */
virtual void bind(MVKCommandEncoder* cmdEncoder, virtual void bind(MVKCommandEncoder* cmdEncoder,
VkDescriptorType descriptorType, VkDescriptorType descriptorType,
@ -180,6 +182,11 @@ public:
/** Sets the binding layout. */ /** Sets the binding layout. */
virtual void setLayout(MVKDescriptorSetLayoutBinding* dslBinding, uint32_t index) {} virtual void setLayout(MVKDescriptorSetLayoutBinding* dslBinding, uint32_t index) {}
/** Resets any internal content. */
virtual void reset() {}
~MVKDescriptor() { reset(); }
}; };
@ -212,7 +219,9 @@ public:
VkBufferView* pTexelBufferView, VkBufferView* pTexelBufferView,
VkWriteDescriptorSetInlineUniformBlockEXT* inlineUniformBlock) override; VkWriteDescriptorSetInlineUniformBlockEXT* inlineUniformBlock) override;
~MVKBufferDescriptor(); void reset() override;
~MVKBufferDescriptor() { reset(); }
protected: protected:
MVKBuffer* _mvkBuffer = nullptr; MVKBuffer* _mvkBuffer = nullptr;
@ -222,12 +231,50 @@ protected:
#pragma mark - #pragma mark -
#pragma mark MVKInlineUniformDescriptor #pragma mark MVKUniformBufferDescriptor
class MVKUniformBufferDescriptor : public MVKBufferDescriptor {
public:
VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; }
};
#pragma mark -
#pragma mark MVKUniformBufferDynamicDescriptor
class MVKUniformBufferDynamicDescriptor : public MVKBufferDescriptor {
public:
VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; }
};
#pragma mark -
#pragma mark MVKStorageBufferDescriptor
class MVKStorageBufferDescriptor : public MVKBufferDescriptor {
public:
VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; }
};
#pragma mark -
#pragma mark MVKStorageBufferDynamicDescriptor
class MVKStorageBufferDynamicDescriptor : public MVKBufferDescriptor {
public:
VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; }
};
#pragma mark -
#pragma mark MVKInlineUniformBlockDescriptor
/** Represents a Vulkan descriptor tracking an inline block of uniform data. */ /** Represents a Vulkan descriptor tracking an inline block of uniform data. */
class MVKInlineUniformDescriptor : public MVKDescriptor { class MVKInlineUniformBlockDescriptor : public MVKDescriptor {
public: public:
VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT; }
void bind(MVKCommandEncoder* cmdEncoder, void bind(MVKCommandEncoder* cmdEncoder,
VkDescriptorType descriptorType, VkDescriptorType descriptorType,
uint32_t descriptorIndex, uint32_t descriptorIndex,
@ -250,11 +297,13 @@ public:
VkBufferView* pTexelBufferView, VkBufferView* pTexelBufferView,
VkWriteDescriptorSetInlineUniformBlockEXT* inlineUniformBlock) override; VkWriteDescriptorSetInlineUniformBlockEXT* inlineUniformBlock) override;
~MVKInlineUniformDescriptor(); void reset() override;
~MVKInlineUniformBlockDescriptor() { reset(); }
protected: protected:
id<MTLBuffer> _mtlBuffer = nil; id<MTLBuffer> _mtlBuffer = nil;
uint32_t _dataSize; uint32_t _dataSize = 0;
}; };
@ -287,7 +336,9 @@ public:
VkBufferView* pTexelBufferView, VkBufferView* pTexelBufferView,
VkWriteDescriptorSetInlineUniformBlockEXT* inlineUniformBlock) override; VkWriteDescriptorSetInlineUniformBlockEXT* inlineUniformBlock) override;
~MVKImageDescriptor(); void reset() override;
~MVKImageDescriptor() { reset(); }
protected: protected:
MVKImageView* _mvkImageView = nullptr; MVKImageView* _mvkImageView = nullptr;
@ -295,6 +346,33 @@ protected:
}; };
#pragma mark -
#pragma mark MVKSampledImageDescriptor
class MVKSampledImageDescriptor : public MVKImageDescriptor {
public:
VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; }
};
#pragma mark -
#pragma mark MVKStorageImageDescriptor
class MVKStorageImageDescriptor : public MVKImageDescriptor {
public:
VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; }
};
#pragma mark -
#pragma mark MVKInputAttachmentDescriptor
class MVKInputAttachmentDescriptor : public MVKImageDescriptor {
public:
VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; }
};
#pragma mark - #pragma mark -
#pragma mark MVKSamplerDescriptorMixin #pragma mark MVKSamplerDescriptorMixin
@ -332,7 +410,9 @@ protected:
void setLayout(MVKDescriptorSetLayoutBinding* dslBinding, uint32_t index); void setLayout(MVKDescriptorSetLayoutBinding* dslBinding, uint32_t index);
virtual ~MVKSamplerDescriptorMixin(); void reset();
~MVKSamplerDescriptorMixin() { reset(); }
MVKSampler* _mvkSampler = nullptr; MVKSampler* _mvkSampler = nullptr;
bool _hasDynamicSampler = true; bool _hasDynamicSampler = true;
@ -346,6 +426,8 @@ protected:
class MVKSamplerDescriptor : public MVKDescriptor, public MVKSamplerDescriptorMixin { class MVKSamplerDescriptor : public MVKDescriptor, public MVKSamplerDescriptorMixin {
public: public:
VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_SAMPLER; }
void bind(MVKCommandEncoder* cmdEncoder, void bind(MVKCommandEncoder* cmdEncoder,
VkDescriptorType descriptorType, VkDescriptorType descriptorType,
uint32_t descriptorIndex, uint32_t descriptorIndex,
@ -370,6 +452,10 @@ public:
void setLayout(MVKDescriptorSetLayoutBinding* dslBinding, uint32_t index) override; void setLayout(MVKDescriptorSetLayoutBinding* dslBinding, uint32_t index) override;
void reset() override;
~MVKSamplerDescriptor() { reset(); }
}; };
@ -380,6 +466,8 @@ public:
class MVKCombinedImageSamplerDescriptor : public MVKImageDescriptor, public MVKSamplerDescriptorMixin { class MVKCombinedImageSamplerDescriptor : public MVKImageDescriptor, public MVKSamplerDescriptorMixin {
public: public:
VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; }
void bind(MVKCommandEncoder* cmdEncoder, void bind(MVKCommandEncoder* cmdEncoder,
VkDescriptorType descriptorType, VkDescriptorType descriptorType,
uint32_t descriptorIndex, uint32_t descriptorIndex,
@ -404,6 +492,10 @@ public:
void setLayout(MVKDescriptorSetLayoutBinding* dslBinding, uint32_t index) override; void setLayout(MVKDescriptorSetLayoutBinding* dslBinding, uint32_t index) override;
void reset() override;
~MVKCombinedImageSamplerDescriptor() { reset(); }
}; };
@ -436,8 +528,28 @@ public:
VkBufferView* pTexelBufferView, VkBufferView* pTexelBufferView,
VkWriteDescriptorSetInlineUniformBlockEXT* inlineUniformBlock) override; VkWriteDescriptorSetInlineUniformBlockEXT* inlineUniformBlock) override;
~MVKTexelBufferDescriptor(); void reset() override;
~MVKTexelBufferDescriptor() { reset(); }
protected: protected:
MVKBufferView* _mvkBufferView = nullptr; MVKBufferView* _mvkBufferView = nullptr;
}; };
#pragma mark -
#pragma mark MVKUniformTexelBufferDescriptor
class MVKUniformTexelBufferDescriptor : public MVKTexelBufferDescriptor {
public:
VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; }
};
#pragma mark -
#pragma mark MVKStorageTexelBufferDescriptor
class MVKStorageTexelBufferDescriptor : public MVKTexelBufferDescriptor {
public:
VkDescriptorType getDescriptorType() override { return VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; }
};

View File

@ -20,9 +20,6 @@
#include "MVKDescriptorSet.h" #include "MVKDescriptorSet.h"
#include "MVKBuffer.h" #include "MVKBuffer.h"
using namespace std;
using namespace mvk;
#pragma mark MVKShaderStageResourceBinding #pragma mark MVKShaderStageResourceBinding
@ -45,15 +42,15 @@ MVKShaderStageResourceBinding& MVKShaderStageResourceBinding::operator+= (const
#pragma mark MVKShaderResourceBinding #pragma mark MVKShaderResourceBinding
uint32_t MVKShaderResourceBinding::getMaxBufferIndex() { uint32_t MVKShaderResourceBinding::getMaxBufferIndex() {
return max({stages[kMVKShaderStageVertex].bufferIndex, stages[kMVKShaderStageTessCtl].bufferIndex, stages[kMVKShaderStageTessEval].bufferIndex, stages[kMVKShaderStageFragment].bufferIndex, stages[kMVKShaderStageCompute].bufferIndex}); return std::max({stages[kMVKShaderStageVertex].bufferIndex, stages[kMVKShaderStageTessCtl].bufferIndex, stages[kMVKShaderStageTessEval].bufferIndex, stages[kMVKShaderStageFragment].bufferIndex, stages[kMVKShaderStageCompute].bufferIndex});
} }
uint32_t MVKShaderResourceBinding::getMaxTextureIndex() { uint32_t MVKShaderResourceBinding::getMaxTextureIndex() {
return max({stages[kMVKShaderStageVertex].textureIndex, stages[kMVKShaderStageTessCtl].textureIndex, stages[kMVKShaderStageTessEval].textureIndex, stages[kMVKShaderStageFragment].textureIndex, stages[kMVKShaderStageCompute].textureIndex}); return std::max({stages[kMVKShaderStageVertex].textureIndex, stages[kMVKShaderStageTessCtl].textureIndex, stages[kMVKShaderStageTessEval].textureIndex, stages[kMVKShaderStageFragment].textureIndex, stages[kMVKShaderStageCompute].textureIndex});
} }
uint32_t MVKShaderResourceBinding::getMaxSamplerIndex() { uint32_t MVKShaderResourceBinding::getMaxSamplerIndex() {
return max({stages[kMVKShaderStageVertex].samplerIndex, stages[kMVKShaderStageTessCtl].samplerIndex, stages[kMVKShaderStageTessEval].samplerIndex, stages[kMVKShaderStageFragment].samplerIndex, stages[kMVKShaderStageCompute].samplerIndex}); return std::max({stages[kMVKShaderStageVertex].samplerIndex, stages[kMVKShaderStageTessCtl].samplerIndex, stages[kMVKShaderStageTessEval].samplerIndex, stages[kMVKShaderStageFragment].samplerIndex, stages[kMVKShaderStageCompute].samplerIndex});
} }
MVKShaderResourceBinding MVKShaderResourceBinding::operator+ (const MVKShaderResourceBinding& rhs) { MVKShaderResourceBinding MVKShaderResourceBinding::operator+ (const MVKShaderResourceBinding& rhs) {
@ -303,7 +300,7 @@ bool MVKDescriptorSetLayoutBinding::validate(MVKSampler* mvkSampler) {
return true; return true;
} }
void MVKDescriptorSetLayoutBinding::populateShaderConverterContext(SPIRVToMSLConversionConfiguration& context, void MVKDescriptorSetLayoutBinding::populateShaderConverterContext(mvk::SPIRVToMSLConversionConfiguration& context,
MVKShaderResourceBinding& dslMTLRezIdxOffsets, MVKShaderResourceBinding& dslMTLRezIdxOffsets,
uint32_t dslIndex) { uint32_t dslIndex) {
@ -534,16 +531,20 @@ void MVKBufferDescriptor::read(MVKDescriptorSet* mvkDescSet,
} }
} }
MVKBufferDescriptor::~MVKBufferDescriptor() { void MVKBufferDescriptor::reset() {
if (_mvkBuffer) { _mvkBuffer->release(); } if (_mvkBuffer) { _mvkBuffer->release(); }
_mvkBuffer = nullptr;
_buffOffset = 0;
_buffRange = 0;
MVKDescriptor::reset();
} }
#pragma mark - #pragma mark -
#pragma mark MVKInlineUniformDescriptor #pragma mark MVKInlineUniformBlockDescriptor
// A null cmdEncoder can be passed to perform a validation pass // A null cmdEncoder can be passed to perform a validation pass
void MVKInlineUniformDescriptor::bind(MVKCommandEncoder* cmdEncoder, void MVKInlineUniformBlockDescriptor::bind(MVKCommandEncoder* cmdEncoder,
VkDescriptorType descriptorType, VkDescriptorType descriptorType,
uint32_t descriptorIndex, uint32_t descriptorIndex,
bool stages[], bool stages[],
@ -574,7 +575,7 @@ void MVKInlineUniformDescriptor::bind(MVKCommandEncoder* cmdEncoder,
} }
} }
void MVKInlineUniformDescriptor::write(MVKDescriptorSet* mvkDescSet, void MVKInlineUniformBlockDescriptor::write(MVKDescriptorSet* mvkDescSet,
VkDescriptorType descriptorType, VkDescriptorType descriptorType,
uint32_t srcIndex, uint32_t srcIndex,
size_t stride, size_t stride,
@ -602,7 +603,7 @@ void MVKInlineUniformDescriptor::write(MVKDescriptorSet* mvkDescSet,
} }
} }
void MVKInlineUniformDescriptor::read(MVKDescriptorSet* mvkDescSet, void MVKInlineUniformBlockDescriptor::read(MVKDescriptorSet* mvkDescSet,
VkDescriptorType descriptorType, VkDescriptorType descriptorType,
uint32_t dstIndex, uint32_t dstIndex,
VkDescriptorImageInfo* pImageInfo, VkDescriptorImageInfo* pImageInfo,
@ -628,8 +629,11 @@ void MVKInlineUniformDescriptor::read(MVKDescriptorSet* mvkDescSet,
} }
} }
MVKInlineUniformDescriptor::~MVKInlineUniformDescriptor() { void MVKInlineUniformBlockDescriptor::reset() {
[_mtlBuffer release]; [_mtlBuffer release];
_mtlBuffer = nil;
_dataSize = 0;
MVKDescriptor::reset();
} }
@ -726,8 +730,11 @@ void MVKImageDescriptor::read(MVKDescriptorSet* mvkDescSet,
} }
} }
MVKImageDescriptor::~MVKImageDescriptor() { void MVKImageDescriptor::reset() {
if (_mvkImageView) { _mvkImageView->release(); } if (_mvkImageView) { _mvkImageView->release(); }
_mvkImageView = nullptr;
_imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
MVKDescriptor::reset();
} }
@ -845,8 +852,10 @@ void MVKSamplerDescriptorMixin::setLayout(MVKDescriptorSetLayoutBinding* dslBind
if (oldSamp) { oldSamp->release(); } if (oldSamp) { oldSamp->release(); }
} }
MVKSamplerDescriptorMixin::~MVKSamplerDescriptorMixin() { void MVKSamplerDescriptorMixin::reset() {
if (_mvkSampler) { _mvkSampler->release(); } if (_mvkSampler) { _mvkSampler->release(); }
_mvkSampler = nullptr;
_hasDynamicSampler = true;
} }
@ -913,6 +922,11 @@ void MVKSamplerDescriptor::setLayout(MVKDescriptorSetLayoutBinding* dslBinding,
MVKSamplerDescriptorMixin::setLayout(dslBinding, index); MVKSamplerDescriptorMixin::setLayout(dslBinding, index);
} }
void MVKSamplerDescriptor::reset() {
MVKSamplerDescriptorMixin::reset();
MVKDescriptor::reset();
}
#pragma mark - #pragma mark -
#pragma mark MVKCombinedImageSamplerDescriptor #pragma mark MVKCombinedImageSamplerDescriptor
@ -982,6 +996,11 @@ void MVKCombinedImageSamplerDescriptor::setLayout(MVKDescriptorSetLayoutBinding*
MVKSamplerDescriptorMixin::setLayout(dslBinding, index); MVKSamplerDescriptorMixin::setLayout(dslBinding, index);
} }
void MVKCombinedImageSamplerDescriptor::reset() {
MVKSamplerDescriptorMixin::reset();
MVKImageDescriptor::reset();
}
#pragma mark - #pragma mark -
#pragma mark MVKTexelBufferDescriptor #pragma mark MVKTexelBufferDescriptor
@ -1062,6 +1081,8 @@ void MVKTexelBufferDescriptor::read(MVKDescriptorSet* mvkDescSet,
} }
} }
MVKTexelBufferDescriptor::~MVKTexelBufferDescriptor() { void MVKTexelBufferDescriptor::reset() {
if (_mvkBufferView) { _mvkBufferView->release(); } if (_mvkBufferView) { _mvkBufferView->release(); }
_mvkBufferView = nullptr;
MVKDescriptor::reset();
} }

View File

@ -142,9 +142,70 @@ protected:
#pragma mark - #pragma mark -
#pragma mark MVKDescriptorPool #pragma mark MVKDescriptorTypePreallocation
typedef MVKDeviceObjectPool<MVKDescriptorSet> MVKDescriptorSetPool; /** Support class for MVKDescriptorPool that holds preallocated instances of a single concrete descriptor class. */
template<class DescriptorClass>
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);
std::vector<DescriptorClass> _descriptors;
std::vector<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);
protected:
friend class MVKDescriptorPool;
VkResult allocateDescriptor(VkDescriptorType descriptorType, MVKDescriptor** pMVKDesc);
void freeDescriptor(MVKDescriptor* mvkDesc);
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;
};
#pragma mark -
#pragma mark MVKDescriptorPool
/** Represents a Vulkan descriptor pool. */ /** Represents a Vulkan descriptor pool. */
class MVKDescriptorPool : public MVKVulkanAPIDeviceObject { class MVKDescriptorPool : public MVKVulkanAPIDeviceObject {
@ -183,6 +244,7 @@ protected:
uint32_t _maxSets; uint32_t _maxSets;
std::unordered_set<MVKDescriptorSet*> _allocatedSets; std::unordered_set<MVKDescriptorSet*> _allocatedSets;
MVKPreallocatedDescriptors* _preallocatedDescriptors;
}; };

View File

@ -17,8 +17,7 @@
*/ */
#include "MVKDescriptorSet.h" #include "MVKDescriptorSet.h"
#include "MVKOSExtensions.h"
using namespace mvk;
#pragma mark - #pragma mark -
@ -174,7 +173,7 @@ void MVKDescriptorSetLayout::pushDescriptorSet(MVKCommandEncoder* cmdEncoder,
} }
} }
void MVKDescriptorSetLayout::populateShaderConverterContext(SPIRVToMSLConversionConfiguration& context, void MVKDescriptorSetLayout::populateShaderConverterContext(mvk::SPIRVToMSLConversionConfiguration& context,
MVKShaderResourceBinding& dslMTLRezIdxOffsets, MVKShaderResourceBinding& dslMTLRezIdxOffsets,
uint32_t dslIndex) { uint32_t dslIndex) {
uint32_t bindCnt = (uint32_t)_bindings.size(); uint32_t bindCnt = (uint32_t)_bindings.size();
@ -269,6 +268,220 @@ MVKDescriptorSet::~MVKDescriptorSet() {
} }
#pragma mark -
#pragma mark MVKDescriptorTypePreallocation
#ifndef MVK_CONFIG_PREALLOCATE_DESCRIPTORS
# define MVK_CONFIG_PREALLOCATE_DESCRIPTORS 0
#endif
static bool _mvkPreallocateDescriptors = MVK_CONFIG_PREALLOCATE_DESCRIPTORS;
static bool _mvkPreallocateDescriptorsInitialized = false;
// Returns whether descriptors should be preallocated in the descriptor pools
// We do this once lazily instead of in a library constructor function to
// ensure the NSProcessInfo environment is available when called upon.
static inline bool getMVKPreallocateDescriptors() {
if ( !_mvkPreallocateDescriptorsInitialized ) {
_mvkPreallocateDescriptorsInitialized = true;
MVK_SET_FROM_ENV_OR_BUILD_BOOL(_mvkPreallocateDescriptors, MVK_CONFIG_PREALLOCATE_DESCRIPTORS);
}
return _mvkPreallocateDescriptors;
}
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;
}
}
// 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;
}
// 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
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;
}
}
}
}
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);
}
}
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) {
}
#pragma mark - #pragma mark -
#pragma mark MVKDescriptorPool #pragma mark MVKDescriptorPool
@ -327,54 +540,90 @@ VkResult MVKDescriptorPool::allocateDescriptorSet(MVKDescriptorSetLayout* mvkDSL
void MVKDescriptorPool::freeDescriptorSet(MVKDescriptorSet* mvkDS) { mvkDS->destroy(); } void MVKDescriptorPool::freeDescriptorSet(MVKDescriptorSet* mvkDS) { mvkDS->destroy(); }
// Allocate a descriptor of the specified type
VkResult MVKDescriptorPool::allocateDescriptor(VkDescriptorType descriptorType, VkResult MVKDescriptorPool::allocateDescriptor(VkDescriptorType descriptorType,
MVKDescriptor** pMVKDesc) { MVKDescriptor** pMVKDesc) {
// If descriptors are preallocated allocate from the preallocated pools
if (_preallocatedDescriptors) {
return _preallocatedDescriptors->allocateDescriptor(descriptorType, pMVKDesc);
}
// Otherwise instantiate one of the apporpriate type now
switch (descriptorType) { switch (descriptorType) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
*pMVKDesc = new MVKUniformBufferDescriptor();
break;
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
*pMVKDesc = new MVKBufferDescriptor(); *pMVKDesc = new MVKStorageBufferDescriptor();
return VK_SUCCESS; break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
*pMVKDesc = new MVKUniformBufferDynamicDescriptor();
break;
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
*pMVKDesc = new MVKStorageBufferDynamicDescriptor();
break;
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
*pMVKDesc = new MVKInlineUniformDescriptor(); *pMVKDesc = new MVKInlineUniformBlockDescriptor();
return VK_SUCCESS; break;
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
*pMVKDesc = new MVKSampledImageDescriptor();
break;
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
*pMVKDesc = new MVKStorageImageDescriptor();
break;
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
*pMVKDesc = new MVKImageDescriptor(); *pMVKDesc = new MVKInputAttachmentDescriptor();
return VK_SUCCESS; break;
case VK_DESCRIPTOR_TYPE_SAMPLER: case VK_DESCRIPTOR_TYPE_SAMPLER:
*pMVKDesc = new MVKSamplerDescriptor(); *pMVKDesc = new MVKSamplerDescriptor();
return VK_SUCCESS; break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
*pMVKDesc = new MVKCombinedImageSamplerDescriptor(); *pMVKDesc = new MVKCombinedImageSamplerDescriptor();
return VK_SUCCESS; break;
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
*pMVKDesc = new MVKUniformTexelBufferDescriptor();
break;
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
*pMVKDesc = new MVKTexelBufferDescriptor(); *pMVKDesc = new MVKStorageTexelBufferDescriptor();
return VK_SUCCESS; break;
default: default:
return reportError(VK_ERROR_INITIALIZATION_FAILED, "Unrecognized VkDescriptorType %d.", descriptorType); return reportError(VK_ERROR_INITIALIZATION_FAILED, "Unrecognized VkDescriptorType %d.", descriptorType);
} }
return VK_SUCCESS;
} }
void MVKDescriptorPool::freeDescriptor(MVKDescriptor* mvkDesc) { mvkDesc->destroy(); } // 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();
}
}
MVKDescriptorPool::MVKDescriptorPool(MVKDevice* device, MVKDescriptorPool::MVKDescriptorPool(MVKDevice* device,
const VkDescriptorPoolCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) { const VkDescriptorPoolCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
_maxSets = pCreateInfo->maxSets; _maxSets = pCreateInfo->maxSets;
_preallocatedDescriptors = getMVKPreallocateDescriptors() ? new MVKPreallocatedDescriptors(pCreateInfo) : nullptr;
} }
// Destroy all allocated descriptor sets // Destroy all allocated descriptor sets and preallocated descriptors
MVKDescriptorPool::~MVKDescriptorPool() { MVKDescriptorPool::~MVKDescriptorPool() {
reset(0); reset(0);
if (_preallocatedDescriptors) { _preallocatedDescriptors->destroy(); }
} }
@ -478,13 +727,13 @@ void mvkUpdateDescriptorSetWithTemplate(VkDescriptorSet descriptorSet,
} }
} }
void mvkPopulateShaderConverterContext(SPIRVToMSLConversionConfiguration& context, void mvkPopulateShaderConverterContext(mvk::SPIRVToMSLConversionConfiguration& context,
MVKShaderStageResourceBinding& ssRB, MVKShaderStageResourceBinding& ssRB,
spv::ExecutionModel stage, spv::ExecutionModel stage,
uint32_t descriptorSetIndex, uint32_t descriptorSetIndex,
uint32_t bindingIndex, uint32_t bindingIndex,
MVKSampler* immutableSampler) { MVKSampler* immutableSampler) {
MSLResourceBinding rb; mvk::MSLResourceBinding rb;
auto& rbb = rb.resourceBinding; auto& rbb = rb.resourceBinding;
rbb.stage = stage; rbb.stage = stage;