diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index d18ce65e..2df61a3c 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -12,6 +12,28 @@ Copyright (c) 2014-2018 [The Brenwill Workshop Ltd.](http://www.brenwill.com) For best results, use a Markdown reader.* +MoltenVK 1.0.23 +--------------- + +Released 2018/09/28 + +- Add support for features: + - shaderStorageImageMultisample + - shaderStorageImageReadWithoutFormat + - shaderStorageImageWriteWithoutFormat + - shaderUniformBufferArrayDynamicIndexing + - shaderSampledImageArrayDynamicIndexing + - shaderStorageBufferArrayDynamicIndexing + - shaderStorageImageArrayDynamicIndexing +- Support reduced render area +- Support rasterization to missing attachment +- Allocate MVKCommandBuffers from a pool within MVKCommandPool. +- Update glslang version +- Update to latest SPIRV-Cross version: + - MSL: Improve coordinate handling for buffer reads. + - MSL: Expand arrays of buffers passed as input. + + MoltenVK 1.0.22 --------------- diff --git a/ExternalRevisions/glslang_repo_revision b/ExternalRevisions/glslang_repo_revision index 3cf4e5d4..26eb722f 100644 --- a/ExternalRevisions/glslang_repo_revision +++ b/ExternalRevisions/glslang_repo_revision @@ -1 +1 @@ -a8453d4bc00998049db0d448764784a6a0767539 +91ac4290bcf2cb930b4fb0981f09c00c0b6797e1 diff --git a/MoltenVK/MoltenVK/Commands/MVKCommand.h b/MoltenVK/MoltenVK/Commands/MVKCommand.h index b3dd8f3e..00ba38a4 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommand.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommand.h @@ -77,7 +77,7 @@ public: /** * Instances of this class can participate in a linked list or pool. When so participating, - * this is a reference to the next command in the linked list. This value should only be + * this is a reference to the next instance in the linked list. This value should only be * managed and set by the linked list. */ MVKCommand* _next = nullptr; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h index 9c062903..c28a3989 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h @@ -21,6 +21,7 @@ #include "MVKDevice.h" #include "MVKCommand.h" #include "MVKCommandEncoderState.h" +#include "MVKMTLBufferAllocation.h" #include "MVKCmdPipeline.h" #include #include @@ -90,15 +91,15 @@ public: /** * Instances of this class can participate in a linked list or pool. When so participating, - * this is a reference to the next command in the linked list. This value should only be + * this is a reference to the next instance in the linked list. This value should only be * managed and set by the linked list. */ MVKCommandBuffer* _next; #pragma mark Construction - - MVKCommandBuffer(MVKDevice* device, const VkCommandBufferAllocateInfo* pAllocateInfo); + + MVKCommandBuffer(MVKDevice* device) : MVKDispatchableDeviceObject(device) {} ~MVKCommandBuffer() override; @@ -118,7 +119,9 @@ public: protected: friend class MVKCommandEncoder; + friend class MVKCommandPool; + void init(const VkCommandBufferAllocateInfo* pAllocateInfo); bool canExecute(); bool canPrefill(); void prefill(); @@ -140,6 +143,33 @@ protected: }; +#pragma mark - +#pragma mark MVKCommandBufferPool + +/** + * A pool of MVKCommandBuffer instances. + * + * To return a MVKCommandBuffer retrieved from this pool, back to this pool, + * call the returnToPool() function on the MVKCommandBuffer instance. + */ +class MVKCommandBufferPool : public MVKObjectPool { + +public: + + /** Returns a new command instance. */ + MVKCommandBuffer* newObject() override { return new MVKCommandBuffer(_device); } + + /** + * Configures this instance to either use pooling, or not, depending on the + * value of isPooling, which defaults to true if not indicated explicitly. + */ + MVKCommandBufferPool(MVKDevice* device, bool isPooling = true) : MVKObjectPool(isPooling), _device(device) {} + +protected: + MVKDevice* _device; +}; + + #pragma mark - #pragma mark MVKCommandEncoder diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index 6812ceb7..7c2f2327 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -175,11 +175,9 @@ void MVKCommandBuffer::clearPrefilledMTLCommandBuffer() { #pragma mark Construction -MVKCommandBuffer::MVKCommandBuffer(MVKDevice* device, - const VkCommandBufferAllocateInfo* pAllocateInfo) : MVKDispatchableDeviceObject(device) { - +// Initializes this instance after it has been created retrieved from a pool. +void MVKCommandBuffer::init(const VkCommandBufferAllocateInfo* pAllocateInfo) { _commandPool = (MVKCommandPool*)pAllocateInfo->commandPool; - _commandPool->addCommandBuffer(this); _isSecondary = (pAllocateInfo->level == VK_COMMAND_BUFFER_LEVEL_SECONDARY); _head = nullptr; _tail = nullptr; @@ -190,7 +188,6 @@ MVKCommandBuffer::MVKCommandBuffer(MVKDevice* device, MVKCommandBuffer::~MVKCommandBuffer() { reset(0); - _commandPool->removeCommandBuffer(this); } diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h index ce9779d1..8e54826f 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h @@ -18,7 +18,8 @@ #pragma once -#include "MVKCommandPool.h" +#include "MVKMTLResourceBindings.h" +#include "MVKCommandResourceFactory.h" #include class MVKCommandEncoder; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h index 37c25671..1373cb0c 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h @@ -97,6 +97,9 @@ public: /** Returns a MTLComputePipelineState for filling a buffer. */ id getCmdFillBufferMTLComputePipelineState(); + /** Deletes all the internal resources. */ + void clear(); + #pragma mark Construction MVKCommandEncodingPool(MVKDevice* device); diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm index 74e82d6a..b1d94620 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm @@ -105,6 +105,12 @@ id MVKCommandEncodingPool::getCmdFillBufferMTLComputePi MVK_ENC_REZ_ACCESS(_mtlFillBufferComputePipelineState, newCmdFillBufferMTLComputePipelineState()); } +void MVKCommandEncodingPool::clear() { + lock_guard lock(_lock); + destroyMetalResources(); +} + + #pragma mark Construction MVKCommandEncodingPool::MVKCommandEncodingPool(MVKDevice* device) : MVKBaseDeviceObject(device), diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPool.h b/MoltenVK/MoltenVK/Commands/MVKCommandPool.h index e8278b44..5ded1d5e 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandPool.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandPool.h @@ -19,6 +19,7 @@ #pragma once #include "MVKDevice.h" +#include "MVKCommandBuffer.h" #include "MVKCommandResourceFactory.h" #include "MVKCommandEncodingPool.h" #include "MVKCommand.h" @@ -169,12 +170,10 @@ public: ~MVKCommandPool() override; -private: - friend class MVKCommandBuffer; - - void addCommandBuffer(MVKCommandBuffer* cmdBuffer); - void removeCommandBuffer(MVKCommandBuffer* cmdBuffer); +protected: + void freeCommandBuffer(MVKCommandBuffer* mvkCmdBuff); + MVKCommandBufferPool _commandBufferPool; std::unordered_set _commandBuffers; MVKCommandEncodingPool _commandEncodingPool; uint32_t _queueFamilyIndex; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm b/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm index d33b9e5e..559b3489 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm @@ -33,9 +33,14 @@ using namespace std; // Reset all of the command buffers VkResult MVKCommandPool::reset(VkCommandPoolResetFlags flags) { - for (auto& cb : _commandBuffers) { - cb->reset(VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); - } + bool releaseRez = mvkAreFlagsEnabled(flags, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT); + + VkCommandBufferResetFlags cmdBuffFlags = releaseRez ? VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT : 0; + + for (auto& cb : _commandBuffers) { cb->reset(cmdBuffFlags); } + + if (releaseRez) { trim(); } + return VK_SUCCESS; } @@ -47,7 +52,9 @@ VkResult MVKCommandPool::allocateCommandBuffers(const VkCommandBufferAllocateInf VkResult rslt = VK_SUCCESS; uint32_t cbCnt = pAllocateInfo->commandBufferCount; for (uint32_t cbIdx = 0; cbIdx < cbCnt; cbIdx++) { - MVKCommandBuffer* mvkCmdBuff = new MVKCommandBuffer(_device, pAllocateInfo); + MVKCommandBuffer* mvkCmdBuff = _commandBufferPool.acquireObject(); + mvkCmdBuff->init(pAllocateInfo); + _commandBuffers.insert(mvkCmdBuff); pCmdBuffer[cbIdx] = mvkCmdBuff->getVkCommandBuffer(); if (rslt == VK_SUCCESS) { rslt = mvkCmdBuff->getConfigurationResult(); } } @@ -57,25 +64,66 @@ VkResult MVKCommandPool::allocateCommandBuffers(const VkCommandBufferAllocateInf void MVKCommandPool::freeCommandBuffers(uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers) { for (uint32_t cbIdx = 0; cbIdx < commandBufferCount; cbIdx++) { - VkCommandBuffer cmdBuff = pCommandBuffers[cbIdx]; - if (cmdBuff) { MVKCommandBuffer::getMVKCommandBuffer(cmdBuff)->destroy(); } + freeCommandBuffer(MVKCommandBuffer::getMVKCommandBuffer(pCommandBuffers[cbIdx])); } } +void MVKCommandPool::freeCommandBuffer(MVKCommandBuffer* mvkCmdBuff) { + if ( !mvkCmdBuff ) { return; } + + mvkCmdBuff->reset(VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); + _commandBuffers.erase(mvkCmdBuff); + _commandBufferPool.returnObject(mvkCmdBuff); +} + id MVKCommandPool::newMTLCommandBuffer(uint32_t queueIndex) { return [[_device->getQueue(_queueFamilyIndex, queueIndex)->getMTLCommandQueue() commandBuffer] retain]; } void MVKCommandPool::trim() { - // TODO: Implement. -} - -void MVKCommandPool::addCommandBuffer(MVKCommandBuffer* cmdBuffer) { - _commandBuffers.insert(cmdBuffer); -} - -void MVKCommandPool::removeCommandBuffer(MVKCommandBuffer* cmdBuffer) { - _commandBuffers.erase(cmdBuffer); + _commandBufferPool.clear(); + _commandEncodingPool.clear(); + _cmdPipelineBarrierPool.clear(); + _cmdBindPipelinePool.clear(); + _cmdBeginRenderPassPool.clear(); + _cmdNextSubpassPool.clear(); + _cmdExecuteCommandsPool.clear(); + _cmdEndRenderPassPool.clear(); + _cmdBindDescriptorSetsPool.clear(); + _cmdSetViewportPool.clear(); + _cmdSetScissorPool.clear(); + _cmdSetLineWidthPool.clear(); + _cmdSetDepthBiasPool.clear(); + _cmdSetBlendConstantsPool.clear(); + _cmdSetDepthBoundsPool.clear(); + _cmdSetStencilCompareMaskPool.clear(); + _cmdSetStencilWriteMaskPool.clear(); + _cmdSetStencilReferencePool.clear(); + _cmdBindVertexBuffersPool.clear(); + _cmdBindIndexBufferPool.clear(); + _cmdDrawPool.clear(); + _cmdDrawIndexedPool.clear(); + _cmdDrawIndirectPool.clear(); + _cmdDrawIndexedIndirectPool.clear(); + _cmdCopyImagePool.clear(); + _cmdBlitImagePool.clear(); + _cmdResolveImagePool.clear(); + _cmdFillBufferPool.clear(); + _cmdUpdateBufferPool.clear(); + _cmdCopyBufferPool.clear(); + _cmdBufferImageCopyPool.clear(); + _cmdClearAttachmentsPool.clear(); + _cmdClearImagePool.clear(); + _cmdBeginQueryPool.clear(); + _cmdEndQueryPool.clear(); + _cmdWriteTimestampPool.clear(); + _cmdResetQueryPoolPool.clear(); + _cmdCopyQueryPoolResultsPool.clear(); + _cmdPushConstantsPool.clear(); + _cmdDispatchPool.clear(); + _cmdDispatchIndirectPool.clear(); + _cmdPushDescriptorSetPool.clear(); + _cmdPushSetWithTemplatePool.clear(); } @@ -83,6 +131,7 @@ void MVKCommandPool::removeCommandBuffer(MVKCommandBuffer* cmdBuffer) { MVKCommandPool::MVKCommandPool(MVKDevice* device, const VkCommandPoolCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device), + _commandBufferPool(device), _commandEncodingPool(device), _queueFamilyIndex(pCreateInfo->queueFamilyIndex), _cmdPipelineBarrierPool(this, true), @@ -128,7 +177,8 @@ MVKCommandPool::MVKCommandPool(MVKDevice* device, _cmdPushSetWithTemplatePool(this, true) {} -// TODO: Destroying a command pool implicitly destroys all command buffers and commands created from it. - -MVKCommandPool::~MVKCommandPool() {} +MVKCommandPool::~MVKCommandPool() { + auto cmdBuffs = _commandBuffers; + for (auto& cb : cmdBuffs) { freeCommandBuffer(cb); } +} diff --git a/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.h b/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.h index 7bcf2572..d3158639 100644 --- a/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.h +++ b/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.h @@ -55,7 +55,7 @@ public: /** * Instances of this class can participate in a linked list or pool. When so participating, - * this is a reference to the next command in the linked list. This value should only be + * this is a reference to the next instance in the linked list. This value should only be * managed and set by the linked list. */ MVKMTLBufferAllocation* _next = nullptr; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h index 4c9e41cb..3b7efb15 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h @@ -313,8 +313,8 @@ public: protected: uint32_t _maxSets; + uint32_t _allocatedSetCount; std::forward_list _allocatedSets; - size_t _allocatedSetCount; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm index 6377ce4e..346dfaa6 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm @@ -868,6 +868,7 @@ MVKDescriptorSet::MVKDescriptorSet(MVKDevice* device, VkResult MVKDescriptorPool::allocateDescriptorSets(uint32_t count, const VkDescriptorSetLayout* pSetLayouts, VkDescriptorSet* pDescriptorSets) { +// MVKLogDebug("Descriptor pool %p allocating %d descriptor sets for total %d.", this, count, _allocatedSetCount + count); if (_allocatedSetCount + count > _maxSets) { if (_device->_enabledExtensions.vk_KHR_maintenance1.enabled) { return VK_ERROR_OUT_OF_POOL_MEMORY; // Failure is an acceptable test...don't log as error. @@ -888,6 +889,7 @@ VkResult MVKDescriptorPool::allocateDescriptorSets(uint32_t count, } VkResult MVKDescriptorPool::freeDescriptorSets(uint32_t count, const VkDescriptorSet* pDescriptorSets) { +// MVKLogDebug("Descriptor pool %p freeing %d descriptor sets from total %d.", this, count, _allocatedSetCount); for (uint32_t dsIdx = 0; dsIdx < count; dsIdx++) { MVKDescriptorSet* mvkDS = (MVKDescriptorSet*)pDescriptorSets[dsIdx]; if (mvkDS) { @@ -900,6 +902,7 @@ VkResult MVKDescriptorPool::freeDescriptorSets(uint32_t count, const VkDescripto } VkResult MVKDescriptorPool::reset(VkDescriptorPoolResetFlags flags) { +// MVKLogDebug("Descriptor pool %p resetting with %d descriptor sets.", this, _allocatedSetCount); mvkDestroyContainerContents(_allocatedSets); _allocatedSetCount = 0; return VK_SUCCESS; @@ -909,12 +912,13 @@ MVKDescriptorPool::MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device) { _maxSets = pCreateInfo->maxSets; _allocatedSetCount = 0; +// MVKLogDebug("Descriptor pool %p created with max %d sets.", this, _maxSets); } // TODO: Destroying a descriptor pool implicitly destroys all descriptor sets created from it. MVKDescriptorPool::~MVKDescriptorPool() { -// MVKLogDebug("Pool %p destroyed with %d descriptor sets.", this, _allocatedSetCount); +// MVKLogDebug("Descriptor pool %p destroyed with %d descriptor sets.", this, _allocatedSetCount); reset(0); } diff --git a/MoltenVK/MoltenVK/Utility/MVKBaseObject.h b/MoltenVK/MoltenVK/Utility/MVKBaseObject.h index f15aeac3..6827bf15 100644 --- a/MoltenVK/MoltenVK/Utility/MVKBaseObject.h +++ b/MoltenVK/MoltenVK/Utility/MVKBaseObject.h @@ -95,7 +95,7 @@ public: * This is the compliment of the getVkHandle() method. */ static inline MVKDispatchableObject* getDispatchableObject(void* vkHandle) { - return ((MVKDispatchableObjectICDRef*)vkHandle)->mvkObject; + return vkHandle ? ((MVKDispatchableObjectICDRef*)vkHandle)->mvkObject : nullptr; } protected: diff --git a/MoltenVK/MoltenVK/Utility/MVKObjectPool.h b/MoltenVK/MoltenVK/Utility/MVKObjectPool.h index 4e243e4a..ba0d09ee 100644 --- a/MoltenVK/MoltenVK/Utility/MVKObjectPool.h +++ b/MoltenVK/MoltenVK/Utility/MVKObjectPool.h @@ -76,6 +76,8 @@ public: * aquireObject() and returnObject() must be made from the same thread. */ void returnObject(T* obj) { + if ( !obj ) { return; } + if (_isPooling) { if (_tail) { _tail->_next = obj; } obj->_next = VK_NULL_HANDLE;