summaryrefslogtreecommitdiffstats
path: root/src/core/delegated_frame_node.cpp
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-04-10 17:32:36 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-04-10 21:03:22 +0200
commit682ddcd7187b16723af66d7f9c1b61bc060f44c1 (patch)
treeda181af0cbb3656a95c6b3c3b0708d6fda91a369 /src/core/delegated_frame_node.cpp
parentf61493ee97f285e4b7257f7590f45764980ca52e (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.cpp56
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();
}