summaryrefslogtreecommitdiffstats
path: root/src/gui/rhi/qrhimetal.mm
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2021-02-02 17:07:49 +0100
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2021-02-05 11:50:06 +0100
commit0cba6a27e27b160e2805c5cc29b108bf6e7fde20 (patch)
treeb7410df8bf5ff42f6fe73816084bf315cc5dfce4 /src/gui/rhi/qrhimetal.mm
parent0a86e7fb6d83559905146fc8ba43eaba8da780ed (diff)
rhi: metal: Manually manage drawable lifetime
The drawable returned from nextDrawable is autoreleased, which means unless we explicitly retain it we have no guarantee that it will stay alive long enough to be used again in endFrame(). For example, if the user had an autorelease-pool in their custom render code, where the call to beginPass() happens, the drawable would be released when that pool went out of scope. The only reason we didn't hit this yet is due to the default autorelease-pool being at the level of the runloop, so the drawable happened to outlive the rendering of a single frame. An advantage of manually managing the lifetime of the drawable is also that we can release it immediately after being done with it, instead of waiting until the autorelease-pool drains. Change-Id: Ie6fd271adbe1121eb947bb7075142f1a6c81175d Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io> Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src/gui/rhi/qrhimetal.mm')
-rw-r--r--src/gui/rhi/qrhimetal.mm11
1 files changed, 8 insertions, 3 deletions
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm
index 9eb0ba75b5..7151741f2e 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -322,7 +322,7 @@ struct QMetalSwapChainData
#else
CAMetalLayer *layer = nullptr;
#endif
- id<CAMetalDrawable> curDrawable;
+ id<CAMetalDrawable> curDrawable = nil;
dispatch_semaphore_t sem[QMTL_FRAMES_IN_FLIGHT];
MTLRenderPassDescriptor *rp = nullptr;
id<MTLTexture> msaaTex[QMTL_FRAMES_IN_FLIGHT];
@@ -1457,7 +1457,7 @@ QRhi::FrameOpResult QRhiMetal::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
[swapChainD->cbWrapper.d->cb presentDrawable: swapChainD->d->curDrawable];
// Must not hold on to the drawable, regardless of needsPresent.
- // (internally it is autoreleased or something, it seems)
+ [swapChainD->d->curDrawable release];
swapChainD->d->curDrawable = nil;
__block int thisFrameSlot = currentFrameSlot;
@@ -1964,10 +1964,11 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
Q_ASSERT(currentSwapChain);
QMetalSwapChain *swapChainD = QRHI_RES(QMetalSwapChain, currentSwapChain);
if (!swapChainD->d->curDrawable) {
+ QMacAutoReleasePool pool;
#ifdef TARGET_IPHONE_SIMULATOR
if (@available(ios 13.0, *))
#endif
- swapChainD->d->curDrawable = [swapChainD->d->layer nextDrawable];
+ swapChainD->d->curDrawable = [[swapChainD->d->layer nextDrawable] retain];
}
if (!swapChainD->d->curDrawable) {
qWarning("No drawable");
@@ -3807,6 +3808,9 @@ void QMetalSwapChain::destroy()
d->layer = nullptr;
+ [d->curDrawable release];
+ d->curDrawable = nil;
+
QRHI_RES_RHI(QRhiMetal);
rhiD->swapchains.remove(this);
@@ -3940,6 +3944,7 @@ bool QMetalSwapChain::createOrResize()
[d->layer setDevice: rhiD->d->dev];
+ [d->curDrawable release];
d->curDrawable = nil;
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) {