macOS Don't throw away backingstore buffers when backing properties change

Clients such as QtWidgets that do their own dirty tracking will assume
they can just flush in response to the expose event, without repainting
anything. Since we have no way at the moment to inform these clients that
the backingstore content might be invalid we can't just throw it away.

It turns out that to pick up changes in color spaces we can just tag
the existing buffers with the new color space, so we don't need to
throw it away. And for the older surface-backed mode we tag the color
space on flush, so we didn't need to invalidate anything in the first
place.

Fixes: QTBUG-80844
Task-number: QTBUG-77749
Change-Id: Icb1ceb178894bb43887cdf03fb855d2d614b5ab0
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
Tor Arne Vestbø 2019-12-20 16:46:24 +01:00
parent 6c2052f9d7
commit 7ac4e55cb9
5 changed files with 32 additions and 30 deletions

View File

@ -54,8 +54,6 @@ class QCocoaBackingStore : public QRasterBackingStore
protected:
QCocoaBackingStore(QWindow *window);
QCFType<CGColorSpaceRef> colorSpace() const;
QMacNotificationObserver m_backingPropertiesObserver;
virtual void backingPropertiesChanged() = 0;
};
class QNSWindowBackingStore : public QCocoaBackingStore
@ -71,7 +69,6 @@ private:
bool windowHasUnifiedToolbar() const;
QImage::Format format() const override;
void redrawRoundedBottomCorners(CGRect) const;
void backingPropertiesChanged() override;
};
class QCALayerBackingStore : public QCocoaBackingStore
@ -118,7 +115,8 @@ private:
bool recreateBackBufferIfNeeded();
bool prepareForFlush();
void backingPropertiesChanged() override;
void backingPropertiesChanged();
QMacNotificationObserver m_backingPropertiesObserver;
std::list<std::unique_ptr<GraphicsBuffer>> m_buffers;
};

View File

@ -51,17 +51,6 @@ QT_BEGIN_NAMESPACE
QCocoaBackingStore::QCocoaBackingStore(QWindow *window)
: QRasterBackingStore(window)
{
// Ideally this would be plumbed from the platform layer to QtGui, and
// the QBackingStore would be recreated, but we don't have that code yet,
// so at least make sure we invalidate our backingstore when the backing
// properties (color space e.g.) are changed.
NSView *view = static_cast<QCocoaWindow *>(window->handle())->view();
m_backingPropertiesObserver = QMacNotificationObserver(view.window,
NSWindowDidChangeBackingPropertiesNotification, [this]() {
qCDebug(lcQpaBackingStore) << "Backing properties for"
<< this->window() << "did change";
backingPropertiesChanged();
});
}
QCFType<CGColorSpaceRef> QCocoaBackingStore::colorSpace() const
@ -341,11 +330,6 @@ void QNSWindowBackingStore::redrawRoundedBottomCorners(CGRect windowRect) const
#endif
}
void QNSWindowBackingStore::backingPropertiesChanged()
{
m_image = QImage();
}
// ----------------------------------------------------------------------------
QCALayerBackingStore::QCALayerBackingStore(QWindow *window)
@ -353,6 +337,18 @@ QCALayerBackingStore::QCALayerBackingStore(QWindow *window)
{
qCDebug(lcQpaBackingStore) << "Creating QCALayerBackingStore for" << window;
m_buffers.resize(1);
// Ideally this would be plumbed from the platform layer to QtGui, and
// the QBackingStore would be recreated, but we don't have that code yet,
// so at least make sure we update our backingstore when the backing
// properties (color space e.g.) are changed.
NSView *view = static_cast<QCocoaWindow *>(window->handle())->view();
m_backingPropertiesObserver = QMacNotificationObserver(view.window,
NSWindowDidChangeBackingPropertiesNotification, [this]() {
qCDebug(lcQpaBackingStore) << "Backing properties for"
<< this->window() << "did change";
backingPropertiesChanged();
});
}
QCALayerBackingStore::~QCALayerBackingStore()
@ -620,8 +616,9 @@ QImage QCALayerBackingStore::toImage() const
void QCALayerBackingStore::backingPropertiesChanged()
{
m_buffers.clear();
m_buffers.resize(1);
qCDebug(lcQpaBackingStore) << "Updating color space of existing buffers";
for (auto &buffer : m_buffers)
buffer->setColorSpace(colorSpace());
}
QPlatformGraphicsBuffer *QCALayerBackingStore::graphicsBuffer() const
@ -698,10 +695,11 @@ bool QCALayerBackingStore::prepareForFlush()
QCALayerBackingStore::GraphicsBuffer::GraphicsBuffer(const QSize &size, qreal devicePixelRatio,
const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace)
: QIOSurfaceGraphicsBuffer(size, format, colorSpace)
: QIOSurfaceGraphicsBuffer(size, format)
, dirtyRegion(0, 0, size.width() / devicePixelRatio, size.height() / devicePixelRatio)
, m_devicePixelRatio(devicePixelRatio)
{
setColorSpace(colorSpace);
}
QImage *QCALayerBackingStore::GraphicsBuffer::asImage()

View File

@ -396,6 +396,8 @@ QVariant QCocoaIntegration::styleHint(StyleHint hint) const
return QCoreTextFontEngine::fontSmoothingGamma();
case ShowShortcutsInContextMenus:
return QVariant(false);
// case CursorFlashTime:
// return 50000;
default: break;
}

View File

@ -48,9 +48,11 @@ QT_BEGIN_NAMESPACE
class QIOSurfaceGraphicsBuffer : public QPlatformGraphicsBuffer
{
public:
QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace);
QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format);
~QIOSurfaceGraphicsBuffer();
void setColorSpace(QCFType<CGColorSpaceRef> colorSpace);
const uchar *data() const override;
uchar *data() override;
int bytesPerLine() const override;

View File

@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaIOSurface, "qt.qpa.backingstore.iosurface");
QIOSurfaceGraphicsBuffer::QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format, QCFType<CGColorSpaceRef> colorSpace)
QIOSurfaceGraphicsBuffer::QIOSurfaceGraphicsBuffer(const QSize &size, const QPixelFormat &format)
: QPlatformGraphicsBuffer(size, format)
{
const size_t width = size.width();
@ -81,17 +81,19 @@ QIOSurfaceGraphicsBuffer::QIOSurfaceGraphicsBuffer(const QSize &size, const QPix
Q_ASSERT(size_t(bytesPerLine()) == bytesPerRow);
Q_ASSERT(size_t(byteCount()) == totalBytes);
if (colorSpace) {
IOSurfaceSetValue(m_surface, CFSTR("IOSurfaceColorSpace"),
QCFType<CFPropertyListRef>(CGColorSpaceCopyPropertyList(colorSpace)));
}
}
QIOSurfaceGraphicsBuffer::~QIOSurfaceGraphicsBuffer()
{
}
void QIOSurfaceGraphicsBuffer::setColorSpace(QCFType<CGColorSpaceRef> colorSpace)
{
Q_ASSERT(colorSpace);
IOSurfaceSetValue(m_surface, CFSTR("IOSurfaceColorSpace"),
QCFType<CFPropertyListRef>(CGColorSpaceCopyPropertyList(colorSpace)));
}
const uchar *QIOSurfaceGraphicsBuffer::data() const
{
return (const uchar *)IOSurfaceGetBaseAddress(m_surface);