From 5190e77d87d743a75362ecf933adb466199e8958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 4 Nov 2021 13:29:05 +0100 Subject: macOS: Track painted area of backingstore buffer via its dirty region When introducing support for scrolling the backingstore it doesn't make sense to track the painted region explicitly. Pick-to: 6.2 Change-Id: I370932f02490ac526fb049908f99af678884e807 Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoabackingstore.h | 5 ++- src/plugins/platforms/cocoa/qcocoabackingstore.mm | 40 ++++++++++++++--------- 2 files changed, 28 insertions(+), 17 deletions(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index 374dc97f7d..28adbaee41 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -85,7 +85,6 @@ private: bool eventFilter(QObject *watched, QEvent *event) override; QSize m_requestedSize; - QRegion m_paintedRegion; class GraphicsBuffer : public QIOSurfaceGraphicsBuffer { @@ -96,12 +95,16 @@ private: QRegion dirtyRegion; // In unscaled coordinates QImage *asImage(); qreal devicePixelRatio() const { return m_devicePixelRatio; } + bool isDirty() const { return !dirtyRegion.isEmpty(); } + QRegion validRegion() const; private: qreal m_devicePixelRatio; QImage m_image; }; + void updateDirtyStates(const QRegion &paintedRegion); + void ensureBackBuffer(); bool recreateBackBufferIfNeeded(); bool prepareForFlush(); diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index e4a7a3d8af..21ccbcbb00 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -140,7 +140,8 @@ void QCALayerBackingStore::beginPaint(const QRegion ®ion) painter.fillRect(rect, Qt::transparent); } - m_paintedRegion += region; + // We assume the client is going to paint the entire region + updateDirtyStates(region); } void QCALayerBackingStore::ensureBackBuffer() @@ -242,7 +243,7 @@ QPaintDevice *QCALayerBackingStore::paintDevice() void QCALayerBackingStore::endPaint() { - qCInfo(lcQpaBackingStore) << "Paint ended with painted region" << m_paintedRegion; + qCInfo(lcQpaBackingStore) << "Paint ended. Back buffer valid region is now" << m_buffers.back()->validRegion(); m_buffers.back()->unlock(); } @@ -259,7 +260,7 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion ®ion, return; } - if (m_buffers.front()->isInUse() && m_buffers.front()->dirtyRegion.isEmpty()) { + if (m_buffers.front()->isInUse() && !m_buffers.front()->isDirty()) { qCInfo(lcQpaBackingStore) << "Asked to flush, but front buffer is up to date. Ignoring."; return; } @@ -414,28 +415,31 @@ QPlatformGraphicsBuffer *QCALayerBackingStore::graphicsBuffer() const return m_buffers.back().get(); } -bool QCALayerBackingStore::prepareForFlush() +void QCALayerBackingStore::updateDirtyStates(const QRegion &paintedRegion) { - if (!m_buffers.back()) { - qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first"; - return false; - } - // Update dirty state of buffers based on what was painted. The back buffer will be // less dirty, since we painted to it, while other buffers will become more dirty. // This allows us to minimize copies between front and back buffers on swap in the // cases where the painted region overlaps with the previous frame (front buffer). for (const auto &buffer : m_buffers) { if (buffer == m_buffers.back()) - buffer->dirtyRegion -= m_paintedRegion; + buffer->dirtyRegion -= paintedRegion; else - buffer->dirtyRegion += m_paintedRegion; + buffer->dirtyRegion += paintedRegion; + } +} + +bool QCALayerBackingStore::prepareForFlush() +{ + 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()->dirtyRegion.isEmpty() && m_buffers.front() != m_buffers.back()) { + 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"; @@ -473,9 +477,6 @@ bool QCALayerBackingStore::prepareForFlush() m_buffers.back()->dirtyRegion = QRegion(); } - // Prepare for another round of painting - m_paintedRegion = QRegion(); - return true; } @@ -484,12 +485,19 @@ bool QCALayerBackingStore::prepareForFlush() QCALayerBackingStore::GraphicsBuffer::GraphicsBuffer(const QSize &size, qreal devicePixelRatio, const QPixelFormat &format, QCFType colorSpace) : QIOSurfaceGraphicsBuffer(size, format) - , dirtyRegion(0, 0, size.width() / devicePixelRatio, size.height() / devicePixelRatio) + , dirtyRegion(QRect(QPoint(0, 0), size / devicePixelRatio)) , m_devicePixelRatio(devicePixelRatio) { setColorSpace(colorSpace); } +QRegion QCALayerBackingStore::GraphicsBuffer::validRegion() const +{ + + QRegion fullRegion = QRect(QPoint(0, 0), size() / m_devicePixelRatio); + return fullRegion - dirtyRegion; +} + QImage *QCALayerBackingStore::GraphicsBuffer::asImage() { if (m_image.isNull()) { -- cgit v1.2.3