Fix memory leak when pre-filling MTLCommandBuffers.
Wrap MVKCommandBuffer::prefill() in autoreleasepool. For non-reusable MVKCommandBuffers, release command instances once prefilling is done to reduce memory pressure.
This commit is contained in:
parent
30658f05f5
commit
7658bccfba
@ -17,16 +17,15 @@ For best results, use a Markdown reader.*
|
|||||||
MoltenVK 1.0.41
|
MoltenVK 1.0.41
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
Released TBD
|
Released 2020/03/30
|
||||||
|
|
||||||
- Fix issue where immutable samplers are removed during descriptor update.
|
- Fix issue where immutable samplers are removed during descriptor update.
|
||||||
- Guard against Metal validation assertion from reuse of query number
|
- Guard against Metal validation assertion from reuse of query number within a single `MTLRenderEncoder`.
|
||||||
within a single `MTLRenderEncoder`.
|
|
||||||
- Increase value of `VkPhysicalDeviceLimits::minStorageBufferOffsetAlignment`
|
- Increase value of `VkPhysicalDeviceLimits::minStorageBufferOffsetAlignment`
|
||||||
to `16` to avoid Metal validation assertions.
|
to `16` to avoid Metal validation assertions.
|
||||||
- Add ability to disable command memory pooling using `MVK_CONFIG_USE_COMMAND_POOLING`
|
- Add ability to disable command memory pooling using `MVK_CONFIG_USE_COMMAND_POOLING`
|
||||||
environment variable.
|
environment variable.
|
||||||
|
- Fix memory leak when pre-filling `MTLCommandBuffers` using `MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,6 +152,7 @@ protected:
|
|||||||
bool canPrefill();
|
bool canPrefill();
|
||||||
void prefill();
|
void prefill();
|
||||||
void clearPrefilledMTLCommandBuffer();
|
void clearPrefilledMTLCommandBuffer();
|
||||||
|
void releaseCommands();
|
||||||
|
|
||||||
MVKCommand* _head = nullptr;
|
MVKCommand* _head = nullptr;
|
||||||
MVKCommand* _tail = nullptr;
|
MVKCommand* _tail = nullptr;
|
||||||
|
@ -54,18 +54,20 @@ VkResult MVKCommandBuffer::begin(const VkCommandBufferBeginInfo* pBeginInfo) {
|
|||||||
return getConfigurationResult();
|
return getConfigurationResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult MVKCommandBuffer::reset(VkCommandBufferResetFlags flags) {
|
void MVKCommandBuffer::releaseCommands() {
|
||||||
MVKCommand* cmd = _head;
|
MVKCommand* cmd = _head;
|
||||||
while (cmd) {
|
while (cmd) {
|
||||||
MVKCommand* nextCmd = cmd->_next; // Establish next before returning current to pool.
|
MVKCommand* nextCmd = cmd->_next; // Establish next before returning current to pool.
|
||||||
cmd->returnToPool();
|
cmd->returnToPool();
|
||||||
cmd = nextCmd;
|
cmd = nextCmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearPrefilledMTLCommandBuffer();
|
|
||||||
|
|
||||||
_head = nullptr;
|
_head = nullptr;
|
||||||
_tail = nullptr;
|
_tail = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult MVKCommandBuffer::reset(VkCommandBufferResetFlags flags) {
|
||||||
|
clearPrefilledMTLCommandBuffer();
|
||||||
|
releaseCommands();
|
||||||
_doesContinueRenderPass = false;
|
_doesContinueRenderPass = false;
|
||||||
_canAcceptCommands = false;
|
_canAcceptCommands = false;
|
||||||
_isReusable = false;
|
_isReusable = false;
|
||||||
@ -140,18 +142,24 @@ bool MVKCommandBuffer::canExecute() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we can, prefill a MTLCommandBuffer with the commands in this command buffer
|
// If we can, prefill a MTLCommandBuffer with the commands in this command buffer.
|
||||||
|
// Wrap in autorelease pool to capture autoreleased Metal encoding activity.
|
||||||
void MVKCommandBuffer::prefill() {
|
void MVKCommandBuffer::prefill() {
|
||||||
|
@autoreleasepool {
|
||||||
|
clearPrefilledMTLCommandBuffer();
|
||||||
|
|
||||||
clearPrefilledMTLCommandBuffer();
|
if ( !canPrefill() ) { return; }
|
||||||
|
|
||||||
if ( !canPrefill() ) { return; }
|
uint32_t qIdx = 0;
|
||||||
|
_prefilledMTLCmdBuffer = _commandPool->newMTLCommandBuffer(qIdx); // retain
|
||||||
|
|
||||||
uint32_t qIdx = 0;
|
MVKCommandEncoder encoder(this);
|
||||||
_prefilledMTLCmdBuffer = _commandPool->newMTLCommandBuffer(qIdx); // retain
|
encoder.encode(_prefilledMTLCmdBuffer);
|
||||||
|
|
||||||
MVKCommandEncoder encoder(this);
|
// Once encoded onto Metal, if this command buffer is not reusable, we don't need the
|
||||||
encoder.encode(_prefilledMTLCmdBuffer);
|
// MVKCommand instances anymore, so release them in order to reduce memory pressure.
|
||||||
|
if ( !_isReusable ) { releaseCommands(); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MVKCommandBuffer::canPrefill() {
|
bool MVKCommandBuffer::canPrefill() {
|
||||||
|
@ -249,7 +249,7 @@ void MVKQueueCommandBufferSubmission::setActiveMTLCommandBuffer(id<MTLCommandBuf
|
|||||||
|
|
||||||
if (_activeMTLCommandBuffer) { commitActiveMTLCommandBuffer(); }
|
if (_activeMTLCommandBuffer) { commitActiveMTLCommandBuffer(); }
|
||||||
|
|
||||||
_activeMTLCommandBuffer = mtlCmdBuff; // not retained
|
_activeMTLCommandBuffer = [mtlCmdBuff retain]; // retained to handle prefilled
|
||||||
[_activeMTLCommandBuffer enqueue];
|
[_activeMTLCommandBuffer enqueue];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,8 +276,9 @@ void MVKQueueCommandBufferSubmission::commitActiveMTLCommandBuffer(bool signalCo
|
|||||||
|
|
||||||
// Use temp var because callback may destroy this instance before this function ends.
|
// Use temp var because callback may destroy this instance before this function ends.
|
||||||
id<MTLCommandBuffer> mtlCmdBuff = _activeMTLCommandBuffer;
|
id<MTLCommandBuffer> mtlCmdBuff = _activeMTLCommandBuffer;
|
||||||
_activeMTLCommandBuffer = nil; // not retained
|
_activeMTLCommandBuffer = nil;
|
||||||
[mtlCmdBuff commit];
|
[mtlCmdBuff commit];
|
||||||
|
[mtlCmdBuff release]; // retained
|
||||||
}
|
}
|
||||||
|
|
||||||
void MVKQueueCommandBufferSubmission::finish() {
|
void MVKQueueCommandBufferSubmission::finish() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user