macOS: Gracefully handle devicePixelRatio mismatch in QCALayerBackingStore
If the client of the backingstore fails to pick up dpr changes, and tries to flush the backingstore without a repaint, we will end up flushing a back-buffer with a stale dpr. Detect when this happens, warn the user, and smooth out the situation by adjusting the layer accordingly. Change-Id: If4596a8976a3902252c81d8e28c7aeb9fdd908bf Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io> Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
parent
585150e3d9
commit
2b2133f853
@ -93,6 +93,7 @@ private:
|
|||||||
|
|
||||||
QRegion dirtyRegion; // In unscaled coordinates
|
QRegion dirtyRegion; // In unscaled coordinates
|
||||||
QImage *asImage();
|
QImage *asImage();
|
||||||
|
qreal devicePixelRatio() const { return m_devicePixelRatio; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
qreal m_devicePixelRatio;
|
qreal m_devicePixelRatio;
|
||||||
|
@ -460,12 +460,29 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion ®ion,
|
|||||||
NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
|
NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
|
||||||
NSView *flushedView = static_cast<QCocoaWindow *>(flushedWindow->handle())->view();
|
NSView *flushedView = static_cast<QCocoaWindow *>(flushedWindow->handle())->view();
|
||||||
|
|
||||||
|
// If the backingstore is just flushed, without being painted to first, then we may
|
||||||
|
// end in a situation where the backingstore is flushed to a layer with a different
|
||||||
|
// scale factor than the one it was created for in beginPaint. This is the client's
|
||||||
|
// fault in not picking up the change in scale factor of the window and re-painting
|
||||||
|
// the backingstore accordingly. To smoothing things out, we warn about this situation,
|
||||||
|
// and change the layer's contentsScale to match the scale of the back buffer, so that
|
||||||
|
// we at least cover the whole layer. This is necessary since we set the view's
|
||||||
|
// contents placement policy to NSViewLayerContentsPlacementTopLeft, which means
|
||||||
|
// AppKit will not do any scaling on our behalf.
|
||||||
|
if (m_buffers.back()->devicePixelRatio() != flushedView.layer.contentsScale) {
|
||||||
|
qCWarning(lcQpaBackingStore) << "Back buffer dpr of" << m_buffers.back()->devicePixelRatio()
|
||||||
|
<< "doesn't match" << flushedView.layer << "contents scale of" << flushedView.layer.contentsScale
|
||||||
|
<< "- updating layer to match.";
|
||||||
|
flushedView.layer.contentsScale = m_buffers.back()->devicePixelRatio();
|
||||||
|
}
|
||||||
|
|
||||||
id backBufferSurface = (__bridge id)m_buffers.back()->surface();
|
id backBufferSurface = (__bridge id)m_buffers.back()->surface();
|
||||||
if (flushedView.layer.contents == backBufferSurface) {
|
if (flushedView.layer.contents == backBufferSurface) {
|
||||||
// We've managed to paint to the back buffer again before Core Animation had time
|
// We've managed to paint to the back buffer again before Core Animation had time
|
||||||
// to flush the transaction and persist the layer changes to the window server.
|
// to flush the transaction and persist the layer changes to the window server, or
|
||||||
// The layer already knows about the back buffer, and we don't need to re-apply
|
// we've been asked to flush without painting anything. The layer already knows about
|
||||||
// it to pick up the surface changes, so bail out early.
|
// the back buffer, and we don't need to re-apply it to pick up any possible surface
|
||||||
|
// changes, so bail out early.
|
||||||
qCInfo(lcQpaBackingStore).nospace() << "Skipping flush of " << flushedView
|
qCInfo(lcQpaBackingStore).nospace() << "Skipping flush of " << flushedView
|
||||||
<< ", layer already reflects back buffer";
|
<< ", layer already reflects back buffer";
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user