From 5fb45c959079753f7a11cd7bb0fa0e5c1d9598f5 Mon Sep 17 00:00:00 2001 From: Kai Uwe Broulik Date: Mon, 8 Jan 2024 16:48:14 +0100 Subject: [PATCH] QWaylandShmBackingStore: Don't clear new buffers in beginPaint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QFile::resize done upon creation of the buffer already ensures the buffer is filled with zeroes, so there is no need to paint it transparent if the buffer had just been created. Change-Id: I73ab297f148987acf52a0e08c7dd1ca57f7255be Reviewed-by: Tor Arne Vestbø --- .../wayland/qwaylandshmbackingstore.cpp | 26 +++++++++++++------ .../wayland/qwaylandshmbackingstore_p.h | 4 +-- .../platforms/wayland/qwaylandwindow.cpp | 2 +- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp index a1e9e0e4a34..d77c548a009 100644 --- a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp +++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp @@ -71,6 +71,7 @@ QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display, file->open(fd, QIODevice::ReadWrite | QIODevice::Unbuffered, QFile::AutoCloseHandle); filePointer.reset(file); } + // NOTE beginPaint assumes a new buffer be all zeroes, which QFile::resize does. if (!filePointer->isOpen() || !filePointer->resize(alloc)) { qWarning("QWaylandShmBuffer: failed: %s", qUtf8Printable(filePointer->errorString())); return; @@ -144,9 +145,9 @@ QWaylandShmBackingStore::QWaylandShmBackingStore(QWindow *window, QWaylandDispla // contents from the back buffer mBuffers.clear(); mFrontBuffer = nullptr; - // ensureBackBuffer always resets mBackBuffer + // recreateBackBufferIfNeeded always resets mBackBuffer if (mRequestedSize.isValid() && waylandWindow()) - ensureBackBuffer(); + recreateBackBufferIfNeeded(); qDeleteAll(copy); }); } @@ -181,12 +182,15 @@ void QWaylandShmBackingStore::beginPaint(const QRegion ®ion) { mPainting = true; waylandWindow()->setBackingStore(this); - ensureBackBuffer(); + const bool bufferWasRecreated = recreateBackBufferIfNeeded(); const QMargins margins = windowDecorationMargins(); updateDirtyStates(region.translated(margins.left(), margins.top())); - if (mBackBuffer->image()->hasAlphaChannel()) { + // Although undocumented, QBackingStore::beginPaint expects the painted region + // to be cleared before use if the window has a surface format with an alpha. + // Fresh QWaylandShmBuffer are already cleared, so we don't need to clear those. + if (!bufferWasRecreated && mBackBuffer->image()->hasAlphaChannel()) { QPainter p(paintDevice()); p.setCompositionMode(QPainter::CompositionMode_Source); const QColor blank = Qt::transparent; @@ -238,8 +242,10 @@ void QWaylandShmBackingStore::resize(const QSize &size, const QRegion &) mRequestedSize = size; } -QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size) +QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size, bool &bufferWasRecreated) { + bufferWasRecreated = false; + const auto copy = mBuffers; // remove when ported to vector + remove_if for (QWaylandShmBuffer *b : copy) { if (!b->busy()) { @@ -258,14 +264,16 @@ QWaylandShmBuffer *QWaylandShmBackingStore::getBuffer(const QSize &size) if (mBuffers.size() < MAX_BUFFERS) { QImage::Format format = QPlatformScreen::platformScreenForWindow(window())->format(); QWaylandShmBuffer *b = new QWaylandShmBuffer(mDisplay, size, format, waylandWindow()->scale()); + bufferWasRecreated = true; mBuffers.push_front(b); return b; } return nullptr; } -void QWaylandShmBackingStore::ensureBackBuffer() +bool QWaylandShmBackingStore::recreateBackBufferIfNeeded() { + bool bufferWasRecreated = false; QMargins margins = windowDecorationMargins(); qreal scale = waylandWindow()->scale(); const QSize sizeWithMargins = (mRequestedSize + QSize(margins.left() + margins.right(), margins.top() + margins.bottom())) * scale; @@ -278,12 +286,12 @@ void QWaylandShmBackingStore::ensureBackBuffer() // You can exercise the different codepaths with weston, switching between the gl and the // pixman renderer. With the gl renderer release events are sent early so we can effectively // run single buffered, while with the pixman renderer we have to use two. - QWaylandShmBuffer *buffer = getBuffer(sizeWithMargins); + QWaylandShmBuffer *buffer = getBuffer(sizeWithMargins, bufferWasRecreated); while (!buffer) { qCDebug(lcWaylandBackingstore, "QWaylandShmBackingStore: stalling waiting for a buffer to be released from the compositor..."); mDisplay->blockingReadEvents(); - buffer = getBuffer(sizeWithMargins); + buffer = getBuffer(sizeWithMargins, bufferWasRecreated); } qsizetype oldSizeInBytes = mBackBuffer ? mBackBuffer->image()->sizeInBytes() : 0; @@ -325,6 +333,8 @@ void QWaylandShmBackingStore::ensureBackBuffer() windowDecoration()->update(); buffer->dirtyRegion() = QRegion(); + + return bufferWasRecreated; } QImage *QWaylandShmBackingStore::entireSurface() const diff --git a/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h b/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h index 78889336010..6d276bf7b30 100644 --- a/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h +++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore_p.h @@ -69,7 +69,7 @@ public: QMargins windowDecorationMargins() const; QImage *entireSurface() const; QImage *contentSurface() const; - void ensureBackBuffer(); + bool recreateBackBufferIfNeeded(); QWaylandWindow *waylandWindow() const; void iterateBuffer(); @@ -81,7 +81,7 @@ public: private: void updateDirtyStates(const QRegion ®ion); void updateDecorations(); - QWaylandShmBuffer *getBuffer(const QSize &size); + QWaylandShmBuffer *getBuffer(const QSize &size, bool &bufferWasRecreated); QWaylandDisplay *mDisplay = nullptr; std::list mBuffers; diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp index f5a9fddb81a..84b73c0a46f 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp @@ -92,7 +92,7 @@ void QWaylandWindow::ensureSize() { if (mBackingStore) { setBackingStore(mBackingStore); - mBackingStore->ensureBackBuffer(); + mBackingStore->recreateBackBufferIfNeeded(); } }