From 28b45ce1d9932fbb93041be2b7542ab4a6538564 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Mon, 1 Oct 2018 15:13:11 -0700 Subject: [PATCH] Resolve compositing glitches --- interface/src/Application.cpp | 52 +++++++++++-------- .../display-plugins/OpenGLDisplayPlugin.cpp | 2 + libraries/gl/src/gl/GLHelpers.cpp | 35 +++++++++++++ libraries/gl/src/gl/GLHelpers.h | 3 ++ libraries/gl/src/gl/OffscreenGLCanvas.cpp | 6 ++- libraries/gl/src/gl/OffscreenGLCanvas.h | 2 + .../qml/src/qml/impl/RenderEventHandler.cpp | 3 ++ 7 files changed, 80 insertions(+), 23 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 700561325f..6f65a124dd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2736,7 +2736,36 @@ void Application::initializeGL() { // We have to account for this possibility by checking here for an existing // global share context auto globalShareContext = qt_gl_global_share_context(); - _glWidget->createContext(globalShareContext); + +#if !defined(DISABLE_QML) + // Build a shared canvas / context for the Chromium processes + if (!globalShareContext) { + // Chromium rendering uses some GL functions that prevent nSight from capturing + // frames, so we only create the shared context if nsight is NOT active. + if (!nsightActive()) { + _chromiumShareContext = new OffscreenGLCanvas(); + _chromiumShareContext->setObjectName("ChromiumShareContext"); + auto format =QSurfaceFormat::defaultFormat(); +#ifdef Q_OS_MAC + // On mac, the primary shared OpenGL context must be a 3.2 core context, + // or chromium flips out and spews error spam (but renders fine) + format.setMajorVersion(3); + format.setMinorVersion(2); +#endif + _chromiumShareContext->setFormat(format); + _chromiumShareContext->create(); + if (!_chromiumShareContext->makeCurrent()) { + qCWarning(interfaceapp, "Unable to make chromium shared context current"); + } + globalShareContext = _chromiumShareContext->getContext(); + qt_gl_set_global_share_context(globalShareContext); + _chromiumShareContext->doneCurrent(); + } + } +#endif + + + _glWidget->createContext(globalShareContext); if (!_glWidget->makeCurrent()) { qCWarning(interfaceapp, "Unable to make window context current"); @@ -2749,27 +2778,6 @@ void Application::initializeGL() { if ((vendor.find("AMD") != std::string::npos) || (vendor.find("ATI") != std::string::npos)) { qputenv("QTWEBENGINE_CHROMIUM_FLAGS", QByteArray("--disable-distance-field-text")); } - - // Build a shared canvas / context for the Chromium processes - if (!globalShareContext) { - // Chromium rendering uses some GL functions that prevent nSight from capturing - // frames, so we only create the shared context if nsight is NOT active. - if (!nsightActive()) { - _chromiumShareContext = new OffscreenGLCanvas(); - _chromiumShareContext->setObjectName("ChromiumShareContext"); - _chromiumShareContext->create(_glWidget->qglContext()); - if (!_chromiumShareContext->makeCurrent()) { - qCWarning(interfaceapp, "Unable to make chromium shared context current"); - } - globalShareContext = _chromiumShareContext->getContext(); - qt_gl_set_global_share_context(globalShareContext); - _chromiumShareContext->doneCurrent(); - // Restore the GL widget context - if (!_glWidget->makeCurrent()) { - qCWarning(interfaceapp, "Unable to make window context current"); - } - } - } #endif if (!globalShareContext) { diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 6448c6d3a1..6525672aee 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -179,7 +179,9 @@ public: _context->makeCurrent(); { PROFILE_RANGE(render, "PluginPresent") + gl::globalLock(); currentPlugin->present(); + gl::globalRelease(false); CHECK_GL_ERROR(); } _context->doneCurrent(); diff --git a/libraries/gl/src/gl/GLHelpers.cpp b/libraries/gl/src/gl/GLHelpers.cpp index c22bd0dde5..ba27a13f58 100644 --- a/libraries/gl/src/gl/GLHelpers.cpp +++ b/libraries/gl/src/gl/GLHelpers.cpp @@ -34,6 +34,41 @@ bool gl::disableGl45() { #endif } +#ifdef Q_OS_MAC +#define SERIALIZE_GL_RENDERING +#endif + +#ifdef SERIALIZE_GL_RENDERING + +// This terrible terrible hack brought to you by the complete lack of reasonable +// OpenGL debugging tools on OSX. Without this serialization code, the UI textures +// frequently become 'glitchy' and get composited onto the main scene in what looks +// like a partially rendered state. +// This looks very much like either state bleeding across the contexts, or bad +// synchronization for the shared OpenGL textures. However, previous attempts to resolve +// it, even with gratuitous use of glFinish hasn't improved the situation + +static std::mutex _globalOpenGLLock; + +void gl::globalLock() { + _globalOpenGLLock.lock(); +} + +void gl::globalRelease(bool finish) { + if (finish) { + glFinish(); + } + _globalOpenGLLock.unlock(); +} + +#else + +void gl::globalLock() {} +void gl::globalRelease(bool finish) {} + +#endif + + void gl::getTargetVersion(int& major, int& minor) { #if defined(USE_GLES) major = 3; diff --git a/libraries/gl/src/gl/GLHelpers.h b/libraries/gl/src/gl/GLHelpers.h index 6252eba2f0..1865442ef6 100644 --- a/libraries/gl/src/gl/GLHelpers.h +++ b/libraries/gl/src/gl/GLHelpers.h @@ -35,6 +35,9 @@ int glVersionToInteger(QString glVersion); bool isRenderThread(); namespace gl { + void globalLock(); + void globalRelease(bool finish = true); + void withSavedContext(const std::function& f); bool checkGLError(const char* name); diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp index 1256e316ff..37289745a4 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -33,6 +33,7 @@ OffscreenGLCanvas::OffscreenGLCanvas() : _context(new QOpenGLContext), _offscreenSurface(new QOffscreenSurface) { + setFormat(getDefaultOpenGLSurfaceFormat()); } OffscreenGLCanvas::~OffscreenGLCanvas() { @@ -49,12 +50,15 @@ OffscreenGLCanvas::~OffscreenGLCanvas() { } +void OffscreenGLCanvas::setFormat(const QSurfaceFormat& format) { + _context->setFormat(format); +} + bool OffscreenGLCanvas::create(QOpenGLContext* sharedContext) { if (nullptr != sharedContext) { sharedContext->doneCurrent(); _context->setShareContext(sharedContext); } - _context->setFormat(getDefaultOpenGLSurfaceFormat()); if (!_context->create()) { qFatal("Failed to create OffscreenGLCanvas context"); } diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.h b/libraries/gl/src/gl/OffscreenGLCanvas.h index 374720a910..3946f760cf 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.h +++ b/libraries/gl/src/gl/OffscreenGLCanvas.h @@ -18,11 +18,13 @@ class QOpenGLContext; class QOffscreenSurface; class QOpenGLDebugMessage; +class QSurfaceFormat; class OffscreenGLCanvas : public QObject { public: OffscreenGLCanvas(); ~OffscreenGLCanvas(); + void setFormat(const QSurfaceFormat& format); bool create(QOpenGLContext* sharedContext = nullptr); bool makeCurrent(); void doneCurrent(); diff --git a/libraries/qml/src/qml/impl/RenderEventHandler.cpp b/libraries/qml/src/qml/impl/RenderEventHandler.cpp index 8a56929e6b..46fc3490a7 100644 --- a/libraries/qml/src/qml/impl/RenderEventHandler.cpp +++ b/libraries/qml/src/qml/impl/RenderEventHandler.cpp @@ -12,6 +12,7 @@ #include #include +#include #include @@ -114,6 +115,7 @@ void RenderEventHandler::onRender() { PROFILE_RANGE(render_qml_gl, __FUNCTION__); + gl::globalLock(); if (!_shared->preRender()) { return; } @@ -144,6 +146,7 @@ void RenderEventHandler::onRender() { _shared->updateTextureAndFence({ texture, fence }); _shared->_quickWindow->resetOpenGLState(); } + gl::globalRelease(); } void RenderEventHandler::onQuit() {