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 <timur.pocheptsov@qt.io>
This commit is contained in:
parent
38130406ca
commit
5190e77d87
@ -85,7 +85,6 @@ private:
|
|||||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||||
|
|
||||||
QSize m_requestedSize;
|
QSize m_requestedSize;
|
||||||
QRegion m_paintedRegion;
|
|
||||||
|
|
||||||
class GraphicsBuffer : public QIOSurfaceGraphicsBuffer
|
class GraphicsBuffer : public QIOSurfaceGraphicsBuffer
|
||||||
{
|
{
|
||||||
@ -96,12 +95,16 @@ private:
|
|||||||
QRegion dirtyRegion; // In unscaled coordinates
|
QRegion dirtyRegion; // In unscaled coordinates
|
||||||
QImage *asImage();
|
QImage *asImage();
|
||||||
qreal devicePixelRatio() const { return m_devicePixelRatio; }
|
qreal devicePixelRatio() const { return m_devicePixelRatio; }
|
||||||
|
bool isDirty() const { return !dirtyRegion.isEmpty(); }
|
||||||
|
QRegion validRegion() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
qreal m_devicePixelRatio;
|
qreal m_devicePixelRatio;
|
||||||
QImage m_image;
|
QImage m_image;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void updateDirtyStates(const QRegion &paintedRegion);
|
||||||
|
|
||||||
void ensureBackBuffer();
|
void ensureBackBuffer();
|
||||||
bool recreateBackBufferIfNeeded();
|
bool recreateBackBufferIfNeeded();
|
||||||
bool prepareForFlush();
|
bool prepareForFlush();
|
||||||
|
@ -140,7 +140,8 @@ void QCALayerBackingStore::beginPaint(const QRegion ®ion)
|
|||||||
painter.fillRect(rect, Qt::transparent);
|
painter.fillRect(rect, Qt::transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_paintedRegion += region;
|
// We assume the client is going to paint the entire region
|
||||||
|
updateDirtyStates(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QCALayerBackingStore::ensureBackBuffer()
|
void QCALayerBackingStore::ensureBackBuffer()
|
||||||
@ -242,7 +243,7 @@ QPaintDevice *QCALayerBackingStore::paintDevice()
|
|||||||
|
|
||||||
void QCALayerBackingStore::endPaint()
|
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();
|
m_buffers.back()->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,7 +260,7 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion ®ion,
|
|||||||
return;
|
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.";
|
qCInfo(lcQpaBackingStore) << "Asked to flush, but front buffer is up to date. Ignoring.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -414,6 +415,20 @@ QPlatformGraphicsBuffer *QCALayerBackingStore::graphicsBuffer() const
|
|||||||
return m_buffers.back().get();
|
return m_buffers.back().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QCALayerBackingStore::updateDirtyStates(const QRegion &paintedRegion)
|
||||||
|
{
|
||||||
|
// 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 -= paintedRegion;
|
||||||
|
else
|
||||||
|
buffer->dirtyRegion += paintedRegion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool QCALayerBackingStore::prepareForFlush()
|
bool QCALayerBackingStore::prepareForFlush()
|
||||||
{
|
{
|
||||||
if (!m_buffers.back()) {
|
if (!m_buffers.back()) {
|
||||||
@ -421,21 +436,10 @@ bool QCALayerBackingStore::prepareForFlush()
|
|||||||
return false;
|
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;
|
|
||||||
else
|
|
||||||
buffer->dirtyRegion += m_paintedRegion;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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()->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;
|
QRegion preserveRegion = m_buffers.back()->dirtyRegion;
|
||||||
qCDebug(lcQpaBackingStore) << "Preserving" << preserveRegion << "from front to back buffer";
|
qCDebug(lcQpaBackingStore) << "Preserving" << preserveRegion << "from front to back buffer";
|
||||||
|
|
||||||
@ -473,9 +477,6 @@ bool QCALayerBackingStore::prepareForFlush()
|
|||||||
m_buffers.back()->dirtyRegion = QRegion();
|
m_buffers.back()->dirtyRegion = QRegion();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare for another round of painting
|
|
||||||
m_paintedRegion = QRegion();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,12 +485,19 @@ bool QCALayerBackingStore::prepareForFlush()
|
|||||||
QCALayerBackingStore::GraphicsBuffer::GraphicsBuffer(const QSize &size, qreal devicePixelRatio,
|
QCALayerBackingStore::GraphicsBuffer::GraphicsBuffer(const QSize &size, qreal devicePixelRatio,
|
||||||
const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace)
|
const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace)
|
||||||
: QIOSurfaceGraphicsBuffer(size, format)
|
: QIOSurfaceGraphicsBuffer(size, format)
|
||||||
, dirtyRegion(0, 0, size.width() / devicePixelRatio, size.height() / devicePixelRatio)
|
, dirtyRegion(QRect(QPoint(0, 0), size / devicePixelRatio))
|
||||||
, m_devicePixelRatio(devicePixelRatio)
|
, m_devicePixelRatio(devicePixelRatio)
|
||||||
{
|
{
|
||||||
setColorSpace(colorSpace);
|
setColorSpace(colorSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRegion QCALayerBackingStore::GraphicsBuffer::validRegion() const
|
||||||
|
{
|
||||||
|
|
||||||
|
QRegion fullRegion = QRect(QPoint(0, 0), size() / m_devicePixelRatio);
|
||||||
|
return fullRegion - dirtyRegion;
|
||||||
|
}
|
||||||
|
|
||||||
QImage *QCALayerBackingStore::GraphicsBuffer::asImage()
|
QImage *QCALayerBackingStore::GraphicsBuffer::asImage()
|
||||||
{
|
{
|
||||||
if (m_image.isNull()) {
|
if (m_image.isNull()) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user