diff options
author | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2019-10-18 16:23:48 +0200 |
---|---|---|
committer | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2019-10-24 12:33:40 +0200 |
commit | f39230fcac4de01f26945bde16c3a10c5ac74afb (patch) | |
tree | 9c7949ba969b5100ff4fd6a7b3f947aa752a5ccc /src/plugins/platforms/cocoa | |
parent | 7c9ffe3e46bca3cfdec6fd1db3da4c96a6d5acd6 (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>
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaglcontext.mm | 15 |
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]; } |