diff options
author | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2018-07-31 14:59:37 +0200 |
---|---|---|
committer | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2018-10-03 13:04:41 +0000 |
commit | 01ade488ddf6dc667f38173ba3b2330224761f45 (patch) | |
tree | 51fd7f0eac2d633ece35e98df3b43fe11e377336 /src/plugins/platforms | |
parent | a154ea89e8ae4113f2dd63eb96864c9182f2c459 (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>
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaglcontext.h | 3 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaglcontext.mm | 37 |
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; } |