diff --git a/Docs/MoltenVK_Configuration_Parameters.md b/Docs/MoltenVK_Configuration_Parameters.md index 06cbf3033..d7d499946 100644 --- a/Docs/MoltenVK_Configuration_Parameters.md +++ b/Docs/MoltenVK_Configuration_Parameters.md @@ -324,19 +324,6 @@ You can also use the `MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE` and `MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT` parameters to configure when to log the performance statistics collected by this parameter. ---------------------------------------- -#### MVK_CONFIG_PREALLOCATE_DESCRIPTORS - -##### Type: Boolean -##### Default: `1` - -Controls whether **MoltenVK** should preallocate memory in each `VkDescriptorPool` according -to the values of the `VkDescriptorPoolSize` parameters. Doing so may improve descriptor set -allocation performance and memory stability at a cost of preallocated application memory. -If this setting is disabled, the descriptors required for a descriptor set will be individually -dynamically allocated in application memory when the descriptor set itself is allocated. - - --------------------------------------- #### MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 4c520db07..c904bf278 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -18,6 +18,11 @@ MoltenVK 1.2.11 Released TBD +- Support dynamically allocating descriptors when pool is exhausted. +- Deprecate `MVKConfiguration::preallocateDescriptors` and `MVK_CONFIG_PREALLOCATE_DESCRIPTORS` environment variable. +- `vkAllocateDescriptorSets()`: Per Vulkan spec, if any descriptor set allocation + fails, populate all descriptor set pointers with `VK_NULL_HANDLE`. In addition, + return `VK_ERROR_FRAGMENTED_POOL` if failure was due to pool fragmentation. - Fix rendering issue with render pass that immediately follows a kernel dispatch. - Ensure all MoltenVK config info set by `VK_EXT_layer_settings` is used. diff --git a/MoltenVK/MoltenVK/API/mvk_private_api.h b/MoltenVK/MoltenVK/API/mvk_private_api.h index dd2be2b57..0ea373a5f 100644 --- a/MoltenVK/MoltenVK/API/mvk_private_api.h +++ b/MoltenVK/MoltenVK/API/mvk_private_api.h @@ -225,7 +225,7 @@ typedef struct { MVKConfigAutoGPUCaptureScope autoGPUCaptureScope; /**< MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE */ const char* autoGPUCaptureOutputFilepath; /**< MVK_CONFIG_AUTO_GPU_CAPTURE_OUTPUT_FILE */ VkBool32 texture1DAs2D; /**< MVK_CONFIG_TEXTURE_1D_AS_2D */ - VkBool32 preallocateDescriptors; /**< MVK_CONFIG_PREALLOCATE_DESCRIPTORS */ + VkBool32 preallocateDescriptors; /**< Obsolete, deprecated, and ignored. */ VkBool32 useCommandPooling; /**< MVK_CONFIG_USE_COMMAND_POOLING */ VkBool32 useMTLHeap; /**< MVK_CONFIG_USE_MTLHEAP */ MVKConfigActivityPerformanceLoggingStyle activityPerformanceLoggingStyle; /**< MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE */ diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h index 24917db0e..cb7a63d36 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h @@ -217,12 +217,13 @@ class MVKDescriptorSet : public MVKVulkanAPIDeviceObject { void setBufferSize(uint32_t descIdx, uint32_t value); MVKDescriptorPool* _pool; - MVKDescriptorSetLayout* _layout; + MVKDescriptorSetLayout* _layout = nullptr; + MVKMTLBufferAllocation* _bufferSizesBuffer = nullptr; MVKSmallVector _descriptors; MVKMetalArgumentBuffer _argumentBuffer; - MVKMTLBufferAllocation* _bufferSizesBuffer = nullptr; - uint32_t _dynamicOffsetDescriptorCount; - uint32_t _variableDescriptorCount; + uint32_t _dynamicOffsetDescriptorCount = 0; + uint32_t _variableDescriptorCount = 0; + bool _allDescriptorsAreFromPool = true; }; @@ -242,9 +243,11 @@ class MVKDescriptorTypePool : public MVKBaseObject { protected: friend class MVKDescriptorPool; - VkResult allocateDescriptor(MVKDescriptor** pMVKDesc, MVKDescriptorPool* pool); + VkResult allocateDescriptor(VkDescriptorType descType, MVKDescriptor** pMVKDesc, bool& dynamicAllocation, MVKDescriptorPool* pool); void freeDescriptor(MVKDescriptor* mvkDesc, MVKDescriptorPool* pool); void reset(); + size_t size() { return _availability.size(); } + size_t getRemainingDescriptorCount(); MVKSmallVector _descriptors; MVKBitArray _availability; @@ -286,7 +289,7 @@ class MVKDescriptorPool : public MVKVulkanAPIDeviceObject { void propagateDebugName() override {} VkResult allocateDescriptorSet(MVKDescriptorSetLayout* mvkDSL, uint32_t variableDescriptorCount, VkDescriptorSet* pVKDS); void freeDescriptorSet(MVKDescriptorSet* mvkDS, bool isPoolReset); - VkResult allocateDescriptor(VkDescriptorType descriptorType, MVKDescriptor** pMVKDesc); + VkResult allocateDescriptor(VkDescriptorType descriptorType, MVKDescriptor** pMVKDesc, bool& dynamicAllocation); void freeDescriptor(MVKDescriptor* mvkDesc); void initMetalArgumentBuffer(const VkDescriptorPoolCreateInfo* pCreateInfo); NSUInteger getMetalArgumentBufferEncodedResourceStorageSize(NSUInteger bufferCount, NSUInteger textureCount, NSUInteger samplerCount); @@ -294,7 +297,6 @@ class MVKDescriptorPool : public MVKVulkanAPIDeviceObject { size_t getPoolSize(const VkDescriptorPoolCreateInfo* pCreateInfo, VkDescriptorType descriptorType); std::string getLogDescription(); - bool _hasPooledDescriptors; MVKSmallVector _descriptorSets; MVKBitArray _descriptorSetAvailablility; id _metalArgumentBuffer; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm index b98a6e74d..bc5bf4308 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm @@ -494,7 +494,9 @@ static void populateAuxBuffer(mvk::SPIRVToMSLConversionConfiguration& shaderConf for (uint32_t elemIdx = 0; elemIdx < elemCnt; elemIdx++) { VkDescriptorType descType = mvkDSLBind->getDescriptorType(); MVKDescriptor* mvkDesc = nullptr; - setConfigurationResult(_pool->allocateDescriptor(descType, &mvkDesc)); + bool dynamicAllocation = true; + setConfigurationResult(_pool->allocateDescriptor(descType, &mvkDesc, dynamicAllocation)); // Modifies dynamicAllocation. + if (dynamicAllocation) { _allDescriptorsAreFromPool = false; } if ( !wasConfigurationSuccessful() ) { return getConfigurationResult(); } if (mvkDesc->usesDynamicBufferOffsets()) { _dynamicOffsetDescriptorCount++; } _descriptors.push_back(mvkDesc); @@ -521,12 +523,13 @@ static void populateAuxBuffer(mvk::SPIRVToMSLConversionConfiguration& shaderConf if (isPoolReset) { _argumentBuffer.setArgumentBuffer(_pool->_metalArgumentBuffer, 0, nil); } - // Pooled descriptors don't need to be individually freed under pool resets. - if ( !(_pool->_hasPooledDescriptors && isPoolReset) ) { + // If this is a pool reset, and all desciptors are from the pool, we don't need to free them. + if ( !(isPoolReset && _allDescriptorsAreFromPool) ) { for (auto mvkDesc : _descriptors) { _pool->freeDescriptor(mvkDesc); } } _descriptors.clear(); _descriptors.shrink_to_fit(); + _allDescriptorsAreFromPool = true; if (_bufferSizesBuffer) { _bufferSizesBuffer->returnToPool(); @@ -557,33 +560,46 @@ static void populateAuxBuffer(mvk::SPIRVToMSLConversionConfiguration& shaderConf #pragma mark - #pragma mark MVKDescriptorTypePool -// If preallocated, find the next availalble descriptor. -// If not preallocated, create one on the fly. +// Find the next availalble descriptor in the pool. or if the pool is exhausted, optionally create one on the fly. +// The dynamicAllocation parameter is both an input and output parameter. Incoming, dynamicAllocation indicates that, +// if there are no more descriptors in this pool, a new descriptor should be created and returned. +// On return, dynamicAllocation indicates back to the caller whether a descriptor was dynamically created. +// If a descriptor could not be found in the pool and was not created dynamically, a null descriptor is returned. template -VkResult MVKDescriptorTypePool::allocateDescriptor(MVKDescriptor** pMVKDesc, +VkResult MVKDescriptorTypePool::allocateDescriptor(VkDescriptorType descType, + MVKDescriptor** pMVKDesc, + bool& dynamicAllocation, MVKDescriptorPool* pool) { - DescriptorClass* mvkDesc; - if (pool->_hasPooledDescriptors) { - 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. + VkResult errRslt = VK_ERROR_OUT_OF_POOL_MEMORY; + size_t availDescIdx = _availability.getIndexOfFirstSetBit(); + if (availDescIdx < size()) { + _availability.clearBit(availDescIdx); // Mark the descriptor as taken + *pMVKDesc = &_descriptors[availDescIdx]; + (*pMVKDesc)->reset(); // Reset descriptor before reusing. + dynamicAllocation = false; + return VK_SUCCESS; + } else if (dynamicAllocation) { + *pMVKDesc = new DescriptorClass(); + reportWarning(errRslt, "VkDescriptorPool exhausted pool of %zu %s descriptors. Allocating descriptor dynamically.", size(), mvkVkDescriptorTypeName(descType)); + return VK_SUCCESS; } else { - mvkDesc = new DescriptorClass(); + *pMVKDesc = nullptr; + dynamicAllocation = false; + return reportError(errRslt, "VkDescriptorPool exhausted pool of %zu %s descriptors.", size(), mvkVkDescriptorTypeName(descType)); } - *pMVKDesc = mvkDesc; - return VK_SUCCESS; } -// 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. +// If the descriptor is from the pool, mark it as available, otherwise destroy it. +// Pooled descriptors are held in contiguous memory, so the index of the returning +// descriptor can be calculated by typed pointer differences. The descriptor will +// be reset when it is re-allocated. This streamlines a pool reset(). template void MVKDescriptorTypePool::freeDescriptor(MVKDescriptor* mvkDesc, MVKDescriptorPool* pool) { - if (pool->_hasPooledDescriptors) { - size_t descIdx = (DescriptorClass*)mvkDesc - _descriptors.data(); + DescriptorClass* pDesc = (DescriptorClass*)mvkDesc; + DescriptorClass* pFirstDesc = _descriptors.data(); + int64_t descIdx = pDesc >= pFirstDesc ? pDesc - pFirstDesc : pFirstDesc - pDesc; + if (descIdx >= 0 && descIdx < size()) { _availability.setBit(descIdx); } else { mvkDesc->destroy(); @@ -596,6 +612,13 @@ static void populateAuxBuffer(mvk::SPIRVToMSLConversionConfiguration& shaderConf _availability.setAllBits(); } +template +size_t MVKDescriptorTypePool::getRemainingDescriptorCount() { + size_t enabledCount = 0; + _availability.enumerateEnabledBits(false, [&](size_t bitIdx) { enabledCount++; return true; }); + return enabledCount; +} + template MVKDescriptorTypePool::MVKDescriptorTypePool(size_t poolSize) : _descriptors(poolSize), @@ -620,11 +643,20 @@ static void populateAuxBuffer(mvk::SPIRVToMSLConversionConfiguration& shaderConf } @autoreleasepool { - for (uint32_t dsIdx = 0; dsIdx < pAllocateInfo->descriptorSetCount; dsIdx++) { + auto dsCnt = pAllocateInfo->descriptorSetCount; + for (uint32_t dsIdx = 0; dsIdx < dsCnt; dsIdx++) { MVKDescriptorSetLayout* mvkDSL = (MVKDescriptorSetLayout*)pAllocateInfo->pSetLayouts[dsIdx]; if ( !mvkDSL->_isPushDescriptorLayout ) { VkResult rslt = allocateDescriptorSet(mvkDSL, (pVarDescCounts ? pVarDescCounts[dsIdx] : 0), &pDescriptorSets[dsIdx]); - if (rslt) { return rslt; } + if (rslt) { + // Per Vulkan spec, if any descriptor set allocation fails, free any successful + // allocations, and populate all descriptor set pointers with VK_NULL_HANDLE. + freeDescriptorSets(dsIdx, pDescriptorSets); + for (uint32_t i = 0; i < dsCnt; i++) { pDescriptorSets[i] = VK_NULL_HANDLE; } + return rslt; + } + } else { + pDescriptorSets[dsIdx] = VK_NULL_HANDLE; } } } @@ -637,7 +669,7 @@ static void populateAuxBuffer(mvk::SPIRVToMSLConversionConfiguration& shaderConf VkResult MVKDescriptorPool::allocateDescriptorSet(MVKDescriptorSetLayout* mvkDSL, uint32_t variableDescriptorCount, VkDescriptorSet* pVKDS) { - VkResult rslt = VK_ERROR_OUT_OF_POOL_MEMORY; + VkResult rslt = VK_ERROR_FRAGMENTED_POOL; uint64_t mtlArgBuffEncSize = 0; id mtlArgEnc = nil; if (mvkDSL->isUsingMetalArgumentBuffers()) { @@ -747,43 +779,44 @@ static void populateAuxBuffer(mvk::SPIRVToMSLConversionConfiguration& shaderConf // Allocate a descriptor of the specified type VkResult MVKDescriptorPool::allocateDescriptor(VkDescriptorType descriptorType, - MVKDescriptor** pMVKDesc) { + MVKDescriptor** pMVKDesc, + bool& dynamicAllocation) { switch (descriptorType) { case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: - return _uniformBufferDescriptors.allocateDescriptor(pMVKDesc, this); + return _uniformBufferDescriptors.allocateDescriptor(descriptorType, pMVKDesc, dynamicAllocation, this); case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: - return _storageBufferDescriptors.allocateDescriptor(pMVKDesc, this); + return _storageBufferDescriptors.allocateDescriptor(descriptorType, pMVKDesc, dynamicAllocation, this); case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: - return _uniformBufferDynamicDescriptors.allocateDescriptor(pMVKDesc, this); + return _uniformBufferDynamicDescriptors.allocateDescriptor(descriptorType, pMVKDesc, dynamicAllocation, this); case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: - return _storageBufferDynamicDescriptors.allocateDescriptor(pMVKDesc, this); + return _storageBufferDynamicDescriptors.allocateDescriptor(descriptorType, pMVKDesc, dynamicAllocation, this); case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: - return _inlineUniformBlockDescriptors.allocateDescriptor(pMVKDesc, this); + return _inlineUniformBlockDescriptors.allocateDescriptor(descriptorType, pMVKDesc, dynamicAllocation, this); case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - return _sampledImageDescriptors.allocateDescriptor(pMVKDesc, this); + return _sampledImageDescriptors.allocateDescriptor(descriptorType, pMVKDesc, dynamicAllocation, this); case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - return _storageImageDescriptors.allocateDescriptor(pMVKDesc, this); + return _storageImageDescriptors.allocateDescriptor(descriptorType, pMVKDesc, dynamicAllocation, this); case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: - return _inputAttachmentDescriptors.allocateDescriptor(pMVKDesc, this); + return _inputAttachmentDescriptors.allocateDescriptor(descriptorType, pMVKDesc, dynamicAllocation, this); case VK_DESCRIPTOR_TYPE_SAMPLER: - return _samplerDescriptors.allocateDescriptor(pMVKDesc, this); + return _samplerDescriptors.allocateDescriptor(descriptorType, pMVKDesc, dynamicAllocation, this); case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: - return _combinedImageSamplerDescriptors.allocateDescriptor(pMVKDesc, this); + return _combinedImageSamplerDescriptors.allocateDescriptor(descriptorType, pMVKDesc, dynamicAllocation, this); case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: - return _uniformTexelBufferDescriptors.allocateDescriptor(pMVKDesc, this); + return _uniformTexelBufferDescriptors.allocateDescriptor(descriptorType, pMVKDesc, dynamicAllocation, this); case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: - return _storageTexelBufferDescriptors.allocateDescriptor(pMVKDesc, this); + return _storageTexelBufferDescriptors.allocateDescriptor(descriptorType, pMVKDesc, dynamicAllocation, this); default: return reportError(VK_ERROR_INITIALIZATION_FAILED, "Unrecognized VkDescriptorType %d.", descriptorType); @@ -834,17 +867,12 @@ static void populateAuxBuffer(mvk::SPIRVToMSLConversionConfiguration& shaderConf } } -// Return the size of the preallocated pool for descriptors of the specified type, -// or zero if we are not preallocating descriptors in the pool. +// Return the size of the preallocated pool for descriptors of the specified type. // There may be more than one poolSizeCount instance for the desired VkDescriptorType. // Accumulate the descriptor count for the desired VkDescriptorType accordingly. // For descriptors of the VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT type, // we accumulate the count via the pNext chain. -size_t MVKDescriptorPool::getPoolSize(const VkDescriptorPoolCreateInfo* pCreateInfo, - VkDescriptorType descriptorType) { - - if ( !_hasPooledDescriptors ) { return 0; } - +size_t MVKDescriptorPool::getPoolSize(const VkDescriptorPoolCreateInfo* pCreateInfo, VkDescriptorType descriptorType) { uint32_t descCnt = 0; if (descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) { for (const auto* next = (VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) { @@ -868,26 +896,28 @@ static void populateAuxBuffer(mvk::SPIRVToMSLConversionConfiguration& shaderConf } std::string MVKDescriptorPool::getLogDescription() { +#define STR(name) #name +#define printDescCnt(descType, spacing, descPool) descStr << "\n\t" STR(VK_DESCRIPTOR_TYPE_##descType) ": " spacing << _##descPool##Descriptors.size() << " (" << _##descPool##Descriptors.getRemainingDescriptorCount() << " remaining)"; + std::stringstream descStr; - descStr << "VkDescriptorPool " << this << " with " << _descriptorSetAvailablility.size() << " descriptor sets, and descriptors:"; - descStr << "\n\tVK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: " << _uniformBufferDescriptors._availability.size(); - descStr << "\n\tVK_DESCRIPTOR_TYPE_STORAGE_BUFFER: " << _storageBufferDescriptors._availability.size(); - descStr << "\n\tVK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: " << _uniformBufferDynamicDescriptors._availability.size(); - descStr << "\n\tVK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: " << _storageBufferDynamicDescriptors._availability.size(); - descStr << "\n\tVK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: " << _inlineUniformBlockDescriptors._availability.size(); - descStr << "\n\tVK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: " << _sampledImageDescriptors._availability.size(); - descStr << "\n\tVK_DESCRIPTOR_TYPE_STORAGE_IMAGE: " << _storageImageDescriptors._availability.size(); - descStr << "\n\tVK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: " << _inputAttachmentDescriptors._availability.size(); - descStr << "\n\tVK_DESCRIPTOR_TYPE_SAMPLER: " << _samplerDescriptors._availability.size(); - descStr << "\n\tVK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: " << _combinedImageSamplerDescriptors._availability.size(); - descStr << "\n\tVK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: " << _uniformTexelBufferDescriptors._availability.size(); - descStr << "\n\tVK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: " << _storageTexelBufferDescriptors._availability.size(); + descStr << "VkDescriptorPool " << this << " with " << _descriptorSetAvailablility.size() << " descriptor sets, and pooled descriptors:"; + printDescCnt(UNIFORM_BUFFER, " ", uniformBuffer); + printDescCnt(STORAGE_BUFFER, " ", storageBuffer); + printDescCnt(UNIFORM_BUFFER_DYNAMIC, " ", uniformBufferDynamic); + printDescCnt(STORAGE_BUFFER_DYNAMIC, " ", storageBufferDynamic); + printDescCnt(INLINE_UNIFORM_BLOCK_EXT, "", inlineUniformBlock); + printDescCnt(SAMPLED_IMAGE, " ", sampledImage); + printDescCnt(STORAGE_IMAGE, " ", storageImage); + printDescCnt(INPUT_ATTACHMENT, " ", inputAttachment); + printDescCnt(SAMPLER, " ", sampler); + printDescCnt(COMBINED_IMAGE_SAMPLER, " ", combinedImageSampler); + printDescCnt(UNIFORM_TEXEL_BUFFER, " ", uniformTexelBuffer); + printDescCnt(STORAGE_TEXEL_BUFFER, " ", storageTexelBuffer); return descStr.str(); } MVKDescriptorPool::MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device), - _hasPooledDescriptors(getMVKConfig().preallocateDescriptors), // Set this first! Accessed by MVKDescriptorSet constructor and getPoolSize() in following lines. _descriptorSets(pCreateInfo->maxSets, MVKDescriptorSet(this)), _descriptorSetAvailablility(pCreateInfo->maxSets, true), _mtlBufferAllocator(_device, getMetalFeatures().maxMTLBufferSize, true), @@ -1096,6 +1126,8 @@ void mvkUpdateDescriptorSets(uint32_t writeCount, size_t stride; MVKDescriptorSet* dstSet = (MVKDescriptorSet*)pDescWrite->dstSet; + if( !dstSet ) { continue; } // Nulls are permitted + const VkWriteDescriptorSetInlineUniformBlockEXT* pInlineUniformBlock = nullptr; if (dstSet->getEnabledExtensions().vk_EXT_inline_uniform_block.enabled) { for (const auto* next = (VkBaseInStructure*)pDescWrite->pNext; next; next = next->pNext) { @@ -1134,9 +1166,10 @@ void mvkUpdateDescriptorSets(uint32_t writeCount, inlineUniformBlock.dataSize = descCnt; MVKDescriptorSet* srcSet = (MVKDescriptorSet*)pDescCopy->srcSet; - srcSet->read(pDescCopy, imgInfos, buffInfos, texelBuffInfos, &inlineUniformBlock); - MVKDescriptorSet* dstSet = (MVKDescriptorSet*)pDescCopy->dstSet; + if( !srcSet || !dstSet ) { continue; } // Nulls are permitted + + srcSet->read(pDescCopy, imgInfos, buffInfos, texelBuffInfos, &inlineUniformBlock); VkDescriptorType descType = dstSet->getDescriptorType(pDescCopy->dstBinding); size_t stride; const void* pData = getWriteParameters(descType, imgInfos, buffInfos, texelBuffInfos, &inlineUniformBlock, stride); diff --git a/MoltenVK/MoltenVK/Utility/MVKConfigMembers.def b/MoltenVK/MoltenVK/Utility/MVKConfigMembers.def index 0648ea04a..da73d3121 100644 --- a/MoltenVK/MoltenVK/Utility/MVKConfigMembers.def +++ b/MoltenVK/MoltenVK/Utility/MVKConfigMembers.def @@ -72,7 +72,7 @@ MVK_CONFIG_MEMBER(semaphoreSupportStyle, MVKVkSemaphoreSupportS MVK_CONFIG_MEMBER(autoGPUCaptureScope, MVKConfigAutoGPUCaptureScope, AUTO_GPU_CAPTURE_SCOPE) MVK_CONFIG_MEMBER_STRING(autoGPUCaptureOutputFilepath, const char*, AUTO_GPU_CAPTURE_OUTPUT_FILE) MVK_CONFIG_MEMBER(texture1DAs2D, VkBool32, TEXTURE_1D_AS_2D) -MVK_CONFIG_MEMBER(preallocateDescriptors, VkBool32, PREALLOCATE_DESCRIPTORS) +MVK_CONFIG_MEMBER(preallocateDescriptors, VkBool32, PREALLOCATE_DESCRIPTORS) // Deprecated legacy MVK_CONFIG_MEMBER(useCommandPooling, VkBool32, USE_COMMAND_POOLING) MVK_CONFIG_MEMBER(useMTLHeap, VkBool32, USE_MTLHEAP) MVK_CONFIG_MEMBER(apiVersionToAdvertise, uint32_t, API_VERSION_TO_ADVERTISE) diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h index 10d511cbc..3a8db5d15 100644 --- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h +++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h @@ -293,7 +293,7 @@ void mvkSetConfig(MVKConfiguration& dstMVKConfig, const MVKConfiguration& srcMVK # define MVK_CONFIG_TEXTURE_1D_AS_2D 1 #endif -/** Preallocate descriptors when creating VkDescriptorPool. Enabled by default. */ +/** Obsolete, deprecated, and ignored. */ #ifndef MVK_CONFIG_PREALLOCATE_DESCRIPTORS # define MVK_CONFIG_PREALLOCATE_DESCRIPTORS 1 #endif