rhi: metal: Do not hold on to the drawable when not presenting

The Quick render loops do SkipPresent occasionally, and it all seemed
to work with the threaded one because we lack an autorelease pool on
the SG render thread. (to be corrected separately) The basic one ended
up crashing sometimes, however. Holding on to the drawable is incorrect.

Fixes: QTBUG-76953
Change-Id: I0d0ec6d09aa209d2c848d7a9dbd9b15916fe23ab
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
Laszlo Agocs 2019-07-26 13:16:57 +02:00
parent a093e4e3c2
commit c955426945
3 changed files with 17 additions and 4 deletions

View File

@ -260,6 +260,12 @@ QT_BEGIN_NAMESPACE
tied to those concepts, however, and is thus a topic that is currently out tied to those concepts, however, and is thus a topic that is currently out
of scope, but may be introduced in the future. of scope, but may be introduced in the future.
\note The Metal backend requires that an autorelease pool is available on
the rendering thread, ideally wrapping each iteration of the render loop.
This needs no action from the users of QRhi when rendering on the main
(gui) thread, but becomes important when a separate, dedicated render
thread is used.
\section3 Resource synchronization \section3 Resource synchronization
QRhi does not expose APIs for resource barriers or image layout QRhi does not expose APIs for resource barriers or image layout

View File

@ -57,7 +57,8 @@ QT_BEGIN_NAMESPACE
Textures are Private (device local) and a host visible staging buffer is Textures are Private (device local) and a host visible staging buffer is
used to upload data to them. Does not rely on strong objects refs from used to upload data to them. Does not rely on strong objects refs from
command buffers but does rely on the automatic resource tracking of the command buffers but does rely on the automatic resource tracking of the
command encoders. command encoders. Assumes that an autorelease pool (ideally per frame) is
available on the thread on which QRhi is used.
*/ */
#if __has_feature(objc_arc) #if __has_feature(objc_arc)
@ -1214,10 +1215,12 @@ QRhi::FrameOpResult QRhiMetal::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
Q_ASSERT(currentSwapChain == swapChainD); Q_ASSERT(currentSwapChain == swapChainD);
const bool needsPresent = !flags.testFlag(QRhi::SkipPresent); const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
if (needsPresent) { if (needsPresent)
[swapChainD->cbWrapper.d->cb presentDrawable: swapChainD->d->curDrawable]; [swapChainD->cbWrapper.d->cb presentDrawable: swapChainD->d->curDrawable];
swapChainD->d->curDrawable = nil;
} // Must not hold on to the drawable, regardless of needsPresent.
// (internally it is autoreleased or something, it seems)
swapChainD->d->curDrawable = nil;
__block int thisFrameSlot = currentFrameSlot; __block int thisFrameSlot = currentFrameSlot;
[swapChainD->cbWrapper.d->cb addCompletedHandler: ^(id<MTLCommandBuffer>) { [swapChainD->cbWrapper.d->cb addCompletedHandler: ^(id<MTLCommandBuffer>) {

View File

@ -290,6 +290,10 @@ struct Renderer
void Thread::run() void Thread::run()
{ {
while (active) { while (active) {
#ifdef Q_OS_DARWIN
QMacAutoReleasePool autoReleasePool;
#endif
if (pendingRender) { if (pendingRender) {
pendingRender = false; pendingRender = false;
renderer->render(pendingRenderIsNewExpose, false); renderer->render(pendingRenderIsNewExpose, false);