Allocate MVKCommandBuffers from a pool within MVKCommandPool.
Add support for trimming command pools.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommand.h b/MoltenVK/MoltenVK/Commands/MVKCommand.h
index b3dd8f3..00ba38a 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommand.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommand.h
@@ -77,7 +77,7 @@
/**
* 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 9c06290..c28a398 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 <vector>
#include <unordered_map>
@@ -90,15 +91,15 @@
/**
* 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 @@
protected:
friend class MVKCommandEncoder;
+ friend class MVKCommandPool;
+ void init(const VkCommandBufferAllocateInfo* pAllocateInfo);
bool canExecute();
bool canPrefill();
void prefill();
@@ -141,6 +144,33 @@
#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<MVKCommandBuffer> {
+
+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<MVKCommandBuffer>(isPooling), _device(device) {}
+
+protected:
+ MVKDevice* _device;
+};
+
+
+#pragma mark -
#pragma mark MVKCommandEncoder
// The following commands can be issued both inside and outside a renderpass and their state must
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
index edcf6d1..f997108 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
@@ -175,11 +175,9 @@
#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() {
reset(0);
- _commandPool->removeCommandBuffer(this);
}
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
index ce9779d..8e54826 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 <vector>
class MVKCommandEncoder;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h
index 37c2567..1373cb0 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h
@@ -97,6 +97,9 @@
/** Returns a MTLComputePipelineState for filling a buffer. */
id<MTLComputePipelineState> 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 74e82d6..b1d9462 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm
@@ -105,6 +105,12 @@
MVK_ENC_REZ_ACCESS(_mtlFillBufferComputePipelineState, newCmdFillBufferMTLComputePipelineState());
}
+void MVKCommandEncodingPool::clear() {
+ lock_guard<mutex> 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 e8278b4..5ded1d5 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 @@
~MVKCommandPool() override;
-private:
- friend class MVKCommandBuffer;
+protected:
+ void freeCommandBuffer(MVKCommandBuffer* mvkCmdBuff);
- void addCommandBuffer(MVKCommandBuffer* cmdBuffer);
- void removeCommandBuffer(MVKCommandBuffer* cmdBuffer);
-
+ MVKCommandBufferPool _commandBufferPool;
std::unordered_set<MVKCommandBuffer*> _commandBuffers;
MVKCommandEncodingPool _commandEncodingPool;
uint32_t _queueFamilyIndex;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm b/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm
index d33b9e5..559b348 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm
@@ -33,9 +33,14 @@
// 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 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 @@
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<MTLCommandBuffer> 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 @@
MVKCommandPool::MVKCommandPool(MVKDevice* device,
const VkCommandPoolCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device),
+ _commandBufferPool(device),
_commandEncodingPool(device),
_queueFamilyIndex(pCreateInfo->queueFamilyIndex),
_cmdPipelineBarrierPool(this, true),
@@ -128,7 +177,8 @@
_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 7bcf257..d315863 100644
--- a/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.h
+++ b/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.h
@@ -55,7 +55,7 @@
/**
* 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/Utility/MVKBaseObject.h b/MoltenVK/MoltenVK/Utility/MVKBaseObject.h
index f15aeac..6827bf1 100644
--- a/MoltenVK/MoltenVK/Utility/MVKBaseObject.h
+++ b/MoltenVK/MoltenVK/Utility/MVKBaseObject.h
@@ -95,7 +95,7 @@
* 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 4e243e4..ba0d09e 100644
--- a/MoltenVK/MoltenVK/Utility/MVKObjectPool.h
+++ b/MoltenVK/MoltenVK/Utility/MVKObjectPool.h
@@ -76,6 +76,8 @@
* 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;