diff options
m--------- | src/3rdparty | 0 | ||||
-rw-r--r-- | src/core/chromium_gpu_helper.cpp | 28 | ||||
-rw-r--r-- | src/core/chromium_gpu_helper.h | 30 | ||||
-rw-r--r-- | src/core/delegated_frame_node.cpp | 92 | ||||
-rw-r--r-- | src/core/delegated_frame_node.h | 2 |
5 files changed, 81 insertions, 71 deletions
diff --git a/src/3rdparty b/src/3rdparty -Subproject 250eb95317140bf65dfd7b4dbc03ac20f45cde4 +Subproject 9005624091e3f5a9e9ff4d17d2bc5d32928ce35 diff --git a/src/core/chromium_gpu_helper.cpp b/src/core/chromium_gpu_helper.cpp index c4cb2ec0b..6287bd7c0 100644 --- a/src/core/chromium_gpu_helper.cpp +++ b/src/core/chromium_gpu_helper.cpp @@ -57,27 +57,17 @@ static void addSyncPointCallbackDelegate(content::SyncPointManager *syncPointMan syncPointManager->AddSyncPointCallback(sync_point, callback); } -FenceSync createFence() +QMap<uint32, gfx::TransferableFence> transferFences() { - FenceSync ret; - // Logic taken from chromium/ui/gl/gl_fence.cc -#if !defined(OS_MACOSX) - if (gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync) { - ret.type = FenceSync::EglSync; - ret.egl.display = eglGetCurrentDisplay(); - ret.egl.sync = eglCreateSyncKHR(ret.egl.display, EGL_SYNC_FENCE_KHR, NULL); - } else -#endif - if (gfx::g_driver_gl.ext.b_GL_ARB_sync) { - ret.type = FenceSync::ArbSync; - ret.arb.sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + QMap<uint32, gfx::TransferableFence> ret; + content::GpuChannelManager *gpuChannelManager = content::GpuChildThread::instance()->ChannelManager(); + content::GpuChannelManager::SyncPointGLFences::iterator it = gpuChannelManager->sync_point_gl_fences_.begin(); + content::GpuChannelManager::SyncPointGLFences::iterator end = gpuChannelManager->sync_point_gl_fences_.end(); + for (; it != end; ++it) { + ret[it->first] = it->second->Transfer(); + delete it->second; } - - // glFlush is necessary to make sure that our fence creation reaches the GL server - // before we try waiting on it from a different context, which could deadlock. - // In cases where no fence extension is available, this also serves as flushing - // Chromium's GL context command stream before yielding to the SG thread. - glFlush(); + gpuChannelManager->sync_point_gl_fences_.clear(); return ret; } diff --git a/src/core/chromium_gpu_helper.h b/src/core/chromium_gpu_helper.h index 364f82bbc..8b11c9b5f 100644 --- a/src/core/chromium_gpu_helper.h +++ b/src/core/chromium_gpu_helper.h @@ -38,8 +38,10 @@ #define CHROMIUM_GPU_HELPER_H #include <QtGlobal> // We need this for the Q_OS_QNX define. +#include <QMap> #include "base/callback.h" +#include "ui/gl/gl_fence.h" namespace base { class MessageLoop; @@ -57,38 +59,12 @@ class Texture; } } -typedef void *EGLDisplay; -typedef void *EGLSyncKHR; -typedef struct __GLsync *GLsync; - -union FenceSync { - enum SyncType { - NoSync, - EglSync, - ArbSync - }; - SyncType type; - struct { - SyncType type; - EGLDisplay display; - EGLSyncKHR sync; - } egl; - struct { - SyncType type; - GLsync sync; - } arb; - - FenceSync() : type(NoSync) { } - operator bool() { return type != NoSync; } - void reset() { type = NoSync; } -}; - // These functions wrap code that needs to include headers that are // incompatible with Qt GL headers. // From the outside, types from incompatible headers referenced in these // functions should only be forward-declared and considered as opaque types. -FenceSync createFence(); +QMap<uint32, gfx::TransferableFence> transferFences(); base::MessageLoop *gpu_message_loop(); content::SyncPointManager *sync_point_manager(); gpu::gles2::MailboxManager *mailbox_manager(); diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp index 57ce581f1..3d3e0dd8f 100644 --- a/src/core/delegated_frame_node.cpp +++ b/src/core/delegated_frame_node.cpp @@ -202,42 +202,74 @@ static QSGNode *buildLayerChain(QSGNode *chainParent, const cc::SharedQuadState return layerChain; } -static void waitAndDeleteChromiumSync(FenceSync *sync) +static void waitChromiumSync(gfx::TransferableFence *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: + case gfx::TransferableFence::NoSync: break; - case FenceSync::EglSync: + case gfx::TransferableFence::EglSync: #ifdef EGL_KHR_reusable_sync { static bool resolved = false; static PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR = 0; - static PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = 0; if (!resolved) { if (gfx::GLSurfaceQt::HasEGLExtension("EGL_KHR_reusable_sync")) { QOpenGLContext *context = QOpenGLContext::currentContext(); eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC)context->getProcAddress("eglClientWaitSyncKHR"); - eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)context->getProcAddress("eglDestroySyncKHR"); } resolved = true; } - if (eglClientWaitSyncKHR && eglDestroySyncKHR) { + if (eglClientWaitSyncKHR) // 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); + } +#endif + break; + case gfx::TransferableFence::ArbSync: +#ifdef GL_ARB_sync + glWaitSync(sync->arb.sync, 0, GL_TIMEOUT_IGNORED); +#endif + break; + } +} + +static void deleteChromiumSync(gfx::TransferableFence *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 gfx::TransferableFence::NoSync: + break; + case gfx::TransferableFence::EglSync: +#ifdef EGL_KHR_reusable_sync + { + static bool resolved = false; + static PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = 0; + + if (!resolved) { + if (gfx::GLSurfaceQt::HasEGLExtension("EGL_KHR_reusable_sync")) { + QOpenGLContext *context = QOpenGLContext::currentContext(); + eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)context->getProcAddress("eglDestroySyncKHR"); + } + resolved = true; + } + + if (eglDestroySyncKHR) { + // FIXME: Use the less wasteful eglWaitSyncKHR once we have a device that supports EGL_KHR_wait_sync. eglDestroySyncKHR(sync->egl.display, sync->egl.sync); sync->reset(); } } #endif break; - case FenceSync::ArbSync: + case gfx::TransferableFence::ArbSync: #ifdef GL_ARB_sync - glWaitSync(sync->arb.sync, 0, GL_TIMEOUT_IGNORED); glDeleteSync(sync->arb.sync); sync->reset(); #endif @@ -385,20 +417,33 @@ void DelegatedFrameNode::preprocess() mailboxesToFetch.append(mailboxTexture.data()); if (!mailboxesToFetch.isEmpty()) { - QMutexLocker lock(&m_mutex); - base::MessageLoop *gpuMessageLoop = gpu_message_loop(); - content::SyncPointManager *syncPointManager = sync_point_manager(); + QMap<uint32, gfx::TransferableFence> transferredFences; + { + QMutexLocker lock(&m_mutex); + base::MessageLoop *gpuMessageLoop = gpu_message_loop(); + content::SyncPointManager *syncPointManager = sync_point_manager(); + + Q_FOREACH (MailboxTexture *mailboxTexture, mailboxesToFetch) { + m_numPendingSyncPoints++; + AddSyncPointCallbackOnGpuThread(gpuMessageLoop, syncPointManager, mailboxTexture->resource().mailbox_holder.sync_point, base::Bind(&DelegatedFrameNode::syncPointRetired, this, &mailboxesToFetch)); + } - Q_FOREACH (MailboxTexture *mailboxTexture, mailboxesToFetch) { - m_numPendingSyncPoints++; - AddSyncPointCallbackOnGpuThread(gpuMessageLoop, syncPointManager, mailboxTexture->resource().mailbox_holder.sync_point, base::Bind(&DelegatedFrameNode::syncPointRetired, this, &mailboxesToFetch)); + m_mailboxesFetchedWaitCond.wait(&m_mutex); + m_mailboxGLFences.swap(transferredFences); } - 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); + // Tell GL to wait until Chromium is done generating resource textures on the GPU thread + // for each mailbox. We can safely start referencing those textures onto geometries afterward. + Q_FOREACH (MailboxTexture *mailboxTexture, mailboxesToFetch) { + gfx::TransferableFence fence = transferredFences.take(mailboxTexture->resource().mailbox_holder.sync_point); + waitChromiumSync(&fence); + deleteChromiumSync(&fence); + } + // We transferred all sync point fences from Chromium, + // destroy all the ones not referenced by one of our mailboxes without waiting. + QMap<uint32, gfx::TransferableFence>::iterator end = transferredFences.end(); + for (QMap<uint32, gfx::TransferableFence>::iterator it = transferredFences.begin(); it != end; ++it) + deleteChromiumSync(&*it); } // Then render any intermediate RenderPass in order. @@ -602,14 +647,13 @@ void DelegatedFrameNode::fetchTexturesAndUnlockQt(DelegatedFrameNode *frameNode, Q_FOREACH (MailboxTexture *mailboxTexture, *mailboxesToFetch) mailboxTexture->fetchTexture(mailboxManager); - // 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(); + // Pick fences that we can ask GL to wait for before trying to sample the mailbox texture IDs. + QMap<uint32, gfx::TransferableFence> transferredFences = transferFences(); // 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; + Q_ASSERT(frameNode->m_mailboxGLFences.isEmpty()); + frameNode->m_mailboxGLFences.swap(transferredFences); frameNode->m_mailboxesFetchedWaitCond.wakeOne(); } diff --git a/src/core/delegated_frame_node.h b/src/core/delegated_frame_node.h index 98861eefa..a031a464f 100644 --- a/src/core/delegated_frame_node.h +++ b/src/core/delegated_frame_node.h @@ -75,7 +75,7 @@ private: QExplicitlySharedDataPointer<DelegatedFrameNodeData> m_data; QList<QSharedPointer<RenderPassTexture> > m_renderPassTextures; int m_numPendingSyncPoints; - FenceSync m_mailboxesGLFence; + QMap<uint32, gfx::TransferableFence> m_mailboxGLFences; QWaitCondition m_mailboxesFetchedWaitCond; QMutex m_mutex; |