MVKDescriptorPool optimize reseting descriptor pool.

Don't free individual pooled descriptors during a pool reset.
Don't mark availability of individual descriptor sets during a pool reset.
Add MVKDescriptorPool::_hasPooledDescriptors as SVOT to track if descriptors
are pooled, and is set from outside constructor to ensure all internal
descriptor pools are constructed with the same SVOT.
MVKDescriptorPool::allocateDescriptorSet() ensure correct result returned.
This commit is contained in:
Bill Hollings 2021-03-15 15:52:40 -04:00
parent 4371ef4d2b
commit 6cba6a851b
3 changed files with 70 additions and 57 deletions

View File

@ -161,9 +161,8 @@ public:
protected:
friend class MVKDescriptorPool;
inline bool isPreallocated() { return _availability.size() > 0; }
VkResult allocateDescriptor(MVKDescriptor** pMVKDesc);
void freeDescriptor(MVKDescriptor* mvkDesc);
VkResult allocateDescriptor(MVKDescriptor** pMVKDesc, MVKDescriptorPool* pool);
void freeDescriptor(MVKDescriptor* mvkDesc, MVKDescriptorPool* pool);
void reset();
MVKSmallVector<DescriptorClass> _descriptors;
@ -195,12 +194,13 @@ public:
/** Destroys all currently allocated descriptor sets. */
VkResult reset(VkDescriptorPoolResetFlags flags);
MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo);
MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo, bool poolDescriptors);
~MVKDescriptorPool() override;
protected:
friend class MVKDescriptorSet;
template<class> friend class MVKDescriptorTypePreallocation;
void propagateDebugName() override {}
const uint32_t* getVariableDecriptorCounts(const VkDescriptorSetAllocateInfo* pAllocateInfo);
@ -224,6 +224,7 @@ protected:
MVKDescriptorTypePreallocation<MVKCombinedImageSamplerDescriptor> _combinedImageSamplerDescriptors;
MVKDescriptorTypePreallocation<MVKUniformTexelBufferDescriptor> _uniformTexelBufferDescriptors;
MVKDescriptorTypePreallocation<MVKStorageTexelBufferDescriptor> _storageTexelBufferDescriptors;
bool _hasPooledDescriptors;
};

View File

@ -304,7 +304,10 @@ void MVKDescriptorSet::free(bool isPoolReset) {
_layout = nullptr;
_variableDescriptorCount = 0;
// Pooled descriptors don't need to be individually freed under pool resets.
if ( !(_pool->_hasPooledDescriptors && isPoolReset) ) {
for (auto mvkDesc : _descriptors) { _pool->freeDescriptor(mvkDesc); }
}
_descriptors.clear();
clearConfigurationResult();
@ -321,9 +324,10 @@ MVKDescriptorSet::MVKDescriptorSet(MVKDescriptorPool* pool) : MVKVulkanAPIDevice
// If preallocated, find the next availalble descriptor.
// If not preallocated, create one on the fly.
template<class DescriptorClass>
VkResult MVKDescriptorTypePreallocation<DescriptorClass>::allocateDescriptor(MVKDescriptor** pMVKDesc) {
VkResult MVKDescriptorTypePreallocation<DescriptorClass>::allocateDescriptor(MVKDescriptor** pMVKDesc,
MVKDescriptorPool* pool) {
DescriptorClass* mvkDesc;
if (isPreallocated()) {
if (pool->_hasPooledDescriptors) {
size_t availDescIdx = _availability.getIndexOfFirstSetBit(true);
if (availDescIdx >= _availability.size()) { return VK_ERROR_OUT_OF_POOL_MEMORY; }
mvkDesc = &_descriptors[availDescIdx];
@ -340,8 +344,9 @@ VkResult MVKDescriptorTypePreallocation<DescriptorClass>::allocateDescriptor(MVK
// 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) {
if (isPreallocated()) {
void MVKDescriptorTypePreallocation<DescriptorClass>::freeDescriptor(MVKDescriptor* mvkDesc,
MVKDescriptorPool* pool) {
if (pool->_hasPooledDescriptors) {
size_t descIdx = (DescriptorClass*)mvkDesc - _descriptors.data();
_availability.setBit(descIdx);
} else {
@ -372,7 +377,7 @@ VkResult MVKDescriptorPool::allocateDescriptorSets(const VkDescriptorSetAllocate
MVKDescriptorSetLayout* mvkDSL = (MVKDescriptorSetLayout*)pAllocateInfo->pSetLayouts[dsIdx];
if ( !mvkDSL->isPushDescriptorLayout() ) {
rslt = allocateDescriptorSet(mvkDSL, (pVarDescCounts ? pVarDescCounts[dsIdx] : 0), &pDescriptorSets[dsIdx]);
if (rslt) { break; }
if (rslt) { return rslt; }
}
}
return rslt;
@ -404,13 +409,13 @@ VkResult MVKDescriptorPool::allocateDescriptorSet(MVKDescriptorSetLayout* mvkDSL
if (dsIdx >= _descriptorSets.size()) { return VK_ERROR_OUT_OF_POOL_MEMORY; }
MVKDescriptorSet* mvkDS = &_descriptorSets[dsIdx];
mvkDS->allocate(mvkDSL, variableDescriptorCount);
if (mvkDS->wasConfigurationSuccessful()) {
*pVKDS = (VkDescriptorSet)mvkDS;
} else {
VkResult rslt = mvkDS->allocate(mvkDSL, variableDescriptorCount);
if (rslt) {
freeDescriptorSet(mvkDS, false);
} else {
*pVKDS = (VkDescriptorSet)mvkDS;
}
return mvkDS->getConfigurationResult();
return rslt;
}
VkResult MVKDescriptorPool::freeDescriptorSets(uint32_t count, const VkDescriptorSet* pDescriptorSets) {
@ -422,13 +427,16 @@ VkResult MVKDescriptorPool::freeDescriptorSets(uint32_t count, const VkDescripto
// Descriptor sets are held in contiguous memory, so the index of the returning descriptor
// set can be calculated by pointer differences, and it can be marked as available.
// Don't bother individually set descriptor set availability if pool is being reset.
void MVKDescriptorPool::freeDescriptorSet(MVKDescriptorSet* mvkDS, bool isPoolReset) {
if ( !mvkDS ) { return; } // Vulkan allows NULL refs.
if (mvkDS->_pool == this) {
mvkDS->free(isPoolReset);
if ( !isPoolReset ) {
size_t dsIdx = mvkDS - _descriptorSets.data();
_descriptorSetAvailablility.setBit(dsIdx);
}
} else {
reportError(VK_ERROR_INITIALIZATION_FAILED, "A descriptor set is being returned to a descriptor pool that did not allocate it.");
}
@ -437,6 +445,7 @@ void MVKDescriptorPool::freeDescriptorSet(MVKDescriptorSet* mvkDS, bool isPoolRe
// Free all descriptor sets and reset descriptor pools
VkResult MVKDescriptorPool::reset(VkDescriptorPoolResetFlags flags) {
for (auto& mvkDS : _descriptorSets) { freeDescriptorSet(&mvkDS, true); }
_descriptorSetAvailablility.setAllBits();
_uniformBufferDescriptors.reset();
_storageBufferDescriptors.reset();
@ -459,40 +468,40 @@ VkResult MVKDescriptorPool::allocateDescriptor(VkDescriptorType descriptorType,
MVKDescriptor** pMVKDesc) {
switch (descriptorType) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
return _uniformBufferDescriptors.allocateDescriptor(pMVKDesc);
return _uniformBufferDescriptors.allocateDescriptor(pMVKDesc, this);
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
return _storageBufferDescriptors.allocateDescriptor(pMVKDesc);
return _storageBufferDescriptors.allocateDescriptor(pMVKDesc, this);
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
return _uniformBufferDynamicDescriptors.allocateDescriptor(pMVKDesc);
return _uniformBufferDynamicDescriptors.allocateDescriptor(pMVKDesc, this);
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
return _storageBufferDynamicDescriptors.allocateDescriptor(pMVKDesc);
return _storageBufferDynamicDescriptors.allocateDescriptor(pMVKDesc, this);
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
return _inlineUniformBlockDescriptors.allocateDescriptor(pMVKDesc);
return _inlineUniformBlockDescriptors.allocateDescriptor(pMVKDesc, this);
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
return _sampledImageDescriptors.allocateDescriptor(pMVKDesc);
return _sampledImageDescriptors.allocateDescriptor(pMVKDesc, this);
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
return _storageImageDescriptors.allocateDescriptor(pMVKDesc);
return _storageImageDescriptors.allocateDescriptor(pMVKDesc, this);
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
return _inputAttachmentDescriptors.allocateDescriptor(pMVKDesc);
return _inputAttachmentDescriptors.allocateDescriptor(pMVKDesc, this);
case VK_DESCRIPTOR_TYPE_SAMPLER:
return _samplerDescriptors.allocateDescriptor(pMVKDesc);
return _samplerDescriptors.allocateDescriptor(pMVKDesc, this);
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
return _combinedImageSamplerDescriptors.allocateDescriptor(pMVKDesc);
return _combinedImageSamplerDescriptors.allocateDescriptor(pMVKDesc, this);
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
return _uniformTexelBufferDescriptors.allocateDescriptor(pMVKDesc);
return _uniformTexelBufferDescriptors.allocateDescriptor(pMVKDesc, this);
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
return _storageTexelBufferDescriptors.allocateDescriptor(pMVKDesc);
return _storageTexelBufferDescriptors.allocateDescriptor(pMVKDesc, this);
default:
return reportError(VK_ERROR_INITIALIZATION_FAILED, "Unrecognized VkDescriptorType %d.", descriptorType);
@ -503,40 +512,40 @@ void MVKDescriptorPool::freeDescriptor(MVKDescriptor* mvkDesc) {
VkDescriptorType descriptorType = mvkDesc->getDescriptorType();
switch (descriptorType) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
return _uniformBufferDescriptors.freeDescriptor(mvkDesc);
return _uniformBufferDescriptors.freeDescriptor(mvkDesc, this);
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
return _storageBufferDescriptors.freeDescriptor(mvkDesc);
return _storageBufferDescriptors.freeDescriptor(mvkDesc, this);
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
return _uniformBufferDynamicDescriptors.freeDescriptor(mvkDesc);
return _uniformBufferDynamicDescriptors.freeDescriptor(mvkDesc, this);
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
return _storageBufferDynamicDescriptors.freeDescriptor(mvkDesc);
return _storageBufferDynamicDescriptors.freeDescriptor(mvkDesc, this);
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
return _inlineUniformBlockDescriptors.freeDescriptor(mvkDesc);
return _inlineUniformBlockDescriptors.freeDescriptor(mvkDesc, this);
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
return _sampledImageDescriptors.freeDescriptor(mvkDesc);
return _sampledImageDescriptors.freeDescriptor(mvkDesc, this);
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
return _storageImageDescriptors.freeDescriptor(mvkDesc);
return _storageImageDescriptors.freeDescriptor(mvkDesc, this);
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
return _inputAttachmentDescriptors.freeDescriptor(mvkDesc);
return _inputAttachmentDescriptors.freeDescriptor(mvkDesc, this);
case VK_DESCRIPTOR_TYPE_SAMPLER:
return _samplerDescriptors.freeDescriptor(mvkDesc);
return _samplerDescriptors.freeDescriptor(mvkDesc, this);
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
return _combinedImageSamplerDescriptors.freeDescriptor(mvkDesc);
return _combinedImageSamplerDescriptors.freeDescriptor(mvkDesc, this);
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
return _uniformTexelBufferDescriptors.freeDescriptor(mvkDesc);
return _uniformTexelBufferDescriptors.freeDescriptor(mvkDesc, this);
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
return _storageTexelBufferDescriptors.freeDescriptor(mvkDesc);
return _storageTexelBufferDescriptors.freeDescriptor(mvkDesc, this);
default:
reportError(VK_ERROR_INITIALIZATION_FAILED, "Unrecognized VkDescriptorType %d.", descriptorType);
@ -547,9 +556,9 @@ void MVKDescriptorPool::freeDescriptor(MVKDescriptor* mvkDesc) {
// 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) {
static size_t getPoolSize(const VkDescriptorPoolCreateInfo* pCreateInfo, VkDescriptorType descriptorType, bool poolDescriptors) {
uint32_t descCnt = 0;
if (mvkGetMVKConfiguration()->preallocateDescriptors) {
if (poolDescriptors) {
uint32_t poolCnt = pCreateInfo->poolSizeCount;
for (uint32_t poolIdx = 0; poolIdx < poolCnt; poolIdx++) {
auto& poolSize = pCreateInfo->pPoolSizes[poolIdx];
@ -559,22 +568,25 @@ static size_t getPoolSize(const VkDescriptorPoolCreateInfo* pCreateInfo, VkDescr
return descCnt;
}
MVKDescriptorPool::MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo) :
// Although poolDescriptors is derived from MVKConfiguration, it is passed in here to ensure all components of this instance see a SVOT for this value.
// Alternate might have been to force _hasPooledDescriptors to be set first by changing member declaration order in class declaration.
MVKDescriptorPool::MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo, bool poolDescriptors) :
MVKVulkanAPIDeviceObject(device),
_descriptorSets(pCreateInfo->maxSets, MVKDescriptorSet(this)),
_descriptorSetAvailablility(pCreateInfo->maxSets, true),
_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)) {}
_uniformBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, poolDescriptors)),
_storageBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, poolDescriptors)),
_uniformBufferDynamicDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, poolDescriptors)),
_storageBufferDynamicDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, poolDescriptors)),
_inlineUniformBlockDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT, poolDescriptors)),
_sampledImageDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, poolDescriptors)),
_storageImageDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, poolDescriptors)),
_inputAttachmentDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, poolDescriptors)),
_samplerDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_SAMPLER, poolDescriptors)),
_combinedImageSamplerDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, poolDescriptors)),
_uniformTexelBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, poolDescriptors)),
_storageTexelBufferDescriptors(getPoolSize(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, poolDescriptors)),
_hasPooledDescriptors(poolDescriptors) {}
MVKDescriptorPool::~MVKDescriptorPool() {
reset(0);

View File

@ -3335,7 +3335,7 @@ void MVKDevice::destroyDescriptorSetLayout(MVKDescriptorSetLayout* mvkDSL,
MVKDescriptorPool* MVKDevice::createDescriptorPool(const VkDescriptorPoolCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator) {
return new MVKDescriptorPool(this, pCreateInfo);
return new MVKDescriptorPool(this, pCreateInfo, mvkGetMVKConfiguration()->preallocateDescriptors);
}
void MVKDevice::destroyDescriptorPool(MVKDescriptorPool* mvkDP,