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 <timur.pocheptsov@qt.io>
This commit is contained in:
parent
5190e77d87
commit
4ffdf2270a
@ -107,7 +107,7 @@ private:
|
|||||||
|
|
||||||
void ensureBackBuffer();
|
void ensureBackBuffer();
|
||||||
bool recreateBackBufferIfNeeded();
|
bool recreateBackBufferIfNeeded();
|
||||||
bool prepareForFlush();
|
void finalizeBackBuffer();
|
||||||
|
|
||||||
void backingPropertiesChanged();
|
void backingPropertiesChanged();
|
||||||
QMacNotificationObserver m_backingPropertiesObserver;
|
QMacNotificationObserver m_backingPropertiesObserver;
|
||||||
|
@ -245,6 +245,9 @@ void QCALayerBackingStore::endPaint()
|
|||||||
{
|
{
|
||||||
qCInfo(lcQpaBackingStore) << "Paint ended. Back buffer valid region is now" << m_buffers.back()->validRegion();
|
qCInfo(lcQpaBackingStore) << "Paint ended. Back buffer valid region is now" << m_buffers.back()->validRegion();
|
||||||
m_buffers.back()->unlock();
|
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)
|
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(region);
|
||||||
Q_UNUSED(offset);
|
Q_UNUSED(offset);
|
||||||
|
|
||||||
if (!prepareForFlush())
|
if (!m_buffers.back()) {
|
||||||
|
qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first";
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
finalizeBackBuffer();
|
||||||
|
|
||||||
if (flushedWindow != window()) {
|
if (flushedWindow != window()) {
|
||||||
flushSubWindow(flushedWindow);
|
flushSubWindow(flushedWindow);
|
||||||
@ -370,8 +377,12 @@ void QCALayerBackingStore::windowDestroyed(QObject *object)
|
|||||||
void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
||||||
QPlatformTextureList *textures, bool translucentBackground)
|
QPlatformTextureList *textures, bool translucentBackground)
|
||||||
{
|
{
|
||||||
if (!prepareForFlush())
|
if (!m_buffers.back()) {
|
||||||
|
qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first";
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
finalizeBackBuffer();
|
||||||
|
|
||||||
QPlatformBackingStore::composeAndFlush(window, region, offset, textures, translucentBackground);
|
QPlatformBackingStore::composeAndFlush(window, region, offset, textures, translucentBackground);
|
||||||
}
|
}
|
||||||
@ -379,9 +390,11 @@ void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion ®io
|
|||||||
|
|
||||||
QImage QCALayerBackingStore::toImage() const
|
QImage QCALayerBackingStore::toImage() const
|
||||||
{
|
{
|
||||||
if (!const_cast<QCALayerBackingStore*>(this)->prepareForFlush())
|
if (!m_buffers.back())
|
||||||
return QImage();
|
return QImage();
|
||||||
|
|
||||||
|
const_cast<QCALayerBackingStore*>(this)->finalizeBackBuffer();
|
||||||
|
|
||||||
// We need to make a copy here, as the returned image could be used just
|
// 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
|
// 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
|
// 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
|
// 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,
|
// 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 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);
|
if (!m_buffers.back()->isDirty())
|
||||||
const QImage *frontBuffer = m_buffers.front()->asImage();
|
return;
|
||||||
|
|
||||||
const QRect frontSurfaceBounds(QPoint(0, 0), m_buffers.front()->size());
|
if (m_buffers.front() == m_buffers.back())
|
||||||
const qreal sourceDevicePixelRatio = frontBuffer->devicePixelRatio();
|
return; // Nothing to preserve from
|
||||||
|
|
||||||
m_buffers.back()->lock(QPlatformGraphicsBuffer::SWWriteAccess);
|
QRegion preserveRegion = m_buffers.back()->dirtyRegion;
|
||||||
QPainter painter(m_buffers.back()->asImage());
|
qCDebug(lcQpaBackingStore) << "Preserving" << preserveRegion << "from front to back buffer";
|
||||||
painter.setCompositionMode(QPainter::CompositionMode_Source);
|
|
||||||
|
|
||||||
// Let painter operate in device pixels, to make it easier to compare coordinates
|
m_buffers.front()->lock(QPlatformGraphicsBuffer::SWReadAccess);
|
||||||
const qreal targetDevicePixelRatio = painter.device()->devicePixelRatio();
|
const QImage *frontBuffer = m_buffers.front()->asImage();
|
||||||
painter.scale(1.0 / targetDevicePixelRatio, 1.0 / targetDevicePixelRatio);
|
|
||||||
|
|
||||||
for (const QRect &rect : preserveRegion) {
|
const QRect frontSurfaceBounds(QPoint(0, 0), m_buffers.front()->size());
|
||||||
QRect sourceRect(rect.topLeft() * sourceDevicePixelRatio, rect.size() * sourceDevicePixelRatio);
|
const qreal sourceDevicePixelRatio = frontBuffer->devicePixelRatio();
|
||||||
QRect targetRect(rect.topLeft() * targetDevicePixelRatio, rect.size() * targetDevicePixelRatio);
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
for (const QRect &rect : preserveRegion) {
|
||||||
|
QRect sourceRect(rect.topLeft() * sourceDevicePixelRatio, rect.size() * sourceDevicePixelRatio);
|
||||||
|
QRect targetRect(rect.topLeft() * targetDevicePixelRatio, rect.size() * targetDevicePixelRatio);
|
||||||
|
|
||||||
#ifdef QT_DEBUG
|
#ifdef QT_DEBUG
|
||||||
if (Q_UNLIKELY(!frontSurfaceBounds.contains(sourceRect.bottomRight()))) {
|
if (Q_UNLIKELY(!frontSurfaceBounds.contains(sourceRect.bottomRight()))) {
|
||||||
qCWarning(lcQpaBackingStore) << "Front buffer too small to preserve"
|
qCWarning(lcQpaBackingStore) << "Front buffer too small to preserve"
|
||||||
<< QRegion(sourceRect).subtracted(frontSurfaceBounds);
|
<< QRegion(sourceRect).subtracted(frontSurfaceBounds);
|
||||||
}
|
|
||||||
#endif
|
|
||||||
painter.drawImage(targetRect, *frontBuffer, sourceRect);
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
m_buffers.back()->unlock();
|
painter.drawImage(targetRect, *frontBuffer, sourceRect);
|
||||||
m_buffers.front()->unlock();
|
|
||||||
|
|
||||||
// The back buffer is now completely in sync, ready to be presented
|
|
||||||
m_buffers.back()->dirtyRegion = QRegion();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user