summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa/qcocoabackingstore.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/cocoa/qcocoabackingstore.mm')
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm120
1 files changed, 78 insertions, 42 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index b17302a640..2b4c71f279 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -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()
@@ -386,7 +382,7 @@ void QCALayerBackingStore::beginPaint(const QRegion &region)
// Although undocumented, QBackingStore::beginPaint expects the painted region
// to be cleared before use if the window has a surface format with an alpha.
// Fresh IOSurfaces are already cleared, so we don't need to clear those.
- if (!bufferWasRecreated && window()->format().hasAlpha()) {
+ if (m_clearSurfaceOnPaint && !bufferWasRecreated && window()->format().hasAlpha()) {
qCDebug(lcQpaBackingStore) << "Clearing" << region << "before use";
QPainter painter(m_buffers.back()->asImage());
painter.setCompositionMode(QPainter::CompositionMode_Source);
@@ -515,9 +511,13 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
if (!prepareForFlush())
return;
+ if (flushedWindow != window()) {
+ flushSubWindow(flushedWindow);
+ return;
+ }
+
QMacAutoReleasePool pool;
- NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
NSView *flushedView = static_cast<QCocoaWindow *>(flushedWindow->handle())->view();
// If the backingstore is just flushed, without being painted to first, then we may
@@ -552,7 +552,7 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
// are committed as part of a display-cycle instead of on the next runloop pass. This
// means CA won't try to throttle us if we flush too fast, and we'll coalesce our flush
// with other pending view and layer updates.
- backingStoreView.window.viewsNeedDisplay = YES;
+ flushedView.window.viewsNeedDisplay = YES;
if (window()->format().swapBehavior() == QSurfaceFormat::SingleBuffer) {
// The private API [CALayer reloadValueForKeyPath:@"contents"] would be preferable,
@@ -560,27 +560,10 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
flushedView.layer.contents = nil;
}
- if (flushedView == backingStoreView) {
- qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface
- << "to" << flushedView.layer << "of" << flushedView;
- flushedView.layer.contents = backBufferSurface;
- } else {
- auto subviewRect = [flushedView convertRect:flushedView.bounds toView:backingStoreView];
- auto scale = flushedView.layer.contentsScale;
- subviewRect = CGRectApplyAffineTransform(subviewRect, CGAffineTransformMakeScale(scale, scale));
-
- // We make a copy of the image data up front, which means we don't
- // need to mark the IOSurface as being in use. FIXME: Investigate
- // if there's a cheaper way to get sub-image data to a layer.
- m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
- QImage subImage = m_buffers.back()->asImage()->copy(QRectF::fromCGRect(subviewRect).toRect());
- m_buffers.back()->unlock();
+ qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface
+ << "to" << flushedView.layer << "of" << flushedView;
- qCInfo(lcQpaBackingStore) << "Flushing" << subImage
- << "to" << flushedView.layer << "of subview" << flushedView;
- QCFType<CGImageRef> cgImage = subImage.toCGImage();
- flushedView.layer.contents = (__bridge id)static_cast<CGImageRef>(cgImage);
- }
+ flushedView.layer.contents = backBufferSurface;
// Since we may receive multiple flushes before a new frame is started, we do not
// swap any buffers just yet. Instead we check in the next beginPaint if the layer's
@@ -592,6 +575,53 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
// the window server.
}
+void QCALayerBackingStore::flushSubWindow(QWindow *subWindow)
+{
+ qCInfo(lcQpaBackingStore) << "Flushing sub-window" << subWindow
+ << "via its own backingstore";
+
+ auto &subWindowBackingStore = m_subWindowBackingstores[subWindow];
+ if (!subWindowBackingStore) {
+ subWindowBackingStore.reset(new QCALayerBackingStore(subWindow));
+ QObject::connect(subWindow, &QObject::destroyed, this, &QCALayerBackingStore::windowDestroyed);
+ subWindowBackingStore->m_clearSurfaceOnPaint = false;
+ }
+
+ auto subWindowSize = subWindow->size();
+ static const auto kNoStaticContents = QRegion();
+ subWindowBackingStore->resize(subWindowSize, kNoStaticContents);
+
+ auto subWindowLocalRect = QRect(QPoint(), subWindowSize);
+ subWindowBackingStore->beginPaint(subWindowLocalRect);
+
+ QPainter painter(subWindowBackingStore->m_buffers.back()->asImage());
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+
+ NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
+ NSView *flushedView = static_cast<QCocoaWindow *>(subWindow->handle())->view();
+ auto subviewRect = [flushedView convertRect:flushedView.bounds toView:backingStoreView];
+ auto scale = flushedView.layer.contentsScale;
+ subviewRect = CGRectApplyAffineTransform(subviewRect, CGAffineTransformMakeScale(scale, scale));
+
+ m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
+ const QImage *backingStoreImage = m_buffers.back()->asImage();
+ painter.drawImage(subWindowLocalRect, *backingStoreImage, QRectF::fromCGRect(subviewRect));
+ m_buffers.back()->unlock();
+
+ painter.end();
+ subWindowBackingStore->endPaint();
+ subWindowBackingStore->flush(subWindow, subWindowLocalRect, QPoint());
+
+ qCInfo(lcQpaBackingStore) << "Done flushing sub-window" << subWindow;
+}
+
+void QCALayerBackingStore::windowDestroyed(QObject *object)
+{
+ auto *window = static_cast<QWindow*>(object);
+ qCInfo(lcQpaBackingStore) << "Removing backingstore for sub-window" << window;
+ m_subWindowBackingstores.erase(window);
+}
+
#ifndef QT_NO_OPENGL
void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
QPlatformTextureList *textures, bool translucentBackground)
@@ -620,8 +650,11 @@ 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) {
+ if (buffer)
+ buffer->setColorSpace(colorSpace());
+ }
}
QPlatformGraphicsBuffer *QCALayerBackingStore::graphicsBuffer() const
@@ -698,10 +731,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()
@@ -721,4 +755,6 @@ QImage *QCALayerBackingStore::GraphicsBuffer::asImage()
return &m_image;
}
+#include "moc_qcocoabackingstore.cpp"
+
QT_END_NAMESPACE