summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2019-10-18 16:23:48 +0200
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2019-10-24 12:33:40 +0200
commitf39230fcac4de01f26945bde16c3a10c5ac74afb (patch)
tree9c7949ba969b5100ff4fd6a7b3f947aa752a5ccc
parent7c9ffe3e46bca3cfdec6fd1db3da4c96a6d5acd6 (diff)
macOS: Skip NSOpenGLContext flush if window exposed size is out of sync
Some clients such as QOpenGLWidget will end up drawing and flushing during the resize event, which for GL will result in an immediate update on the screen. The problem is that the underlying Core Animation layer, and the window's frame, has not been visually updated yet to the new size, so we end up drawing "ahead" of what the window server is showing the user. Ideally we'd be able to present the GL drawing in a transaction, in sync with the drawing of the window frame, but this API is only available for CAMetalLayer and CAEAGLLayer. As a workaround we detect when the exposed size is out of sync with the window geometry, and skip the flush until the exposed size has caught up. We know this will happen eventually as AppKit will always ask us to display after a resize. Change-Id: I1739ac8878b3fc6820a55dd017ddd170fd5f55d6 Fixes: QTBUG-79139 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm15
1 files changed, 15 insertions, 0 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index 76a210d0b6..7452d53579 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -501,6 +501,21 @@ void QCocoaGLContext::swapBuffers(QPlatformSurface *surface)
return;
}
+ if (m_context.view.layer) {
+ // Flushing an NSOpenGLContext will hit the screen immediately, ignoring
+ // any Core Animation transactions in place. This may result in major
+ // visual artifacts if the flush happens out of sync with the size
+ // of the layer, view, and window reflected by other parts of the UI,
+ // e.g. if the application flushes in the resize event or a timer during
+ // window resizing, instead of in the expose event.
+ auto *cocoaWindow = static_cast<QCocoaWindow *>(surface);
+ if (cocoaWindow->geometry().size() != cocoaWindow->m_exposedRect.size()) {
+ qCInfo(lcQpaOpenGLContext) << "Window exposed size does not match geometry (yet)."
+ << "Skipping flush to avoid visual artifacts.";
+ return;
+ }
+ }
+
QMutexLocker locker(&s_reentrancyMutex);
[m_context flushBuffer];
}