Cocoa: Fix backing store performance regression.
authorMorten Johan Sørvig <morten.sorvig@theqtcompany.com>
Thu, 13 Aug 2015 19:42:10 +0000 (21:42 +0200)
committerMorten Johan Sørvig <morten.sorvig@theqtcompany.com>
Tue, 25 Aug 2015 13:51:00 +0000 (13:51 +0000)
Commit 916dfcb8 introduced a regression where QNSView
would hold a copy if the backing store QImage, which
would cause a detach and deep copy if/when the image
was painted on while the copy was held.

Revert back to the previous share-by-pointer scheme.
Make sure the following bugs stays fixed:
    QTBUG-38377
    QTBUG-42206
    QTBUG-44313

Change-Id: Ib8049051d51947113f23b66ee61dc34c22388914
Task-number: QTBUG-46959
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@theqtcompany.com>
src/plugins/platforms/cocoa/qcocoabackingstore.mm
src/plugins/platforms/cocoa/qnsview.h
src/plugins/platforms/cocoa/qnsview.mm

index 6a4f7ed8ee710b7537b4733d55da29fc093ee419..ca921038260183b63a36f0ecae9fdd760d6548e7 100644 (file)
@@ -44,6 +44,8 @@ QCocoaBackingStore::QCocoaBackingStore(QWindow *window)
 
 QCocoaBackingStore::~QCocoaBackingStore()
 {
+    if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window()->handle()))
+        [cocoaWindow->m_qtView clearBackingStore:this];
 }
 
 QPaintDevice *QCocoaBackingStore::paintDevice()
index 05ab8ae2c705fb6cd8b91dc57d41ef58f29b9f71..14a61554a362dfd599d2721362124b13c89f83a1 100644 (file)
@@ -51,8 +51,7 @@ QT_END_NAMESPACE
 Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
 
 @interface QT_MANGLE_NAMESPACE(QNSView) : NSView <NSTextInputClient> {
-    QImage m_backingStore;
-    qreal m_pixelRatio;
+    QCocoaBackingStore* m_backingStore;
     QPoint m_backingStoreOffset;
     CGImageRef m_maskImage;
     uchar *m_maskData;
@@ -86,6 +85,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
 - (void)setQCocoaGLContext:(QCocoaGLContext *)context;
 #endif
 - (void)flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset;
+- (void)clearBackingStore:(QCocoaBackingStore *)backingStore;
 - (void)setMaskRegion:(const QRegion *)region;
 - (void)invalidateWindowShadowIfNeeded;
 - (void)drawRect:(NSRect)dirtyRect;
index d802a366766f786eb32d1ae3dcbcd44656cedec9..f27335d7527e486ff09eb9c736c298ac14f3aa0f 100644 (file)
@@ -135,7 +135,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
 {
     self = [super initWithFrame : NSMakeRect(0,0, 300,300)];
     if (self) {
-        m_pixelRatio = 1.;
+        m_backingStore = 0;
         m_maskImage = 0;
         m_shouldInvalidateWindowShadow = false;
         m_window = 0;
@@ -371,7 +371,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
         if (!m_platformWindow->m_inSetGeometry)
             QWindowSystemInterface::flushWindowSystemEvents();
         else
-            m_backingStore = QImage();
+            m_backingStore = 0;
     }
 }
 
@@ -476,12 +476,16 @@ QT_WARNING_POP
 
 - (void) flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset
 {
-    m_backingStore = backingStore->toImage();
-    m_pixelRatio = backingStore->getBackingStoreDevicePixelRatio();
-    m_backingStoreOffset = offset * m_pixelRatio;
-    foreach (QRect rect, region.rects()) {
+    m_backingStore = backingStore;
+    m_backingStoreOffset = offset * m_backingStore->getBackingStoreDevicePixelRatio();
+    foreach (QRect rect, region.rects())
         [self setNeedsDisplayInRect:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())];
-    }
+}
+
+- (void)clearBackingStore:(QCocoaBackingStore *)backingStore
+{
+    if (backingStore == m_backingStore)
+        m_backingStore = 0;
 }
 
 - (BOOL) hasMask
@@ -544,7 +548,7 @@ QT_WARNING_POP
     if (m_platformWindow->m_drawContentBorderGradient)
         NSDrawWindowBackground(dirtyRect);
 
-    if (m_backingStore.isNull())
+    if (!m_backingStore)
         return;
 
     // Calculate source and target rects. The target rect is the dirtyRect:
@@ -552,10 +556,11 @@ QT_WARNING_POP
 
     // The backing store source rect will be larger on retina displays.
     // Scale dirtyRect by the device pixel ratio:
-    CGRect dirtyBackingRect = CGRectMake(dirtyRect.origin.x * m_pixelRatio,
-                                         dirtyRect.origin.y * m_pixelRatio,
-                                         dirtyRect.size.width * m_pixelRatio,
-                                         dirtyRect.size.height * m_pixelRatio);
+    const qreal devicePixelRatio = m_backingStore->getBackingStoreDevicePixelRatio();
+    CGRect dirtyBackingRect = CGRectMake(dirtyRect.origin.x * devicePixelRatio,
+                                         dirtyRect.origin.y * devicePixelRatio,
+                                         dirtyRect.size.width * devicePixelRatio,
+                                         dirtyRect.size.height * devicePixelRatio);
 
     NSGraphicsContext *nsGraphicsContext = [NSGraphicsContext currentContext];
     CGContextRef cgContext = (CGContextRef) [nsGraphicsContext graphicsPort];
@@ -581,7 +586,7 @@ QT_WARNING_POP
         dirtyBackingRect.size.width,
         dirtyBackingRect.size.height
     );
-    CGImageRef bsCGImage = qt_mac_toCGImage(m_backingStore);
+    CGImageRef bsCGImage = qt_mac_toCGImage(m_backingStore->toImage());
     CGImageRef cleanImg = CGImageCreateWithImageInRect(bsCGImage, backingStoreRect);
 
     // Optimization: Copy frame buffer content instead of blending for