From 4ffdf2270a1341a703b591eb79f40dcc6033a3f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 4 Nov 2021 13:44:10 +0100 Subject: macOS: Rename QCALayerBackingStore::prepareForFlush() The need to finalize the back buffer isn't limited to flushing. Pick-to: 6.2 Change-Id: I98b04ab49ec27ea536e99462deab8d48a8e40e82 Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoabackingstore.h | 2 +- src/plugins/platforms/cocoa/qcocoabackingstore.mm | 87 +++++++++++++---------- 2 files changed, 50 insertions(+), 39 deletions(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index 28adbaee41..2deeac4db2 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -107,7 +107,7 @@ private: void ensureBackBuffer(); bool recreateBackBufferIfNeeded(); - bool prepareForFlush(); + void finalizeBackBuffer(); void backingPropertiesChanged(); QMacNotificationObserver m_backingPropertiesObserver; diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 21ccbcbb00..70bc49071f 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -245,6 +245,9 @@ void QCALayerBackingStore::endPaint() { qCInfo(lcQpaBackingStore) << "Paint ended. Back buffer valid region is now" << m_buffers.back()->validRegion(); m_buffers.back()->unlock(); + + // Since we can have multiple begin/endPaint rounds before a flush + // we defer finalizing the back buffer until its content is needed. } void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion ®ion, const QPoint &offset) @@ -252,8 +255,12 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion ®ion, Q_UNUSED(region); Q_UNUSED(offset); - if (!prepareForFlush()) + if (!m_buffers.back()) { + qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first"; return; + } + + finalizeBackBuffer(); if (flushedWindow != window()) { flushSubWindow(flushedWindow); @@ -370,8 +377,12 @@ void QCALayerBackingStore::windowDestroyed(QObject *object) void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, bool translucentBackground) { - if (!prepareForFlush()) + if (!m_buffers.back()) { + qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first"; return; + } + + finalizeBackBuffer(); QPlatformBackingStore::composeAndFlush(window, region, offset, textures, translucentBackground); } @@ -379,9 +390,11 @@ void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion ®io QImage QCALayerBackingStore::toImage() const { - if (!const_cast(this)->prepareForFlush()) + if (!m_buffers.back()) return QImage(); + const_cast(this)->finalizeBackBuffer(); + // We need to make a copy here, as the returned image could be used just // for reading, in which case it won't detach, and then the underlying // image data might change under the feet of the client when we re-use @@ -429,55 +442,53 @@ void QCALayerBackingStore::updateDirtyStates(const QRegion &paintedRegion) } } -bool QCALayerBackingStore::prepareForFlush() +void QCALayerBackingStore::finalizeBackBuffer() { - if (!m_buffers.back()) { - qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first"; - return false; - } - // After painting, the back buffer is only guaranteed to have content for the painted // region, and may still have dirty areas that need to be synced up with the front buffer, // if we have one. We know that the front buffer is always up to date. - if (m_buffers.back()->isDirty() && m_buffers.front() != m_buffers.back()) { - QRegion preserveRegion = m_buffers.back()->dirtyRegion; - qCDebug(lcQpaBackingStore) << "Preserving" << preserveRegion << "from front to back buffer"; - m_buffers.front()->lock(QPlatformGraphicsBuffer::SWReadAccess); - const QImage *frontBuffer = m_buffers.front()->asImage(); + if (!m_buffers.back()->isDirty()) + return; - const QRect frontSurfaceBounds(QPoint(0, 0), m_buffers.front()->size()); - const qreal sourceDevicePixelRatio = frontBuffer->devicePixelRatio(); + if (m_buffers.front() == m_buffers.back()) + return; // Nothing to preserve from - m_buffers.back()->lock(QPlatformGraphicsBuffer::SWWriteAccess); - QPainter painter(m_buffers.back()->asImage()); - painter.setCompositionMode(QPainter::CompositionMode_Source); + QRegion preserveRegion = m_buffers.back()->dirtyRegion; + qCDebug(lcQpaBackingStore) << "Preserving" << preserveRegion << "from front to back buffer"; - // Let painter operate in device pixels, to make it easier to compare coordinates - const qreal targetDevicePixelRatio = painter.device()->devicePixelRatio(); - painter.scale(1.0 / targetDevicePixelRatio, 1.0 / targetDevicePixelRatio); + m_buffers.front()->lock(QPlatformGraphicsBuffer::SWReadAccess); + const QImage *frontBuffer = m_buffers.front()->asImage(); - for (const QRect &rect : preserveRegion) { - QRect sourceRect(rect.topLeft() * sourceDevicePixelRatio, rect.size() * sourceDevicePixelRatio); - QRect targetRect(rect.topLeft() * targetDevicePixelRatio, rect.size() * targetDevicePixelRatio); + const QRect frontSurfaceBounds(QPoint(0, 0), m_buffers.front()->size()); + const qreal sourceDevicePixelRatio = frontBuffer->devicePixelRatio(); -#ifdef QT_DEBUG - if (Q_UNLIKELY(!frontSurfaceBounds.contains(sourceRect.bottomRight()))) { - qCWarning(lcQpaBackingStore) << "Front buffer too small to preserve" - << QRegion(sourceRect).subtracted(frontSurfaceBounds); - } -#endif - painter.drawImage(targetRect, *frontBuffer, sourceRect); - } + m_buffers.back()->lock(QPlatformGraphicsBuffer::SWWriteAccess); + QPainter painter(m_buffers.back()->asImage()); + painter.setCompositionMode(QPainter::CompositionMode_Source); + + // Let painter operate in device pixels, to make it easier to compare coordinates + const qreal targetDevicePixelRatio = painter.device()->devicePixelRatio(); + painter.scale(1.0 / targetDevicePixelRatio, 1.0 / targetDevicePixelRatio); - m_buffers.back()->unlock(); - m_buffers.front()->unlock(); + for (const QRect &rect : preserveRegion) { + QRect sourceRect(rect.topLeft() * sourceDevicePixelRatio, rect.size() * sourceDevicePixelRatio); + QRect targetRect(rect.topLeft() * targetDevicePixelRatio, rect.size() * targetDevicePixelRatio); - // The back buffer is now completely in sync, ready to be presented - m_buffers.back()->dirtyRegion = QRegion(); +#ifdef QT_DEBUG + if (Q_UNLIKELY(!frontSurfaceBounds.contains(sourceRect.bottomRight()))) { + qCWarning(lcQpaBackingStore) << "Front buffer too small to preserve" + << QRegion(sourceRect).subtracted(frontSurfaceBounds); + } +#endif + painter.drawImage(targetRect, *frontBuffer, sourceRect); } - return true; + m_buffers.back()->unlock(); + m_buffers.front()->unlock(); + + // The back buffer is now completely in sync, ready to be presented + m_buffers.back()->dirtyRegion = QRegion(); } // ---------------------------------------------------------------------------- -- cgit v1.2.3