diff --git a/3rdparty b/3rdparty index 63f1510d708ce6e90354c63655fa21bd4906e52e..9427c1a0222ebd67efef1a2c7990a0fa5c9aac84 160000 --- a/3rdparty +++ b/3rdparty @@ -1 +1 @@ -Subproject commit 63f1510d708ce6e90354c63655fa21bd4906e52e +Subproject commit 9427c1a0222ebd67efef1a2c7990a0fa5c9aac84 diff --git a/examples/quick/quicknanobrowser/main.cpp b/examples/quick/quicknanobrowser/main.cpp index 982c1eb7a481a1fe56285cf91c757577baece167..6c2f91de6dd9397800213f7e725429cc692bbc96 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 c32540a71e03761f00ad6e6eeb57c53cc25454f2..2132b031aebc5a6cf329917828389093e019b7cc 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 0000000000000000000000000000000000000000..3d393c25dd46d35632b3b74054aa101e12a8392d --- /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 0000000000000000000000000000000000000000..e0ac8e2a3c04db7c001f80fa1f43c1f577ae464a --- /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 4ff15d3b1906cbf1e96f040e7741d6b1b3868c0e..97d5c8e4e480aa8f7bb1ff0fd87c7742be06d6be 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 f8c42e5691de90ae7a5202fd5b9d8081d819f83d..b97eaa5e1ad824b2a802892810ae661844c3a36a 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 dea9605beb90d0bc80985147cffbcfe739807c81..0e3f34fffe03a276674c363a71f3c86d1b2b961a 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 9eb9b5c48a0e571b68c5be402cabbc3c631e0170..0b6657e9828f630c9bb74ef5d122c77325d743bb 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 c25920b1609f7086277f1645d2366a5c238cd954..32af217b6057bbe761c8fbd8f11602d46f7fb288 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 8989759f635b26f09e57079d1359b416aeaa1447..2d90e772bdd340d1968a5543c1e1e37f5daee1cd 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 80f5baca88991b8b029af892fe93578b9d740a5d..612b89ed1c29ea470482107f5cd121e2ef83dea0 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 b6a1d290567603586a043962b0600bd7e94d89a1..16adb5ec2e167a35b215f68d6d2c02b1e101d51a 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 24c84555683b17d0201a19f6904526bcd0ea73a0..be32cfcf587a0891611981beb40a956958830b5a 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 2f1401b6daab73cbb9baca2cb4bc77ae4ac803e5..c541e36e78602ba3d95b0601c19936bdffdfd99c 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 6a9a124282f96c124e71531ee55308a7a8d3d40e..b2e29685df9f9e26b14da0d98a96ad6900e11155 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 62adf43efebf5c164111f39d208192193d837f78..4a6a6c5cb21cab7845cdb06e2a214cd08645851f 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 0000000000000000000000000000000000000000..fe63dfc0f0dbe1b7797e3243c167c351dd46f835 --- /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 0000000000000000000000000000000000000000..55cf5a5d522a9916fab38c039f2a1bcacb65d897 --- /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 2c3834b081cd5ac480f887fc011798374123920c..38cc4c126186a1e9727e73149f7624d4b03230d8 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"