diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-04-10 17:32:36 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-04-10 21:03:22 +0200 |
commit | 682ddcd7187b16723af66d7f9c1b61bc060f44c1 (patch) | |
tree | da181af0cbb3656a95c6b3c3b0708d6fda91a369 /src/core/delegated_frame_node.cpp | |
parent | f61493ee97f285e4b7257f7590f45764980ca52e (diff) |
Use a fence sync to synchronize GL between threads
The NVidia driver needs more than a glFlush to ensure that GL commands
consuming Chromium resources are run only when the resource is completely
produced by the Chromium GPU thread.
This produces artifacts and an uneven frame rate in WebGL examples
on this kind of hardware.
Use the same mechanism as used by gfx::GLFence, doing a few things
manually to cope with the fact that Chromium and Qt both have their
own GL function table and contexts.
Change-Id: I33eeb1068994dc4176038a74579ce768b2bccb9d
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
Diffstat (limited to 'src/core/delegated_frame_node.cpp')
-rw-r--r-- | src/core/delegated_frame_node.cpp | 56 |
1 files changed, 53 insertions, 3 deletions
diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp index 1f7084d18..608d0b63a 100644 --- a/src/core/delegated_frame_node.cpp +++ b/src/core/delegated_frame_node.cpp @@ -75,6 +75,11 @@ #include <QtQuick/private/qsgrenderer_p.h> #include <QtQuick/private/qsgtexture_p.h> +#if !defined(QT_NO_EGL) +#include <EGL/egl.h> +#include <EGL/eglext.h> +#endif + class RenderPassTexture : public QSGTexture { public: @@ -205,6 +210,45 @@ static QSGNode *buildLayerChain(QSGNode *chainParent, const cc::SharedQuadState return layerChain; } +static void waitAndDeleteChromiumSync(FenceSync *sync) +{ + // Chromium uses its own GL bindings and stores in in thread local storage. + // For that reason, let chromium_gpu_helper.cpp contain the producing code that will run in the Chromium + // GPU thread, and put the sync consuming code here that will run in the QtQuick SG or GUI thread. + switch (sync->type) { + case FenceSync::NoSync: + break; + case FenceSync::EglSync: +#ifdef EGL_KHR_reusable_sync + static bool resolved = false; + static PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR = 0; + static PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = 0; + + if (!resolved) { + QOpenGLContext *context = QOpenGLContext::currentContext(); + eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC)context->getProcAddress("eglClientWaitSyncKHR"); + eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)context->getProcAddress("eglDestroySyncKHR"); + resolved = true; + } + + // FIXME: Use the less wasteful eglWaitSyncKHR once we have a device that supports EGL_KHR_wait_sync. + eglClientWaitSyncKHR(sync->egl.display, sync->egl.sync, 0, EGL_FOREVER_KHR); + eglDestroySyncKHR(sync->egl.display, sync->egl.sync); + sync->reset(); +#endif + break; + case FenceSync::ArbSync: +#ifdef GL_ARB_sync + glWaitSync(sync->arb.sync, 0, GL_TIMEOUT_IGNORED); + glDeleteSync(sync->arb.sync); + sync->reset(); +#endif + break; + } + // If Chromium was able to create a sync, we should have been able to handle its type here too. + Q_ASSERT(!*sync); +} + RenderPassTexture::RenderPassTexture(const cc::RenderPass::Id &id, QSGRenderContext *context) : QSGTexture() , m_id(id) @@ -317,6 +361,10 @@ void DelegatedFrameNode::preprocess() } m_mailboxesFetchedWaitCond.wait(&m_mutex); + + // Tell GL to wait until Chromium is done generating resource textures on the GPU thread. + // We can safely start referencing those textures onto geometries afterward. + waitAndDeleteChromiumSync(&m_mailboxesGLFence); } // Then render any intermediate RenderPass in order. @@ -533,12 +581,14 @@ void DelegatedFrameNode::fetchTexturesAndUnlockQt(DelegatedFrameNode *frameNode, Q_FOREACH (MailboxTexture *mailboxTexture, *mailboxesToFetch) mailboxTexture->fetchTexture(mailboxManager); - // glFlush before yielding to the SG thread, whose context might already start using - // some shared resources provided by the unflushed context here, on the Chromium GPU thread. - glFlush(); + // Set a fence at this point in Chromium's GL command stream + // and transfer the handle to the Qt scene graph thread. + FenceSync fence = createFence(); // Chromium provided everything we were waiting for, let Qt start rendering. QMutexLocker lock(&frameNode->m_mutex); + Q_ASSERT(!frameNode->m_mailboxesGLFence); + frameNode->m_mailboxesGLFence = fence; frameNode->m_mailboxesFetchedWaitCond.wakeOne(); } |