Fix small memory issues with MVKPresentableSwapchainImage.

- Fix Metal validation error caused by CAMetalDrawable released before
  MTLCommandBuffer is finished using it.
- When presenting, MVKPresentableSwapchainImage retains in-flight
  CAMetalDrawable until MTLCommandBuffer completion.

- Fix memory leak of MVKFences and MVKSemaphores when a
  swapchain image is acquired more than it is presented.
- Force MVKPresentableSwapchainImage to untrack any tracked fences or
  semaphores when it is destroyed.

- Update MoltenVK version to 1.2.2.
This commit is contained in:
Bill Hollings 2022-12-29 21:50:04 -05:00
parent 2960554d3a
commit be51089f25
4 changed files with 33 additions and 2 deletions

View File

@ -13,6 +13,18 @@ Copyright (c) 2015-2022 [The Brenwill Workshop Ltd.](http://www.brenwill.com)
MoltenVK 1.2.2
--------------
Released TBD
- Fix Metal validation error caused by `CAMetalDrawable` released before
`MTLCommandBuffer` is finished using it.
- Fix memory leak of `MVKFences` and `MVKSemaphores` when
a swapchain image is acquired more than it is presented.
MoltenVK 1.2.1
--------------

View File

@ -51,7 +51,7 @@ typedef unsigned long MTLArgumentBuffersTier;
*/
#define MVK_VERSION_MAJOR 1
#define MVK_VERSION_MINOR 2
#define MVK_VERSION_PATCH 1
#define MVK_VERSION_PATCH 2
#define MVK_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch))
#define MVK_VERSION MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH)

View File

@ -473,6 +473,7 @@ protected:
void signalPresentationSemaphore(const MVKSwapchainSignaler& signaler, id<MTLCommandBuffer> mtlCmdBuff);
static void markAsTracked(const MVKSwapchainSignaler& signaler);
static void unmarkAsTracked(const MVKSwapchainSignaler& signaler);
void untrackAllSignalers();
void renderWatermark(id<MTLCommandBuffer> mtlCmdBuff);
id<CAMetalDrawable> _mtlDrawable;

View File

@ -1287,6 +1287,18 @@ void MVKPresentableSwapchainImage::unmarkAsTracked(const MVKSwapchainSignaler& s
if (signaler.fence) { signaler.fence->release(); }
}
// Untrack any signalers that are still tracking, releasing the fences and semaphores.
void MVKPresentableSwapchainImage::untrackAllSignalers() {
lock_guard<mutex> lock(_availabilityLock);
if ( !_availability.isAvailable ) {
unmarkAsTracked(_preSignaler);
for (auto& sig : _availabilitySignalers) {
unmarkAsTracked(sig);
}
}
}
#pragma mark Metal
@ -1345,9 +1357,12 @@ void MVKPresentableSwapchainImage::presentCAMetalDrawable(id<MTLCommandBuffer> m
_availabilitySignalers.erase(sigIter);
}
// Ensure this image is not destroyed while awaiting MTLCommandBuffer completion
// Ensure this image and the drawable are not destroyed while awaiting MTLCommandBuffer completion.
// We retain the drawable separately because new drawable might be acquired by this image by then.
retain();
[mtlDrwbl retain];
[mtlCmdBuff addCompletedHandler: ^(id<MTLCommandBuffer> mcb) {
[mtlDrwbl release];
makeAvailable(signaler);
release();
}];
@ -1405,8 +1420,11 @@ MVKPresentableSwapchainImage::MVKPresentableSwapchainImage(MVKDevice* device,
_preSignaler = MVKSwapchainSignaler{nullptr, nullptr, 0};
}
// Unsignaled signalers will exist if this image is acquired more than it is presented.
// Ensure they are untracked so the fences and semaphores will be released.
MVKPresentableSwapchainImage::~MVKPresentableSwapchainImage() {
releaseMetalDrawable();
untrackAllSignalers();
}