Skip to content

Commit

Permalink
macOS: Skip NSOpenGLContext flush if window exposed size is out of sync
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
torarnv committed Oct 24, 2019
1 parent 7c9ffe3 commit f39230f
Showing 1 changed file with 15 additions and 0 deletions.
15 changes: 15 additions & 0 deletions src/plugins/platforms/cocoa/qcocoaglcontext.mm
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,21 @@ static inline QByteArray getGlString(GLenum param)
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];
}
Expand Down

0 comments on commit f39230f

Please sign in to comment.