From 11c8b80f4b4e9933e98715879ea035207481bc21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 14 Oct 2024 15:14:41 +0200 Subject: [PATCH] macOS: Avoid creating 0x0 size IOSurface in backing-store During screen attach/detach, we may end up in a situation where the window has a 0x0 size, and we end up painting to the window, in which case we were trying to create an IOSurface of size 0x0. This resulted in the creation failing, triggering an assert. We now guard the surface creation with a check for the backing store size being non-empty, and for empty sizes we fall back to a plain null-QImage for our paint device. Fixes: QTBUG-128731 Pick-to: 6.5 6.2 Invaluable-research-by: Viktor Arvidsson Change-Id: I06ea582c87fb0d359387ef9495451801612701c9 Reviewed-by: Volker Hilsheimer (cherry picked from commit 58caa18d2ff1a67e16f960f5bd6b804cdaec4063) Reviewed-by: Qt Cherry-pick Bot --- .../platforms/cocoa/qcocoabackingstore.mm | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 68091cd1b14..64794408c90 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -88,6 +88,13 @@ void QCALayerBackingStore::beginPaint(const QRegion ®ion) qCInfo(lcQpaBackingStore) << "Beginning paint of" << region << "into backingstore of" << m_requestedSize; + if (m_requestedSize.isEmpty()) { + // We can't create IOSurfaces with and empty size, so instead reset our back buffer + qCDebug(lcQpaBackingStore) << "Size is empty, throwing away back buffer"; + m_buffers.back().reset(nullptr); + return; + } + ensureBackBuffer(); // Find an unused back buffer, or reserve space for a new one const bool bufferWasRecreated = recreateBackBufferIfNeeded(); @@ -241,12 +248,19 @@ bool QCALayerBackingStore::recreateBackBufferIfNeeded() QPaintDevice *QCALayerBackingStore::paintDevice() { - Q_ASSERT(m_buffers.back()); - return m_buffers.back()->asImage(); + if (m_buffers.back()) { + return m_buffers.back()->asImage(); + } else { + static QImage fallbackDevice; + return &fallbackDevice; + } } void QCALayerBackingStore::endPaint() { + if (!m_buffers.back()) + return; + qCInfo(lcQpaBackingStore) << "Paint ended. Back buffer valid region is now" << m_buffers.back()->validRegion(); m_buffers.back()->unlock(); @@ -317,7 +331,7 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion ®ion, Q_UNUSED(offset); if (!m_buffers.back()) { - qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first"; + qCWarning(lcQpaBackingStore) << "Flush requested with no back buffer. Ignoring."; return; } @@ -444,7 +458,7 @@ QPlatformBackingStore::FlushResult QCALayerBackingStore::rhiFlush(QWindow *windo bool translucentBackground) { if (!m_buffers.back()) { - qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first"; + qCWarning(lcQpaBackingStore) << "Flush requested with no back buffer. Ignoring."; return FlushFailed; }