summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2018-07-31 14:59:37 +0200
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2018-10-03 13:04:41 +0000
commit01ade488ddf6dc667f38173ba3b2330224761f45 (patch)
tree51fd7f0eac2d633ece35e98df3b43fe11e377336
parenta154ea89e8ae4113f2dd63eb96864c9182f2c459 (diff)
macOS: Don't call [NSOpenGLContext update] for every frame
Calling update has a cost, and should only be done when the drawable object changes size or location. Instead of calling update each time makeCurrent is called, we listen for the appropriate notifications, limiting the number of update calls significantly. We still call update on the thread owning the QOpenGLContext, which is not ideal, as [NSOpenGLContext update] should only be called on the main thread, but in practice this works. Getting out of this situation is tricky, and setView has in theory the same problems. Until those problems have been solved we keep the behavior as is. Task-number: QTBUG-63572 Change-Id: Ibac9f8be7843f2aa006af6f7ee670bf027122440 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io> Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm37
2 files changed, 37 insertions, 3 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h
index cef5892989..eefb1cd0fb 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.h
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h
@@ -41,6 +41,7 @@
#define QCOCOAGLCONTEXT_H
#include <QtCore/QPointer>
+#include <QtCore/private/qcore_mac_p.h>
#include <qpa/qplatformopenglcontext.h>
#include <QtGui/QOpenGLContext>
#include <QtGui/QWindow>
@@ -79,6 +80,8 @@ private:
NSOpenGLContext *m_shareContext = nil;
QSurfaceFormat m_format;
bool m_didCheckForSoftwareContext = false;
+ QVarLengthArray<QMacScopedObserver, 3> m_updateObservers;
+ QAtomicInt m_needsUpdate = false;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index 069429796e..1e1b3907ed 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -41,7 +41,6 @@
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
#include <qdebug.h>
-#include <QtCore/private/qcore_mac_p.h>
#include <QtPlatformHeaders/qcocoanativecontext.h>
#include <dlfcn.h>
@@ -351,7 +350,8 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
}
}
- update();
+ if (m_needsUpdate.fetchAndStoreRelaxed(false))
+ update();
}
return true;
@@ -383,13 +383,44 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface)
if (view == m_context.view)
return true;
+ // Setting the drawable may happen on a separate thread as a result of
+ // a call to makeCurrent, so we need to set up the observers before we
+ // associate the view with the context. That way we will guarantee that
+ // as long as the view is the drawable of the context we will know about
+ // any updates to the view that require surface invalidation.
+
+ auto updateCallback = [this, view]() {
+ Q_ASSERT(QThread::currentThread() == qApp->thread());
+ if (m_context.view != view)
+ return;
+ m_needsUpdate = true;
+ };
+
+ m_updateObservers.clear();
+
+ if (view.layer) {
+ m_updateObservers.append(QMacScopedObserver(view, NSViewFrameDidChangeNotification, updateCallback));
+ m_updateObservers.append(QMacScopedObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback));
+ } else {
+ m_updateObservers.append(QMacScopedObserver(view, NSViewGlobalFrameDidChangeNotification, updateCallback));
+ }
+
+ m_updateObservers.append(QMacScopedObserver([NSApplication sharedApplication],
+ NSApplicationDidChangeScreenParametersNotification, updateCallback));
+
+ // If any of the observers fire at this point it's fine. We check the
+ // view association (atomically) in the update callback, and skip the
+ // update if we haven't associated yet. Setting the drawable below will
+ // have the same effect as an update.
+
+ // Now we are ready to associate the view with the context
if ((m_context.view = view) != view) {
qCInfo(lcQpaOpenGLContext) << "Failed to set" << view << "as drawable for" << m_context;
+ m_updateObservers.clear();
return false;
}
qCInfo(lcQpaOpenGLContext) << "Set drawable for" << m_context << "to" << m_context.view;
-
return true;
}