From 8b9c25998fadc2c2c6ecbd907a8bc793af230fdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 16 Oct 2024 11:19:54 +0200 Subject: [PATCH] macOS: Release main thread transaction block as soon as we're done with it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 9122d826d25b9afab230771dc86e1ff6158e6cbc we're presenting drawables on the main thread, even those produced on the Qt Quick render thread, if we are part of a displayLayer call, as we're then presenting the Metal layer within a Core Animation transaction. We do this by assigning a block to the layer, that we then call on the main thread in displayLayer. This block retains the drawable, so when we're done calling the block we need to dispose of the block as soon as possible, to avoid stalls due to running out of drawables. To improve on this we add a local auto-release pool around the clearing of the main thread transaction block. In the case of displayLayer we need to take care to also include the referencing of the transaction block in the auto-release pool, as that makes a separate auto-released copy of the block (and hence also the drawable). Task-number: QTBUG-129839 Change-Id: I7663862c63977adab7b1f22a136416c8bc910c6e Reviewed-by: Laszlo Agocs Reviewed-by: Morten Johan Sørvig (cherry picked from commit 72e4cb96700cd93213d5c3ecb14cd92f4c069c65) Reviewed-by: Qt Cherry-pick Bot --- src/gui/platform/darwin/qmetallayer.mm | 12 +++++++---- .../platforms/cocoa/qnsview_drawing.mm | 21 ++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/gui/platform/darwin/qmetallayer.mm b/src/gui/platform/darwin/qmetallayer.mm index e8a27a7b067..082bde95b5b 100644 --- a/src/gui/platform/darwin/qmetallayer.mm +++ b/src/gui/platform/darwin/qmetallayer.mm @@ -62,10 +62,14 @@ QT_USE_NAMESPACE - (id)nextDrawable { - // Drop the presentation block early, so that if the main thread for - // some reason doesn't handle the presentation, the block won't hold on - // to a drawable unnecessarily. - self.mainThreadPresentation = nil; + { + // Drop the presentation block early, so that if the main thread for + // some reason doesn't handle the presentation, the block won't hold on + // to a drawable unnecessarily. + QMacAutoReleasePool pool; + self.mainThreadPresentation = nil; + } + return [super nextDrawable]; } diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm index c903bcd5359..51e6a19c488 100644 --- a/src/plugins/platforms/cocoa/qnsview_drawing.mm +++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm @@ -245,11 +245,22 @@ handleExposeEvent(); - // If the expose event resulted in a secondary thread requesting that its - // drawable should be presented on the main thread with transaction, do so. - if (auto mainThreadPresentation = qtMetalLayer.mainThreadPresentation) { - mainThreadPresentation(); - qtMetalLayer.mainThreadPresentation = nil; + { + // Clearing the mainThreadPresentation below will auto-release the + // block held by the property, which in turn holds on to drawables, + // so we want to clean up as soon as possible, to prevent stalling + // when requesting new drawables. But merely referencing the block + // below for the nil-check will make another auto-released copy of + // the block, so the scope of the auto-release pool needs to include + // that check as well. + QMacAutoReleasePool pool; + + // If the expose event resulted in a secondary thread requesting that its + // drawable should be presented on the main thread with transaction, do so. + if (auto mainThreadPresentation = qtMetalLayer.mainThreadPresentation) { + mainThreadPresentation(); + qtMetalLayer.mainThreadPresentation = nil; + } } qtMetalLayer.presentsWithTransaction = presentedWithTransaction;