macOS: Implement QCALayerBackingStore::scroll for improved performance
The CALayer backingstore never had a scroll implementation because we were relying on the QRasterBackingStore implementation, but as it turned out that implementation was not applicable for the CALayer backingstore. We now implement scroll() by determining which part of the back buffer can be scrolled directly in-place, and then scrolling the rest by copying from the front buffer. We have to handle both cases, as clients may scroll multiple times before flushing, and the scrolled area may overlap both valid back-buffer content and content that needs to be pulled from the front-buffer. Pick-to: 6.3 6.2 Change-Id: Icc09c9488386925116779c9024669a4329b38247 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>bb10
parent
588f956f78
commit
996061a1c0
|
|
@ -71,6 +71,8 @@ public:
|
|||
QPaintDevice *paintDevice() override;
|
||||
void endPaint() override;
|
||||
|
||||
bool scroll(const QRegion ®ion, int dx, int dy) override;
|
||||
|
||||
void flush(QWindow *, const QRegion &, const QPoint &) override;
|
||||
#ifndef QT_NO_OPENGL
|
||||
void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
||||
|
|
|
|||
|
|
@ -250,6 +250,61 @@ void QCALayerBackingStore::endPaint()
|
|||
// we defer finalizing the back buffer until its content is needed.
|
||||
}
|
||||
|
||||
bool QCALayerBackingStore::scroll(const QRegion ®ion, int dx, int dy)
|
||||
{
|
||||
if (!m_buffers.back()) {
|
||||
qCInfo(lcQpaBackingStore) << "Scroll requested with no back buffer. Ignoring.";
|
||||
return false;
|
||||
}
|
||||
|
||||
const QPoint scrollDelta(dx, dy);
|
||||
qCInfo(lcQpaBackingStore) << "Scrolling" << region << "by" << scrollDelta;
|
||||
|
||||
ensureBackBuffer();
|
||||
recreateBackBufferIfNeeded();
|
||||
|
||||
const QRegion inPlaceRegion = region - m_buffers.back()->dirtyRegion;
|
||||
const QRegion frontBufferRegion = region - inPlaceRegion;
|
||||
|
||||
QMacAutoReleasePool pool;
|
||||
|
||||
m_buffers.back()->lock(QPlatformGraphicsBuffer::SWWriteAccess);
|
||||
|
||||
if (!inPlaceRegion.isEmpty()) {
|
||||
qCDebug(lcQpaBackingStore) << "Scrolling" << inPlaceRegion << "in place";
|
||||
QImage *backBufferImage = m_buffers.back()->asImage();
|
||||
const qreal devicePixelRatio = backBufferImage->devicePixelRatio();
|
||||
const QPoint devicePixelDelta = scrollDelta * devicePixelRatio;
|
||||
|
||||
extern void qt_scrollRectInImage(QImage &, const QRect &, const QPoint &);
|
||||
|
||||
for (const QRect &rect : inPlaceRegion) {
|
||||
qt_scrollRectInImage(*backBufferImage,
|
||||
QRect(rect.topLeft() * devicePixelRatio,
|
||||
rect.size() * devicePixelRatio),
|
||||
devicePixelDelta);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!frontBufferRegion.isEmpty()) {
|
||||
qCDebug(lcQpaBackingStore) << "Scrolling" << frontBufferRegion << "by copying from front buffer";
|
||||
preserveFromFrontBuffer(frontBufferRegion, scrollDelta);
|
||||
}
|
||||
|
||||
m_buffers.back()->unlock();
|
||||
|
||||
// Mark the target region as filled. Note: We do not mark the source region
|
||||
// as dirty, even though the content has conceptually been "moved", as that
|
||||
// would complicate things when preserving from the front buffer. This matches
|
||||
// the behavior of other backingstore implementations using qt_scrollRectInImage.
|
||||
updateDirtyStates(region.translated(scrollDelta));
|
||||
|
||||
qCInfo(lcQpaBackingStore) << "Scroll ended. Back buffer valid region is now" << m_buffers.back()->validRegion();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion ®ion, const QPoint &offset)
|
||||
{
|
||||
Q_UNUSED(region);
|
||||
|
|
|
|||
|
|
@ -6039,8 +6039,7 @@ void tst_QWidget::moveChild()
|
|||
QTRY_COMPARE(pos, child.pos());
|
||||
|
||||
QTRY_COMPARE(parent.r, QRegion(oldGeometry) - child.geometry());
|
||||
if (QGuiApplication::platformName() == "cocoa")
|
||||
QEXPECT_FAIL("", "Cocoa backing store doesn't implement scroll", Abort);
|
||||
|
||||
// should be scrolled in backingstore
|
||||
QCOMPARE(child.r, QRegion());
|
||||
VERIFY_COLOR(child, child.rect(), child.color);
|
||||
|
|
|
|||
Loading…
Reference in New Issue