summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2013-10-29 16:21:46 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-11-11 17:25:25 +0100
commit7403ef5908cf2d2e81e5cedf44cb2536bd1b9ac2 (patch)
tree80e664cce4b4ff3cfeba0c21eda2a92ca7c339c3
parent258e3aad97be370663983573b557c4115db3fafb (diff)
Delegated renderer: Put textures on those quads.
A few changes are necessary to allow fetching textures provided by the render processes through IPC and bound to their respective GL context in the GPU process and use them in the QtQuick scene graph. - Remove the plain color test textures. - Allow setting the QtQuick QOpenGLContext's handle as the share context for all context set as shared in the Chromium GPU process. We do this by letting the GpuChannelManager ask us for a ShareGroup instance responsible for returning a sharing GL context handle. - Fetch texture IDs from the MailboxManager used by the GPU process using the Mailbox given to us in the DelegatedFrameData. This is the same mechanism used by Chromium to share textures between "client" GL contexts. - Keep the QtQuick scene graph threads and Chromium in-process GPU thread separate. The complicated part of merging those two rendering pipelines on the same thread is that it would force Qt to also use only one thread for rendering. For the moment we will try to synchronize those threads together instead. - Lock the Qt SG thread while waiting for resource sync points. Do so by posting a callback to the Chromium GPU thread and wait until the sync point of every resource has been retired by the producing contexts. - Acknowledge the delegated from once QtQuick swapped the GL buffers instead of right after we added the frame to the scene graph. This fixes some issues where the textures for the previous frame would already be released as Chromium was producing the new frame. There are still a few issues regarding synchronization that have to be fixed, especially when Qt triggers the rendering of a new frame while Chromium is starting to produce the next frame. Note: To enable it we still need to pass the following command switches: --enable-delegated-renderer --enable-threaded-compositing --in-process-gpu Change-Id: I2d4f7fac603b1808ed1495a8d689cb48e9ed41b9 Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
m---------3rdparty0
-rw-r--r--examples/quick/quicknanobrowser/main.cpp8
-rw-r--r--examples/quick/quicknanobrowser/quicknanobrowser.pro2
-rw-r--r--lib/chromium_gpu_helper.cpp86
-rw-r--r--lib/chromium_gpu_helper.h76
-rw-r--r--lib/content_browser_client_qt.cpp64
-rw-r--r--lib/content_browser_client_qt.h9
-rw-r--r--lib/delegated_frame_node.cpp202
-rw-r--r--lib/delegated_frame_node.h14
-rw-r--r--lib/lib.pro2
-rw-r--r--lib/quick/render_widget_host_view_qt_delegate_quick.cpp19
-rw-r--r--lib/quick/render_widget_host_view_qt_delegate_quick.h5
-rw-r--r--lib/render_widget_host_view_qt.cpp43
-rw-r--r--lib/render_widget_host_view_qt.h6
-rw-r--r--lib/render_widget_host_view_qt_delegate.h1
-rw-r--r--lib/type_conversion.h5
-rw-r--r--lib/web_engine_context.cpp8
-rw-r--r--patches/0001-Add-accessors-for-the-Qt-delegated-renderer-integrat.patch84
-rw-r--r--patches/0001-Add-seams-to-setup-GL-contexts-sharing-with-QtQuick.patch109
-rwxr-xr-xpatches/patch-chromium.sh2
20 files changed, 667 insertions, 78 deletions
diff --git a/3rdparty b/3rdparty
-Subproject 63f1510d708ce6e90354c63655fa21bd4906e52
+Subproject 9427c1a0222ebd67efef1a2c7990a0fa5c9aac8
diff --git a/examples/quick/quicknanobrowser/main.cpp b/examples/quick/quicknanobrowser/main.cpp
index 982c1eb7a..6c2f91de6 100644
--- a/examples/quick/quicknanobrowser/main.cpp
+++ b/examples/quick/quicknanobrowser/main.cpp
@@ -47,11 +47,19 @@ typedef QApplication Application;
#include <QtGui/QGuiApplication>
typedef QGuiApplication Application;
#endif
+#include <QtQuick/private/qsgcontext_p.h>
int main(int argc, char **argv)
{
Application app(argc, argv);
+ // This is currently needed by all QtWebEngine application using the HW accelerated QQuickWebView.
+ // It enables sharing between the QOpenGLContext of all QQuickWindows of the application.
+ // We have to do so until we expose a public API for it, or chose enable it by default in Qt 5.3.0.
+ QOpenGLContext shareContext;
+ shareContext.create();
+ QSGContext::setSharedOpenGLContext(&shareContext);
+
ApplicationEngine appEngine;
return app.exec();
diff --git a/examples/quick/quicknanobrowser/quicknanobrowser.pro b/examples/quick/quicknanobrowser/quicknanobrowser.pro
index c32540a71..2132b031a 100644
--- a/examples/quick/quicknanobrowser/quicknanobrowser.pro
+++ b/examples/quick/quicknanobrowser/quicknanobrowser.pro
@@ -12,6 +12,8 @@ RESOURCES += resources.qrc
RESOURCES += ../../common/common_resources.qrc
QT += qml quick
+QT_PRIVATE += quick-private gui-private core-private
+
qtHaveModule(widgets) {
QT += widgets # QApplication is required to get native styling with QtQuickControls
}
diff --git a/lib/chromium_gpu_helper.cpp b/lib/chromium_gpu_helper.cpp
new file mode 100644
index 000000000..3d393c25d
--- /dev/null
+++ b/lib/chromium_gpu_helper.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "chromium_gpu_helper.h"
+
+#include "content/common/gpu/gpu_channel_manager.h"
+#include "content/common/gpu/sync_point_manager.h"
+#include "content/gpu/gpu_child_thread.h"
+#include "gpu/command_buffer/service/mailbox_manager.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+
+static void addSyncPointCallbackDelegate(content::SyncPointManager *syncPointManager, uint32 sync_point, const base::Closure& callback)
+{
+ syncPointManager->AddSyncPointCallback(sync_point, callback);
+}
+
+base::MessageLoop *gpu_message_loop()
+{
+ return content::GpuChildThread::instance()->message_loop();
+}
+
+content::SyncPointManager *sync_point_manager()
+{
+ content::GpuChannelManager *gpuChannelManager = content::GpuChildThread::instance()->ChannelManager();
+ return gpuChannelManager->sync_point_manager();
+}
+
+void AddSyncPointCallbackOnGpuThread(base::MessageLoop *gpuMessageLoop, content::SyncPointManager *syncPointManager, uint32 sync_point, const base::Closure& callback)
+{
+ // We need to set our callback from the GPU thread, where the SyncPointManager lives.
+ gpuMessageLoop->PostTask(FROM_HERE, base::Bind(&addSyncPointCallbackDelegate, make_scoped_refptr(syncPointManager), sync_point, callback));
+}
+
+gpu::gles2::MailboxManager *mailbox_manager()
+{
+ content::GpuChannelManager *gpuChannelManager = content::GpuChildThread::instance()->ChannelManager();
+ return gpuChannelManager->mailbox_manager();
+}
+
+gpu::gles2::Texture* ConsumeTexture(gpu::gles2::MailboxManager *mailboxManager, unsigned target, const gpu::gles2::MailboxName& name)
+{
+ return mailboxManager->ConsumeTexture(target, name);
+}
+
+unsigned int service_id(gpu::gles2::Texture *tex)
+{
+ return tex->service_id();
+}
diff --git a/lib/chromium_gpu_helper.h b/lib/chromium_gpu_helper.h
new file mode 100644
index 000000000..e0ac8e2a3
--- /dev/null
+++ b/lib/chromium_gpu_helper.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CHROMIUM_GPU_HELPER_H
+#define CHROMIUM_GPU_HELPER_H
+
+#include "base/callback.h"
+
+namespace base {
+class MessageLoop;
+}
+
+namespace content {
+class SyncPointManager;
+}
+
+namespace gpu {
+namespace gles2 {
+class MailboxManager;
+class MailboxName;
+class Texture;
+}
+}
+
+// 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.
+
+base::MessageLoop *gpu_message_loop();
+content::SyncPointManager *sync_point_manager();
+gpu::gles2::MailboxManager *mailbox_manager();
+
+void AddSyncPointCallbackOnGpuThread(base::MessageLoop *gpuMessageLoop, content::SyncPointManager *syncPointManager, uint32 sync_point, const base::Closure& callback);
+gpu::gles2::Texture* ConsumeTexture(gpu::gles2::MailboxManager *mailboxManager, unsigned target, const gpu::gles2::MailboxName& name);
+unsigned int service_id(gpu::gles2::Texture *tex);
+
+#endif // CHROMIUM_GPU_HELPER_H
diff --git a/lib/content_browser_client_qt.cpp b/lib/content_browser_client_qt.cpp
index 4ff15d3b1..97d5c8e4e 100644
--- a/lib/content_browser_client_qt.cpp
+++ b/lib/content_browser_client_qt.cpp
@@ -50,12 +50,17 @@
#include "grit/net_resources.h"
#include "net/base/net_module.h"
#include "ui/base/resource/resource_bundle.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_share_group.h"
#include "browser_context_qt.h"
#include "dev_tools_http_handler_delegate_qt.h"
#include "web_contents_view_qt.h"
-#include <QCoreApplication>
+#include <QGuiApplication>
+#include <QtQuick/private/qsgcontext_p.h>
+#include <qpa/qplatformnativeinterface.h>
namespace {
@@ -202,6 +207,57 @@ private:
DISALLOW_COPY_AND_ASSIGN(BrowserMainPartsQt);
};
+class QtShareGLContext : public gfx::GLContext {
+public:
+ QtShareGLContext(QOpenGLContext *qtContext)
+ : gfx::GLContext(0)
+ , m_handle(0)
+ {
+ QString platform = qApp->platformName();
+ QPlatformNativeInterface *pni = QGuiApplication::platformNativeInterface();
+ if (platform == QStringLiteral("xcb")) {
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2)
+ m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext);
+ else
+ m_handle = pni->nativeResourceForContext(QByteArrayLiteral("glxcontext"), qtContext);
+ } else if (platform == QStringLiteral("Cocoa"))
+ m_handle = pni->nativeResourceForContext(QByteArrayLiteral("cglcontextobj"), qtContext);
+ else
+ // Add missing platforms once they work.
+ Q_UNREACHABLE();
+ }
+
+ virtual void* GetHandle() { return m_handle; }
+
+ // We don't care about the rest, this context shouldn't be used except for its handle.
+ virtual bool Initialize(gfx::GLSurface *, gfx::GpuPreference) { Q_UNREACHABLE(); return false; }
+ virtual void Destroy() { Q_UNREACHABLE(); }
+ virtual bool MakeCurrent(gfx::GLSurface *) { Q_UNREACHABLE(); return false; }
+ virtual void ReleaseCurrent(gfx::GLSurface *) { Q_UNREACHABLE(); }
+ virtual bool IsCurrent(gfx::GLSurface *) { Q_UNREACHABLE(); return false; }
+ virtual void SetSwapInterval(int) { Q_UNREACHABLE(); }
+
+private:
+ void *m_handle;
+};
+
+class ShareGroupQtQuick : public gfx::GLShareGroup {
+public:
+ virtual gfx::GLContext* GetContext() Q_DECL_OVERRIDE { return m_shareContextQtQuick.get(); }
+ virtual void AboutToAddFirstContext() Q_DECL_OVERRIDE;
+
+private:
+ scoped_refptr<QtShareGLContext> m_shareContextQtQuick;
+};
+
+void ShareGroupQtQuick::AboutToAddFirstContext()
+{
+ // This currently has to be setup by ::main in all applications using QQuickWebEngineView with delegated rendering.
+ QOpenGLContext *shareContext = QSGContext::sharedOpenGLContext();
+ Q_ASSERT(shareContext);
+ m_shareContextQtQuick = make_scoped_refptr(new QtShareGLContext(shareContext));
+}
+
content::WebContentsViewPort* ContentBrowserClientQt::OverrideCreateWebContentsView(content::WebContents* web_contents,
content::RenderViewHostDelegateView** render_view_host_delegate_view)
{
@@ -239,6 +295,12 @@ void ContentBrowserClientQt::RenderProcessHostCreated(content::RenderProcessHost
content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme(host->GetID(), chrome::kFileScheme);
}
+gfx::GLShareGroup *ContentBrowserClientQt::GetInProcessGpuShareGroup()
+{
+ if (!m_shareGroupQtQuick)
+ m_shareGroupQtQuick = new ShareGroupQtQuick;
+ return m_shareGroupQtQuick.get();
+}
BrowserContextQt* ContentBrowserClientQt::browser_context() {
Q_ASSERT(m_browserMainParts);
diff --git a/lib/content_browser_client_qt.h b/lib/content_browser_client_qt.h
index f8c42e569..b97eaa5e1 100644
--- a/lib/content_browser_client_qt.h
+++ b/lib/content_browser_client_qt.h
@@ -44,6 +44,7 @@
#include "base/memory/scoped_ptr.h"
#include "content/public/browser/content_browser_client.h"
+
#include <QtCore/qcompilerdetection.h> // Needed for Q_DECL_OVERRIDE
namespace net {
@@ -60,9 +61,14 @@ class WebContents;
struct MainFunctionParams;
}
+namespace gfx {
+class GLShareGroup;
+}
+
class BrowserContextQt;
class BrowserMainPartsQt;
class DevToolsHttpHandlerDelegateQt;
+class ShareGroupQtQuick;
class ContentBrowserClientQt : public content::ContentBrowserClient {
@@ -73,6 +79,7 @@ public:
virtual content::WebContentsViewPort* OverrideCreateWebContentsView(content::WebContents* , content::RenderViewHostDelegateView**) Q_DECL_OVERRIDE;
virtual content::BrowserMainParts* CreateBrowserMainParts(const content::MainFunctionParams&) Q_DECL_OVERRIDE;
virtual void RenderProcessHostCreated(content::RenderProcessHost* host) Q_DECL_OVERRIDE;
+ virtual gfx::GLShareGroup* GetInProcessGpuShareGroup() Q_DECL_OVERRIDE;
BrowserContextQt* browser_context();
@@ -83,7 +90,7 @@ public:
private:
BrowserMainPartsQt* m_browserMainParts;
scoped_ptr<DevToolsHttpHandlerDelegateQt> m_devtools;
-
+ scoped_refptr<ShareGroupQtQuick> m_shareGroupQtQuick;
};
#endif // CONTENT_BROWSER_CLIENT_QT_H
diff --git a/lib/delegated_frame_node.cpp b/lib/delegated_frame_node.cpp
index dea9605be..0e3f34fff 100644
--- a/lib/delegated_frame_node.cpp
+++ b/lib/delegated_frame_node.cpp
@@ -52,8 +52,11 @@
#define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
#endif
+#include "chromium_gpu_helper.h"
#include "type_conversion.h"
+#include "base/message_loop/message_loop.h"
+#include "base/bind.h"
#include "cc/output/delegated_frame_data.h"
#include "cc/quads/draw_quad.h"
#include "cc/quads/render_pass_draw_quad.h"
@@ -66,6 +69,7 @@
#include <QtQuick/private/qquickwindow_p.h>
#include <QtQuick/private/qsgcontext_p.h>
#include <QtQuick/private/qsgrenderer_p.h>
+#include <QtQuick/private/qsgtexture_p.h>
class RenderPassTexture : public QSGTexture
{
@@ -100,14 +104,41 @@ private:
QSGRenderContext *m_context;
};
-class RawTextureNode : public QSGSimpleTextureNode {
+class MailboxTexture : public QSGTexture {
public:
- RawTextureNode(GLuint textureId, const QSize &textureSize, bool hasAlpha, QQuickWindow *window);
+ MailboxTexture(const cc::TransferableResource *resource, bool hasAlpha);
+ virtual int textureId() const { return m_textureId; }
+ void setTextureSize(const QSize& size) { m_textureSize = size; }
+ virtual QSize textureSize() const { return m_textureSize; }
+ virtual bool hasAlphaChannel() const { return m_hasAlpha; }
+ virtual bool hasMipmaps() const { return false; }
+ virtual void bind();
+
+ bool needsToFetch() const { return m_resource; }
+ const cc::TransferableResource *resource() const { return m_resource; }
+ void fetchTexture(gpu::gles2::MailboxManager *mailboxManager);
private:
- QScopedPointer<QSGTexture> m_texture;
+ // This is just a pointer to the cc::DelegatedFrameData. It has to be held until DelegatedFrameNode::preprocess is done.
+ const cc::TransferableResource *m_resource;
+ int m_textureId;
+ QSize m_textureSize;
+ bool m_hasAlpha;
};
+static const cc::TransferableResource *findResource(const cc::TransferableResourceArray &array, unsigned id)
+{
+ // A 0 ID means that there is no resource.
+ if (!id)
+ return 0;
+
+ for (unsigned i = 0; i < array.size(); ++i) {
+ const cc::TransferableResource &res = array.at(i);
+ if (res.id == id)
+ return &res;
+ }
+ return 0;
+}
static inline QSharedPointer<RenderPassTexture> findRenderPassTexture(const cc::RenderPass::Id &id, const QList<QSharedPointer<RenderPassTexture> > &list)
{
@@ -182,7 +213,6 @@ static QSGNode *buildLayerChain(QSGNode *chainParent, const cc::SharedQuadState
return layerChain;
}
-
RenderPassTexture::RenderPassTexture(const cc::RenderPass::Id &id, QSGRenderContext *context)
: QSGTexture()
, m_id(id)
@@ -235,55 +265,79 @@ void RenderPassTexture::grab()
m_context->renderNextFrame(m_renderer.data(), m_fbo->handle());
}
-RawTextureNode::RawTextureNode(GLuint textureId, const QSize &textureSize, bool hasAlpha, QQuickWindow *window)
- : m_texture(window->createTextureFromId(textureId, textureSize, QQuickWindow::CreateTextureOption(hasAlpha ? QQuickWindow::TextureHasAlphaChannel : 0)))
+MailboxTexture::MailboxTexture(const cc::TransferableResource *resource, bool hasAlpha)
+ : m_resource(resource)
+ , m_textureId(0)
+ , m_textureSize(toQt(resource->size))
+ , m_hasAlpha(hasAlpha)
{
- setTexture(m_texture.data());
+}
+
+void MailboxTexture::bind()
+{
+ glBindTexture(GL_TEXTURE_2D, m_textureId);
+}
+
+void MailboxTexture::fetchTexture(gpu::gles2::MailboxManager *mailboxManager)
+{
+ Q_ASSERT(m_resource);
+ gpu::gles2::Texture *tex = ConsumeTexture(mailboxManager, GL_TEXTURE_2D, *reinterpret_cast<const gpu::gles2::MailboxName*>(m_resource->mailbox.name));
+
+ // The texture might already have been deleted.
+ // FIXME: We might be able to avoid this check with better synchronization.
+ if (tex)
+ m_textureId = service_id(tex);
+
+ // We do not need to fetch this texture again.
+ m_resource = 0;
}
DelegatedFrameNode::DelegatedFrameNode(QQuickWindow *window)
: m_window(window)
- , m_testTexturesSize(sizeof(m_testTextures) / sizeof(GLuint))
+ , m_numPendingSyncPoints(0)
{
setFlag(UsePreprocess);
-
- // Generate plain color textures to be used until we can use the real textures from the ResourceProvider.
- glGenTextures(m_testTexturesSize, m_testTextures);
- for (unsigned i = 0; i < m_testTexturesSize; ++i) {
- QImage image(1, 1, QImage::Format_ARGB32_Premultiplied);
- image.fill(static_cast<Qt::GlobalColor>(i + Qt::red));
-
- // Swizzle
- const int width = image.width();
- const int height = image.height();
- for (int j = 0; j < height; ++j) {
- uint *p = (uint *) image.scanLine(j);
- for (int x = 0; x < width; ++x)
- p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
- }
-
- glBindTexture(GL_TEXTURE_2D, m_testTextures[i]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.constBits() );
- }
}
DelegatedFrameNode::~DelegatedFrameNode()
{
- glDeleteTextures(m_testTexturesSize, m_testTextures);
}
void DelegatedFrameNode::preprocess()
{
- // Render any intermediate RenderPass in order.
- Q_FOREACH (const QSharedPointer<RenderPassTexture> &texture, m_renderPassTextures)
- texture->grab();
+ // With the threaded render loop the GUI thread has been unlocked at this point.
+ // We can now wait for the Chromium GPU thread to produce textures that will be
+ // rendered on our quads and fetch the IDs from the mailboxes we were given.
+ QList<MailboxTexture *> mailboxesToFetch;
+ Q_FOREACH (const QSharedPointer<MailboxTexture> &mailboxTexture, m_mailboxTextures.values())
+ if (mailboxTexture->needsToFetch())
+ mailboxesToFetch.append(mailboxTexture.data());
+
+ if (!mailboxesToFetch.isEmpty()) {
+ 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()->sync_point, base::Bind(&DelegatedFrameNode::syncPointRetired, this, &mailboxesToFetch));
+ }
+
+ m_mailboxesFetchedWaitCond.wait(&m_mutex);
+ }
+
+ // Then render any intermediate RenderPass in order.
+ Q_FOREACH (const QSharedPointer<RenderPassTexture> &renderPass, m_renderPassTextures)
+ renderPass->grab();
}
void DelegatedFrameNode::commit(cc::DelegatedFrameData *frameData)
{
- // Keep the old list around to find the ones we can re-use.
+ // Keep the old texture lists around to find the ones we can re-use.
QList<QSharedPointer<RenderPassTexture> > oldRenderPassTextures;
m_renderPassTextures.swap(oldRenderPassTextures);
+ QMap<int, QSharedPointer<MailboxTexture> > oldMailboxTextures;
+ m_mailboxTextures.swap(oldMailboxTextures);
// The RenderPasses list is actually a tree where a parent RenderPass is connected
// to its dependencies through a RenderPass::Id reference in one or more RenderPassQuads.
@@ -330,37 +384,97 @@ void DelegatedFrameNode::commit(cc::DelegatedFrameData *frameData)
currentLayerChain = buildLayerChain(renderPassChain, currentLayerState);
}
- QSGSimpleTextureNode *textureNode = 0;
switch (quad->material) {
case cc::DrawQuad::RENDER_PASS: {
const cc::RenderPassDrawQuad *renderPassQuad = cc::RenderPassDrawQuad::MaterialCast(quad);
QSGTexture *texture = findRenderPassTexture(renderPassQuad->render_pass_id, m_renderPassTextures).data();
if (texture) {
- textureNode = new QSGSimpleTextureNode;
+ QSGSimpleTextureNode *textureNode = new QSGSimpleTextureNode;
+ textureNode->setRect(toQt(quad->rect));
textureNode->setTexture(texture);
+ currentLayerChain->appendChildNode(textureNode);
} else {
qWarning("Unknown RenderPass layer: Id %d", renderPassQuad->render_pass_id.layer_id);
- textureNode = new RawTextureNode(0, QSize(1, 1), false, m_window);
+ continue;
}
break;
} case cc::DrawQuad::TEXTURE_CONTENT: {
- uint32 resourceId = cc::TextureDrawQuad::MaterialCast(quad)->resource_id;
- textureNode = new RawTextureNode(m_testTextures[resourceId % m_testTexturesSize], QSize(1, 1), false, m_window);
+ const cc::TextureDrawQuad *tquad = cc::TextureDrawQuad::MaterialCast(quad);
+ const cc::TransferableResource *res = findResource(frameData->resource_list, tquad->resource_id);
+
+ // See if we already have a texture for this resource ID. The ID changes when the contents is updated,
+ // even if the GL texture ID is the same as a previous resource.
+ // Reusing a texture only saves us the sync point waiting and mailbox fetching.
+ QSharedPointer<MailboxTexture> &texture = m_mailboxTextures[res->id] = oldMailboxTextures.value(res->id);
+ if (!texture) {
+ texture = QSharedPointer<MailboxTexture>(new MailboxTexture(res, quad->ShouldDrawWithBlending()));
+ // TransferableResource::size isn't always set properly for TextureDrawQuads, use the size of its DrawQuad::rect instead.
+ texture->setTextureSize(toQt(quad->rect.size()));
+ }
+
+ QSGSimpleTextureNode *textureNode = new QSGSimpleTextureNode;
+ textureNode->setTextureCoordinatesTransform(tquad->flipped ? QSGSimpleTextureNode::MirrorVertically : QSGSimpleTextureNode::NoTransform);
+ textureNode->setRect(toQt(quad->rect));
+ textureNode->setFiltering(res->filter == GL_LINEAR ? QSGTexture::Linear : QSGTexture::Nearest);
+ textureNode->setTexture(texture.data());
+ currentLayerChain->appendChildNode(textureNode);
break;
} case cc::DrawQuad::TILED_CONTENT: {
- uint32 resourceId = cc::TileDrawQuad::MaterialCast(quad)->resource_id;
- textureNode = new RawTextureNode(m_testTextures[resourceId % m_testTexturesSize], QSize(1, 1), false, m_window);
+ const cc::TileDrawQuad *tquad = cc::TileDrawQuad::MaterialCast(quad);
+ const cc::TransferableResource *res = findResource(frameData->resource_list, tquad->resource_id);
+
+ QSharedPointer<MailboxTexture> &texture = m_mailboxTextures[res->id] = oldMailboxTextures.value(res->id);
+ if (!texture)
+ texture = QSharedPointer<MailboxTexture>(new MailboxTexture(res, quad->ShouldDrawWithBlending()));
+
+ QSGSimpleTextureNode *textureNode = new QSGSimpleTextureNode;
+ textureNode->setRect(toQt(quad->rect));
+ textureNode->setFiltering(res->filter == GL_LINEAR ? QSGTexture::Linear : QSGTexture::Nearest);
+ textureNode->setTexture(texture.data());
+
+ // FIXME: Find out if we can implement a QSGSimpleTextureNode::setSourceRect instead of this hack.
+ // This has to be done at the end since many QSGSimpleTextureNode methods would overwrite this.
+ QSGGeometry::updateTexturedRectGeometry(textureNode->geometry(), textureNode->rect(), textureNode->texture()->convertToNormalizedSourceRect(toQt(tquad->tex_coord_rect)));
+ currentLayerChain->appendChildNode(textureNode);
+
break;
} default:
qWarning("Unimplemented quad material: %d", quad->material);
- textureNode = new RawTextureNode(0, QSize(1, 1), false, m_window);
+ continue;
}
-
- textureNode->setRect(toQt(quad->rect));
- textureNode->setFiltering(QSGTexture::Linear);
- currentLayerChain->appendChildNode(textureNode);
}
}
}
+void DelegatedFrameNode::fetchTexturesAndUnlockQt(DelegatedFrameNode *frameNode, QList<MailboxTexture *> *mailboxesToFetch)
+{
+ // Fetch texture IDs from the mailboxes while we're on the GPU thread, where the MailboxManager lives.
+ gpu::gles2::MailboxManager *mailboxManager = mailbox_manager();
+ 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();
+
+ // Chromium provided everything we were waiting for, let Qt start rendering.
+ QMutexLocker lock(&frameNode->m_mutex);
+ frameNode->m_mailboxesFetchedWaitCond.wakeOne();
+}
+
+void DelegatedFrameNode::syncPointRetired(DelegatedFrameNode *frameNode, QList<MailboxTexture *> *mailboxesToFetch)
+{
+ // The way that sync points are normally used by the GpuCommandBufferStub is that it asks
+ // the GpuScheduler to resume the work of the associated GL command stream / context once
+ // the sync point has been retired by the dependency's context. In other words, a produced
+ // texture means that the mailbox can be consumed, but the texture itself isn't expected
+ // to be ready until to control is given back to the GpuScheduler through the event loop.
+ // Do the same for our implementation by posting a message to the event loop once the last
+ // of our syncpoints has been retired (the syncpoint callback is called synchronously) and
+ // only at this point we wake the Qt rendering thread.
+ QMutexLocker lock(&frameNode->m_mutex);
+ if (!--frameNode->m_numPendingSyncPoints)
+ base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&DelegatedFrameNode::fetchTexturesAndUnlockQt, frameNode, mailboxesToFetch));
+}
+
#endif // QT_VERSION
diff --git a/lib/delegated_frame_node.h b/lib/delegated_frame_node.h
index 9eb9b5c48..0b6657e98 100644
--- a/lib/delegated_frame_node.h
+++ b/lib/delegated_frame_node.h
@@ -42,8 +42,10 @@
#ifndef DELEGATED_FRAME_NODE_H
#define DELEGATED_FRAME_NODE_H
+#include <QMutex>
#include <QSGNode>
#include <QSharedPointer>
+#include <QWaitCondition>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
@@ -55,6 +57,7 @@ namespace cc {
class DelegatedFrameData;
}
+class MailboxTexture;
class RenderPassTexture;
class DelegatedFrameNode : public QSGNode {
@@ -67,8 +70,15 @@ public:
private:
QQuickWindow *m_window;
QList<QSharedPointer<RenderPassTexture> > m_renderPassTextures;
- const size_t m_testTexturesSize;
- GLuint m_testTextures[Qt::transparent - Qt::red];
+ QMap<int, QSharedPointer<MailboxTexture> > m_mailboxTextures;
+ int m_numPendingSyncPoints;
+ QWaitCondition m_mailboxesFetchedWaitCond;
+ QMutex m_mutex;
+
+ // Making those callbacks static bypasses base::Bind's ref-counting requirement
+ // of the this pointer when the callback is a method.
+ static void fetchTexturesAndUnlockQt(DelegatedFrameNode *frameNode, QList<MailboxTexture *> *mailboxesToFetch);
+ static void syncPointRetired(DelegatedFrameNode *frameNode, QList<MailboxTexture *> *mailboxesToFetch);
};
#endif // QT_VERSION
diff --git a/lib/lib.pro b/lib/lib.pro
index c25920b16..32af217b6 100644
--- a/lib/lib.pro
+++ b/lib/lib.pro
@@ -40,6 +40,7 @@ SOURCES = \
delegated_frame_node.cpp \
dev_tools_http_handler_delegate_qt.cpp \
download_manager_delegate_qt.cpp \
+ chromium_gpu_helper.cpp \
javascript_dialog_manager_qt.cpp \
render_widget_host_view_qt.cpp \
resource_context_qt.cpp \
@@ -58,6 +59,7 @@ HEADERS = \
delegated_frame_node.h \
dev_tools_http_handler_delegate_qt.h \
download_manager_delegate_qt.h \
+ chromium_gpu_helper.h \
javascript_dialog_manager_qt.h \
render_widget_host_view_qt.h \
render_widget_host_view_qt_delegate.h \
diff --git a/lib/quick/render_widget_host_view_qt_delegate_quick.cpp b/lib/quick/render_widget_host_view_qt_delegate_quick.cpp
index 8989759f6..2d90e772b 100644
--- a/lib/quick/render_widget_host_view_qt_delegate_quick.cpp
+++ b/lib/quick/render_widget_host_view_qt_delegate_quick.cpp
@@ -58,10 +58,29 @@ void RenderWidgetHostViewQtDelegateQuick::update(const QRect&)
QQuickItem::update();
}
+void RenderWidgetHostViewQtDelegateQuick::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ QQuickItem::itemChange(change, value);
+ if (change == QQuickItem::ItemSceneChange && value.window)
+ connect(value.window, SIGNAL(frameSwapped()), SLOT(onFrameSwapped()));
+}
+
QSGNode *RenderWidgetHostViewQtDelegateQuick::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
return m_client->updatePaintNode(oldNode, QQuickItem::window());
}
+
+void RenderWidgetHostViewQtDelegateQuick::releaseResources()
+{
+ // This is the only callback we get before being removed from a window while we still know it.
+ QQuickItem::window()->disconnect(this);
+}
+
+void RenderWidgetHostViewQtDelegateQuick::onFrameSwapped()
+{
+ m_client->sendDelegatedFrameAck();
+}
+
#endif // QT_VERSION
diff --git a/lib/quick/render_widget_host_view_qt_delegate_quick.h b/lib/quick/render_widget_host_view_qt_delegate_quick.h
index 80f5baca8..612b89ed1 100644
--- a/lib/quick/render_widget_host_view_qt_delegate_quick.h
+++ b/lib/quick/render_widget_host_view_qt_delegate_quick.h
@@ -216,7 +216,12 @@ public:
virtual WId nativeWindowIdForCompositor() const;
virtual void update(const QRect& rect = QRect());
+ virtual void itemChange(ItemChange, const ItemChangeData &);
virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ virtual void releaseResources();
+
+public Q_SLOTS:
+ void onFrameSwapped();
};
#endif // QT_VERSION
diff --git a/lib/render_widget_host_view_qt.cpp b/lib/render_widget_host_view_qt.cpp
index b6a1d2905..16adb5ec2 100644
--- a/lib/render_widget_host_view_qt.cpp
+++ b/lib/render_widget_host_view_qt.cpp
@@ -168,16 +168,18 @@ void RenderWidgetHostViewQt::setAdapterClient(WebContentsAdapterClient *adapterC
InitAsChild(0);
}
-void RenderWidgetHostViewQt::releaseAndAckDelegatedFrame()
+void RenderWidgetHostViewQt::sendDelegatedFrameAck()
{
+ if (!m_pendingAckFrameData)
+ return;
+
cc::CompositorFrameAck ack;
- // FIXME: This releases all resources of the frame for now.
- ack.resources = m_pendingFrameData->resource_list;
+ ack.resources = m_pendingAckFrameData->resource_list;
content::RenderWidgetHostImpl::SendSwapCompositorFrameAck(
m_host->GetRoutingID(), m_pendingOutputSurfaceId,
m_host->GetProcess()->GetID(), ack);
- m_pendingFrameData.reset();
+ m_pendingAckFrameData.reset();
}
BackingStoreQt* RenderWidgetHostViewQt::GetBackingStore()
@@ -592,10 +594,9 @@ bool RenderWidgetHostViewQt::HasAcceleratedSurface(const gfx::Size&)
void RenderWidgetHostViewQt::OnSwapCompositorFrame(uint32 output_surface_id, scoped_ptr<cc::CompositorFrame> frame)
{
Q_ASSERT(frame->delegated_frame_data);
- SwapDelegatedFrame(output_surface_id,
- frame->delegated_frame_data.Pass(),
- frame->metadata.device_scale_factor,
- frame->metadata.latency_info);
+ m_pendingOutputSurfaceId = output_surface_id;
+ m_pendingUpdateFrameData = frame->delegated_frame_data.Pass();
+ m_delegate->update();
}
void RenderWidgetHostViewQt::GetScreenInfo(WebKit::WebScreenInfo* results)
@@ -650,19 +651,19 @@ void RenderWidgetHostViewQt::paint(QPainter *painter, const QRectF& boundingRect
QSGNode *RenderWidgetHostViewQt::updatePaintNode(QSGNode *oldNode, QQuickWindow *window)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
- if (!m_pendingFrameData) {
- delete oldNode;
- return 0;
- }
+ if (!m_pendingUpdateFrameData)
+ return oldNode;
+
DelegatedFrameNode *frameNode = static_cast<DelegatedFrameNode *>(oldNode);
if (!frameNode)
frameNode = new DelegatedFrameNode(window);
- frameNode->commit(m_pendingFrameData.get());
-
- content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
- base::Bind(&RenderWidgetHostViewQt::releaseAndAckDelegatedFrame, this->AsWeakPtr()));
+ // Switch the frame from one pointer to the other to keep track of its state
+ // to be able to update and then ack each frame only once.
+ Q_ASSERT(!m_pendingAckFrameData);
+ m_pendingAckFrameData.reset(m_pendingUpdateFrameData.release());
+ frameNode->commit(m_pendingAckFrameData.get());
return frameNode;
#else
return 0;
@@ -763,16 +764,6 @@ void RenderWidgetHostViewQt::Paint(const gfx::Rect& damage_rect)
m_delegate->update(r);
}
-void RenderWidgetHostViewQt::SwapDelegatedFrame(uint32 output_surface_id, scoped_ptr<cc::DelegatedFrameData> frame_data, float frame_device_scale_factor, const ui::LatencyInfo& latency_info) {
- gfx::Size frame_size_in_dip;
- if (!frame_data->render_pass_list.empty())
- frame_size_in_dip = gfx::ToFlooredSize(gfx::ScaleSize(frame_data->render_pass_list.back()->output_rect.size(), 1.f/frame_device_scale_factor));
-
- m_pendingOutputSurfaceId = output_surface_id;
- m_pendingFrameData = frame_data.Pass();
- m_delegate->update();
-}
-
void RenderWidgetHostViewQt::ProcessGestures(ui::GestureRecognizer::Gestures *gestures)
{
if (!gestures || gestures->empty())
diff --git a/lib/render_widget_host_view_qt.h b/lib/render_widget_host_view_qt.h
index 24c845556..be32cfcf5 100644
--- a/lib/render_widget_host_view_qt.h
+++ b/lib/render_widget_host_view_qt.h
@@ -99,7 +99,6 @@ public:
void setDelegate(RenderWidgetHostViewQtDelegate *delegate);
void setAdapterClient(WebContentsAdapterClient *adapterClient);
- void releaseAndAckDelegatedFrame();
BackingStoreQt* GetBackingStore();
virtual content::BackingStore *AllocBackingStore(const gfx::Size &size);
@@ -168,6 +167,7 @@ public:
// Overridden from RenderWidgetHostViewQtDelegateClient.
virtual void paint(QPainter *, const QRectF& boundingRect) Q_DECL_OVERRIDE;
virtual QSGNode *updatePaintNode(QSGNode *, QQuickWindow *) Q_DECL_OVERRIDE;
+ virtual void sendDelegatedFrameAck() Q_DECL_OVERRIDE;
virtual void fetchBackingStore() Q_DECL_OVERRIDE;
virtual void notifyResize() Q_DECL_OVERRIDE;
virtual bool forwardEvent(QEvent *) Q_DECL_OVERRIDE;
@@ -196,7 +196,6 @@ public:
private:
void Paint(const gfx::Rect& damage_rect);
- void SwapDelegatedFrame(uint32 output_surface_id, scoped_ptr<cc::DelegatedFrameData> frame_data, float frame_device_scale_factor, const ui::LatencyInfo& latency_info);
void ProcessGestures(ui::GestureRecognizer::Gestures *gestures);
int GetMappedTouch(int qtTouchId);
void RemoveExpiredMappings(QTouchEvent *ev);
@@ -211,7 +210,8 @@ private:
BackingStoreQt *m_backingStore;
uint32 m_pendingOutputSurfaceId;
- scoped_ptr<cc::DelegatedFrameData> m_pendingFrameData;
+ scoped_ptr<cc::DelegatedFrameData> m_pendingUpdateFrameData;
+ scoped_ptr<cc::DelegatedFrameData> m_pendingAckFrameData;
WebContentsAdapterClient *m_adapterClient;
MultipleMouseClickHelper m_clickHelper;
diff --git a/lib/render_widget_host_view_qt_delegate.h b/lib/render_widget_host_view_qt_delegate.h
index 2f1401b6d..c541e36e7 100644
--- a/lib/render_widget_host_view_qt_delegate.h
+++ b/lib/render_widget_host_view_qt_delegate.h
@@ -64,6 +64,7 @@ public:
virtual ~RenderWidgetHostViewQtDelegateClient() { }
virtual void paint(QPainter *, const QRectF& boundingRect) = 0;
virtual QSGNode *updatePaintNode(QSGNode *, QQuickWindow *) = 0;
+ virtual void sendDelegatedFrameAck() = 0;
virtual void fetchBackingStore() = 0;
virtual void notifyResize() = 0;
virtual bool forwardEvent(QEvent *) = 0;
diff --git a/lib/type_conversion.h b/lib/type_conversion.h
index 6a9a12428..b2e29685d 100644
--- a/lib/type_conversion.h
+++ b/lib/type_conversion.h
@@ -81,6 +81,11 @@ inline QRect toQt(const gfx::Rect &rect)
return QRect(rect.x(), rect.y(), rect.width(), rect.height());
}
+inline QRectF toQt(const gfx::RectF &rect)
+{
+ return QRectF(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
inline QSize toQt(const gfx::Size &size)
{
return QSize(size.width(), size.height());
diff --git a/lib/web_engine_context.cpp b/lib/web_engine_context.cpp
index 62adf43ef..4a6a6c5cb 100644
--- a/lib/web_engine_context.cpp
+++ b/lib/web_engine_context.cpp
@@ -55,13 +55,15 @@
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/main_function_params.h"
+#include "ui/gl/gl_switches.h"
#include "webkit/common/user_agent/user_agent_util.h"
#include "content_browser_client_qt.h"
#include "content_client_qt.h"
#include "type_conversion.h"
-#include <QCoreApplication>
+#include <QGuiApplication>
#include <QStringList>
+#include <qpa/qplatformnativeinterface.h>
namespace {
@@ -134,6 +136,10 @@ WebEngineContext::WebEngineContext()
parsedCommandLine->AppendSwitch(switches::kNoSandbox);
parsedCommandLine->AppendSwitch(switches::kDisablePlugins);
+ // Tell Chromium to use EGL instead of GLX if the Qt xcb plugin also does.
+ if (qApp->platformName() == QStringLiteral("xcb") && qApp->platformNativeInterface()->nativeResourceForWindow(QByteArrayLiteral("egldisplay"), 0))
+ parsedCommandLine->AppendSwitchASCII(switches::kUseGL, gfx::kGLImplementationEGLName);
+
m_contentRunner->Initialize(0, 0, m_mainDelegate.get());
m_browserRunner->Initialize(content::MainFunctionParams(*CommandLine::ForCurrentProcess()));
diff --git a/patches/0001-Add-accessors-for-the-Qt-delegated-renderer-integrat.patch b/patches/0001-Add-accessors-for-the-Qt-delegated-renderer-integrat.patch
new file mode 100644
index 000000000..fe63dfc0f
--- /dev/null
+++ b/patches/0001-Add-accessors-for-the-Qt-delegated-renderer-integrat.patch
@@ -0,0 +1,84 @@
+From e40d3482d46ff88755aa2bd76048de698ae03915 Mon Sep 17 00:00:00 2001
+From: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
+Date: Fri, 20 Sep 2013 15:00:47 +0200
+Subject: [PATCH] Add accessors for the Qt delegated renderer integration.
+
+This is needed to fetch the MessageLoop, the MailboxManager and the
+SyncPointManager of the GPU in-process host.
+---
+ content/common/gpu/gpu_channel_manager.h | 2 ++
+ content/gpu/gpu_child_thread.cc | 6 ++++++
+ content/gpu/gpu_child_thread.h | 6 ++++++
+ 3 files changed, 14 insertions(+)
+
+diff --git a/content/common/gpu/gpu_channel_manager.h b/content/common/gpu/gpu_channel_manager.h
+index f01a1c5..e41a548 100644
+--- a/content/common/gpu/gpu_channel_manager.h
++++ b/content/common/gpu/gpu_channel_manager.h
+@@ -89,6 +89,8 @@ class GpuChannelManager : public IPC::Listener,
+
+ gpu::gles2::ProgramCache* program_cache();
+
++ gpu::gles2::MailboxManager* mailbox_manager() { return mailbox_manager_.get(); }
++
+ GpuMemoryManager* gpu_memory_manager() { return &gpu_memory_manager_; }
+
+ GpuChannel* LookupChannel(int32 client_id);
+diff --git a/content/gpu/gpu_child_thread.cc b/content/gpu/gpu_child_thread.cc
+index 170b364..a84a9e0 100644
+--- a/content/gpu/gpu_child_thread.cc
++++ b/content/gpu/gpu_child_thread.cc
+@@ -40,6 +40,8 @@ bool GpuProcessLogMessageHandler(int severity,
+
+ } // namespace
+
++GpuChildThread* GpuChildThread::instance_ = 0;
++
+ GpuChildThread::GpuChildThread(GpuWatchdogThread* watchdog_thread,
+ bool dead_on_arrival,
+ const gpu::GPUInfo& gpu_info,
+@@ -53,6 +55,8 @@ GpuChildThread::GpuChildThread(GpuWatchdogThread* watchdog_thread,
+ target_services_ = NULL;
+ #endif
+ g_thread_safe_sender.Get() = thread_safe_sender();
++
++ instance_ = this;
+ }
+
+ GpuChildThread::GpuChildThread(const std::string& channel_id)
+@@ -71,6 +75,8 @@ GpuChildThread::GpuChildThread(const std::string& channel_id)
+ VLOG(1) << "gfx::GLSurface::InitializeOneOff()";
+ }
+ g_thread_safe_sender.Get() = thread_safe_sender();
++
++ instance_ = this;
+ }
+
+ GpuChildThread::~GpuChildThread() {
+diff --git a/content/gpu/gpu_child_thread.h b/content/gpu/gpu_child_thread.h
+index ff0c925..82bb32a 100644
+--- a/content/gpu/gpu_child_thread.h
++++ b/content/gpu/gpu_child_thread.h
+@@ -56,6 +56,10 @@ class GpuChildThread : public ChildThread {
+ virtual bool Send(IPC::Message* msg) OVERRIDE;
+ virtual bool OnControlMessageReceived(const IPC::Message& msg) OVERRIDE;
+
++ GpuChannelManager* ChannelManager() const { return gpu_channel_manager_.get(); }
++
++ static GpuChildThread* instance() { return instance_; }
++
+ private:
+ // Message handlers.
+ void OnInitialize();
+@@ -94,6 +98,8 @@ class GpuChildThread : public ChildThread {
+ // Whether the GPU thread is running in the browser process.
+ bool in_browser_process_;
+
++ static GpuChildThread* instance_;
++
+ DISALLOW_COPY_AND_ASSIGN(GpuChildThread);
+ };
+
+--
+1.8.4.2
+
diff --git a/patches/0001-Add-seams-to-setup-GL-contexts-sharing-with-QtQuick.patch b/patches/0001-Add-seams-to-setup-GL-contexts-sharing-with-QtQuick.patch
new file mode 100644
index 000000000..55cf5a5d5
--- /dev/null
+++ b/patches/0001-Add-seams-to-setup-GL-contexts-sharing-with-QtQuick.patch
@@ -0,0 +1,109 @@
+From 559c011aabd6fc9f064d2913e4fae06db2c8495b Mon Sep 17 00:00:00 2001
+From: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
+Date: Thu, 24 Oct 2013 18:26:59 +0200
+Subject: [PATCH] Add seams to setup GL contexts sharing with QtQuick.
+
+This will allow us to know right before the first GL context is
+instantiated by Chromium so that we can install those contexts to
+be shared with QtQuick GL contexts as well.
+---
+ content/common/gpu/gpu_channel_manager.cc | 8 +++++++-
+ content/public/browser/content_browser_client.h | 5 +++++
+ ui/gl/gl_share_group.cc | 3 +++
+ ui/gl/gl_share_group.h | 7 +++++--
+ 4 files changed, 20 insertions(+), 3 deletions(-)
+
+diff --git a/content/common/gpu/gpu_channel_manager.cc b/content/common/gpu/gpu_channel_manager.cc
+index 8b466bd..fe3f7b3 100644
+--- a/content/common/gpu/gpu_channel_manager.cc
++++ b/content/common/gpu/gpu_channel_manager.cc
+@@ -11,6 +11,7 @@
+ #include "content/common/gpu/gpu_memory_manager.h"
+ #include "content/common/gpu/gpu_messages.h"
+ #include "content/common/gpu/sync_point_manager.h"
++#include "content/public/browser/content_browser_client.h"
+ #include "gpu/command_buffer/service/feature_info.h"
+ #include "gpu/command_buffer/service/gpu_switches.h"
+ #include "gpu/command_buffer/service/mailbox_manager.h"
+@@ -124,7 +125,12 @@ void GpuChannelManager::OnEstablishChannel(int client_id, bool share_context) {
+ DCHECK(!mailbox_manager_.get());
+ mailbox_manager_ = new gpu::gles2::MailboxManager;
+ }
+- share_group = share_group_.get();
++ // Qt: Ask the browser client at the top to manage the context sharing.
++ // This can only work with --in-process-gpu or --single-process.
++ if (GetContentClient()->browser() && GetContentClient()->browser()->GetInProcessGpuShareGroup())
++ share_group = GetContentClient()->browser()->GetInProcessGpuShareGroup();
++ else
++ share_group = share_group_.get();
+ mailbox_manager = mailbox_manager_.get();
+ }
+
+diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
+index 1f5e836..2168769 100644
+--- a/content/public/browser/content_browser_client.h
++++ b/content/public/browser/content_browser_client.h
+@@ -48,6 +48,7 @@ class CryptoModuleBlockingPasswordDelegate;
+ }
+
+ namespace gfx {
++class GLShareGroup;
+ class ImageSkia;
+ }
+
+@@ -563,6 +564,10 @@ class CONTENT_EXPORT ContentBrowserClient {
+ // Return NULL to use the default one for the platform to be created.
+ virtual LocationProvider* OverrideSystemLocationProvider();
+
++ // Allow an embedder to provide a share group reimplementation to connect renderer
++ // GL contexts with the root compositor.
++ virtual gfx::GLShareGroup* GetInProcessGpuShareGroup() { return 0; }
++
+ #if defined(OS_POSIX) && !defined(OS_MACOSX)
+ // Populates |mappings| with all files that need to be mapped before launching
+ // a child process.
+diff --git a/ui/gl/gl_share_group.cc b/ui/gl/gl_share_group.cc
+index 8e8958b..347873d 100644
+--- a/ui/gl/gl_share_group.cc
++++ b/ui/gl/gl_share_group.cc
+@@ -18,6 +18,9 @@ GLShareGroup::GLShareGroup()
+ }
+
+ void GLShareGroup::AddContext(GLContext* context) {
++ if (contexts_.empty())
++ AboutToAddFirstContext();
++
+ contexts_.insert(context);
+ }
+
+diff --git a/ui/gl/gl_share_group.h b/ui/gl/gl_share_group.h
+index 1deed63..f1b0369 100644
+--- a/ui/gl/gl_share_group.h
++++ b/ui/gl/gl_share_group.h
+@@ -31,7 +31,7 @@ class GL_EXPORT GLShareGroup : public base::RefCounted<GLShareGroup> {
+
+ // Returns a pointer to any initialized context in the share group
+ // or NULL if there are no initialized contexts in the share group.
+- GLContext* GetContext();
++ virtual GLContext* GetContext();
+
+ // Sets and returns the unique shared GL context. Used for context
+ // virtualization.
+@@ -45,10 +45,13 @@ class GL_EXPORT GLShareGroup : public base::RefCounted<GLShareGroup> {
+ int GetRendererID();
+ #endif
+
++ protected:
++ virtual ~GLShareGroup();
++ virtual void AboutToAddFirstContext() { }
++
+ private:
+ friend class base::RefCounted<GLShareGroup>;
+
+- ~GLShareGroup();
+
+ // References to GLContext are by raw pointer to avoid a reference count
+ // cycle.
+--
+1.8.4.2
+
diff --git a/patches/patch-chromium.sh b/patches/patch-chromium.sh
index 2c3834b08..38cc4c126 100755
--- a/patches/patch-chromium.sh
+++ b/patches/patch-chromium.sh
@@ -69,6 +69,8 @@ git am $PATCH_DIR/0001-Solve-conflicts-when-including-both-QtOpenGL-headers.patc
git am $PATCH_DIR/0001-Do-not-forward-declare-UIResourceRequest-Identity-an.patch
git am $PATCH_DIR/0001-Fix-the-build-with-a-GL-ES2-configured-Qt.patch
git am $PATCH_DIR/0001-Hide-the-definition-of-MessagePumpGtk-GetDefaultXDis.patch
+git am $PATCH_DIR/0001-Add-accessors-for-the-Qt-delegated-renderer-integrat.patch
+git am $PATCH_DIR/0001-Add-seams-to-setup-GL-contexts-sharing-with-QtQuick.patch
cd $CHROMIUM_SRC_DIR/third_party/WebKit
echo "Entering $PWD"