summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-10-15 13:59:17 +0200
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-11-25 16:27:18 +0100
commit3a7674a1b6901826a70b54eab5c9312ecd0d6052 (patch)
tree599e000eed26b3708d54dc26dc5255e6e8f849a7 /src/core
parent3f08d8a506241bf9b9cdfb2be37f8a3868869adf (diff)
Avoid relying on QOpenGL classes to handle RenderPasses
Use QSGLayer and get rid of RenderPassTexture so that we can render intermediate layers with the QtQuick 2D Renderer. This reintroduces the private dependency on QtQuick since the QSGLayer factory methods aren't available publically, and also that we need to use QSGImageNode instead of QSGSimpleTextureNode to use them. Since we can't subclass QSGLayer to hold a reference to SG objects directly in the nodes that use them, store them all in the wrapping DelegatedFrameNode in a SGObjects structs. This works assuming that the DelegatedFrameNode will always be at the root of our nodes, layers and textures; if the scene graph destroys the DelegatedFrameNode all child nodes will be destroyed with it. Change-Id: Iedeceb8f98eb54fd8228a677c366d6df9a270e11 Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
Diffstat (limited to 'src/core')
-rw-r--r--src/core/core_gyp_generator.pro2
-rw-r--r--src/core/core_module.pro2
-rw-r--r--src/core/delegated_frame_node.cpp158
-rw-r--r--src/core/delegated_frame_node.h14
-rw-r--r--src/core/render_widget_host_view_qt.cpp2
-rw-r--r--src/core/render_widget_host_view_qt_delegate.h4
6 files changed, 69 insertions, 113 deletions
diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro
index a011effec..4514475ec 100644
--- a/src/core/core_gyp_generator.pro
+++ b/src/core/core_gyp_generator.pro
@@ -11,7 +11,7 @@ TEMPLATE = lib
# gyp/ninja will take care of the compilation, qmake/make will finish with linking and install.
TARGET = QtWebEngineCore
QT += qml quick
-QT_PRIVATE += gui-private
+QT_PRIVATE += quick-private gui-private core-private
# Defining keywords such as 'signal' clashes with the chromium code base.
DEFINES += QT_NO_KEYWORDS \
diff --git a/src/core/core_module.pro b/src/core/core_module.pro
index c755d673d..04ce090e1 100644
--- a/src/core/core_module.pro
+++ b/src/core/core_module.pro
@@ -5,7 +5,7 @@ CMAKE_MODULE_TESTS = "-"
qtHaveModule(positioning):QT += positioning
QT += qml quick
-QT_PRIVATE += gui-private
+QT_PRIVATE += quick-private gui-private core-private
# Look for linking information produced by gyp for our target according to core_generated.gyp
!include($$OUT_PWD/$$getConfigDir()/$${TARGET}_linking.pri) {
diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp
index d1e01cac0..1df7cae3e 100644
--- a/src/core/delegated_frame_node.cpp
+++ b/src/core/delegated_frame_node.cpp
@@ -64,49 +64,17 @@
#include "cc/quads/tile_draw_quad.h"
#include "cc/quads/yuv_video_draw_quad.h"
#include <QOpenGLContext>
-#include <QOpenGLFramebufferObject>
#include <QOpenGLFunctions>
-#include <QSGAbstractRenderer>
-#include <QSGEngine>
#include <QSGSimpleRectNode>
#include <QSGSimpleTextureNode>
#include <QSGTexture>
+#include <private/qsgadaptationlayer_p.h>
#if !defined(QT_NO_EGL)
#include <EGL/egl.h>
#include <EGL/eglext.h>
#endif
-class RenderPassTexture : public QSGTexture, protected QOpenGLFunctions
-{
-public:
- RenderPassTexture(const cc::RenderPass::Id &id);
-
- const cc::RenderPass::Id &id() const { return m_id; }
- void bind();
-
- int textureId() const { return m_fbo ? m_fbo->texture() : 0; }
- QSize textureSize() const { return m_rect.size(); }
- bool hasAlphaChannel() const { return m_format != GL_RGB; }
- bool hasMipmaps() const { return false; }
-
- void setRect(const QRect &rect) { m_rect = rect; }
- void setFormat(GLenum format) { m_format = format; }
- QSGNode *rootNode() { return m_rootNode.data(); }
-
- void grab();
-
-private:
- cc::RenderPass::Id m_id;
- QRect m_rect;
- GLenum m_format;
-
- QScopedPointer<QSGEngine> m_sgEngine;
- QScopedPointer<QSGRootNode> m_rootNode;
- QScopedPointer<QSGAbstractRenderer> m_renderer;
- QScopedPointer<QOpenGLFramebufferObject> m_fbo;
-};
-
class MailboxTexture : public QSGTexture, protected QOpenGLFunctions {
public:
MailboxTexture(const cc::TransferableResource &resource);
@@ -145,12 +113,13 @@ private:
QSGGeometry m_geometry;
};
-static inline QSharedPointer<RenderPassTexture> findRenderPassTexture(const cc::RenderPass::Id &id, const QList<QSharedPointer<RenderPassTexture> > &list)
+static inline QSharedPointer<QSGLayer> findRenderPassLayer(const cc::RenderPass::Id &id, const QList<QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> > > &list)
{
- Q_FOREACH (const QSharedPointer<RenderPassTexture> &texture, list)
- if (texture->id() == id)
- return texture;
- return QSharedPointer<RenderPassTexture>();
+ typedef QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> > Pair;
+ Q_FOREACH (const Pair &pair, list)
+ if (pair.first == id)
+ return pair.second;
+ return QSharedPointer<QSGLayer>();
}
static inline QSharedPointer<MailboxTexture> &findMailboxTexture(unsigned resourceId
@@ -295,50 +264,6 @@ static void deleteChromiumSync(gfx::TransferableFence *sync)
Q_ASSERT(!*sync);
}
-RenderPassTexture::RenderPassTexture(const cc::RenderPass::Id &id)
- : QSGTexture()
- , m_id(id)
- , m_format(GL_RGBA)
- , m_sgEngine(new QSGEngine)
- , m_rootNode(new QSGRootNode)
-{
- initializeOpenGLFunctions();
-}
-
-void RenderPassTexture::bind()
-{
- glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0);
- updateBindOptions();
-}
-
-void RenderPassTexture::grab()
-{
- if (!m_renderer) {
- m_sgEngine->initialize(QOpenGLContext::currentContext());
- m_renderer.reset(m_sgEngine->createRenderer());
- m_renderer->setRootNode(m_rootNode.data());
- }
-
- if (!m_fbo || m_fbo->size() != m_rect.size() || m_fbo->format().internalTextureFormat() != m_format)
- {
- QOpenGLFramebufferObjectFormat format;
- format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
- format.setInternalTextureFormat(m_format);
-
- m_fbo.reset(new QOpenGLFramebufferObject(m_rect.size(), format));
- glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
- updateBindOptions(true);
- }
-
- m_renderer->setDeviceRect(m_rect.size());
- m_renderer->setViewportRect(m_rect.size());
- QRectF mirrored(m_rect.left(), m_rect.bottom(), m_rect.width(), -m_rect.height());
- m_renderer->setProjectionMatrixToRect(mirrored);
- m_renderer->setClearColor(Qt::transparent);
-
- m_renderer->renderScene(m_fbo->handle());
-}
-
MailboxTexture::MailboxTexture(const cc::TransferableResource &resource)
: m_resource(resource)
, m_textureId(0)
@@ -471,11 +396,16 @@ void DelegatedFrameNode::preprocess()
}
// Then render any intermediate RenderPass in order.
- Q_FOREACH (const QSharedPointer<RenderPassTexture> &renderPass, m_renderPassTextures)
- renderPass->grab();
+ typedef QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> > Pair;
+ Q_FOREACH (const Pair &pair, m_sgObjects.renderPassLayers) {
+ // The layer is non-live, request a one-time update here.
+ pair.second->scheduleUpdate();
+ // Proceed with the actual update.
+ pair.second->updateTexture();
+ }
}
-void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, cc::ReturnedResourceArray *resourcesToRelease)
+void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, cc::ReturnedResourceArray *resourcesToRelease, RenderWidgetHostViewQtDelegate *apiDelegate)
{
m_chromiumCompositorData = chromiumCompositorData;
cc::DelegatedFrameData* frameData = m_chromiumCompositorData->frameData.get();
@@ -489,11 +419,12 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData,
matrix.scale(1 / m_chromiumCompositorData->frameDevicePixelRatio, 1 / m_chromiumCompositorData->frameDevicePixelRatio);
setMatrix(matrix);
- // Keep the old texture lists around to find the ones we can re-use.
- QList<QSharedPointer<RenderPassTexture> > oldRenderPassTextures;
- m_renderPassTextures.swap(oldRenderPassTextures);
+ // Keep the old objects in scope to hold a ref on layers, resources and textures
+ // that we can re-use. Destroy the remaining objects before returning.
+ SGObjects previousSGObjects;
+ qSwap(m_sgObjects, previousSGObjects);
QHash<unsigned, QSharedPointer<MailboxTexture> > mailboxTextureCandidates;
- m_chromiumCompositorData->mailboxTextures.swap(mailboxTextureCandidates);
+ qSwap(m_chromiumCompositorData->mailboxTextures, mailboxTextureCandidates);
// A frame's resource_list only contains the new resources to be added to the scene. Quads can
// still reference resources that were added in previous frames. Add them to the list of
@@ -509,6 +440,13 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData,
frameData->resource_list.clear();
+ // There is currently no way to know which and how quads changed since the last frame.
+ // We have to reconstruct the node chain with their geometries on every update.
+ // Intermediate render pass node chains are going to be destroyed when previousSGObjects
+ // goes out of scope together with any QSGLayer that could reference them.
+ while (QSGNode *oldChain = firstChild())
+ delete oldChain;
+
// 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.
// The list is already ordered with intermediate RenderPasses placed before their
@@ -522,21 +460,24 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData,
QSGNode *renderPassParent = 0;
if (pass != rootRenderPass) {
- QSharedPointer<RenderPassTexture> rpTexture = findRenderPassTexture(pass->id, oldRenderPassTextures);
- if (!rpTexture)
- rpTexture = QSharedPointer<RenderPassTexture>(new RenderPassTexture(pass->id));
- m_renderPassTextures.append(rpTexture);
- rpTexture->setRect(toQt(pass->output_rect));
- rpTexture->setFormat(pass->has_transparent_background ? GL_RGBA : GL_RGB);
- renderPassParent = rpTexture->rootNode();
+ QSharedPointer<QSGLayer> rpLayer = findRenderPassLayer(pass->id, previousSGObjects.renderPassLayers);
+ if (!rpLayer) {
+ rpLayer = QSharedPointer<QSGLayer>(apiDelegate->createLayer());
+ // Avoid any premature texture update since we need to wait
+ // for the GPU thread to produce the dependent resources first.
+ rpLayer->setLive(false);
+ }
+ QSharedPointer<QSGRootNode> rootNode(new QSGRootNode);
+ rpLayer->setRect(toQt(pass->output_rect));
+ rpLayer->setSize(toQt(pass->output_rect.size()));
+ rpLayer->setFormat(pass->has_transparent_background ? GL_RGBA : GL_RGB);
+ rpLayer->setItem(rootNode.data());
+ m_sgObjects.renderPassLayers.append(QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> >(pass->id, rpLayer));
+ m_sgObjects.renderPassRootNodes.append(rootNode);
+ renderPassParent = rootNode.data();
} else
renderPassParent = this;
- // There is currently no way to know which and how quads changed since the last frame.
- // We have to reconstruct the node chain with their geometries on every update.
- while (QSGNode *oldChain = renderPassParent->firstChild())
- delete oldChain;
-
QSGNode *renderPassChain = buildRenderPassChain(renderPassParent);
const cc::SharedQuadState *currentLayerState = 0;
QSGNode *currentLayerChain = 0;
@@ -562,15 +503,18 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData,
break;
} case cc::DrawQuad::RENDER_PASS: {
const cc::RenderPassDrawQuad *renderPassQuad = cc::RenderPassDrawQuad::MaterialCast(quad);
- QSGTexture *texture = findRenderPassTexture(renderPassQuad->render_pass_id, m_renderPassTextures).data();
+ QSGTexture *layer = findRenderPassLayer(renderPassQuad->render_pass_id, m_sgObjects.renderPassLayers).data();
// cc::GLRenderer::DrawRenderPassQuad silently ignores missing render passes.
- if (!texture)
+ if (!layer)
continue;
- QSGSimpleTextureNode *textureNode = new QSGSimpleTextureNode;
- textureNode->setRect(toQt(quad->rect));
- textureNode->setTexture(texture);
- currentLayerChain->appendChildNode(textureNode);
+ // Only QSGImageNode currently supports QSGLayer textures.
+ QSGImageNode *imageNode = apiDelegate->createImageNode();
+ imageNode->setTargetRect(toQt(quad->rect));
+ imageNode->setInnerTargetRect(toQt(quad->rect));
+ imageNode->setTexture(layer);
+ imageNode->update();
+ currentLayerChain->appendChildNode(imageNode);
break;
} case cc::DrawQuad::TEXTURE_CONTENT: {
const cc::TextureDrawQuad *tquad = cc::TextureDrawQuad::MaterialCast(quad);
diff --git a/src/core/delegated_frame_node.h b/src/core/delegated_frame_node.h
index 0a042ba32..41e89f75f 100644
--- a/src/core/delegated_frame_node.h
+++ b/src/core/delegated_frame_node.h
@@ -38,6 +38,7 @@
#define DELEGATED_FRAME_NODE_H
#include "base/memory/scoped_ptr.h"
+#include "cc/quads/render_pass.h"
#include "cc/resources/transferable_resource.h"
#include <QMutex>
#include <QSGNode>
@@ -46,13 +47,17 @@
#include <QWaitCondition>
#include "chromium_gpu_helper.h"
+#include "render_widget_host_view_qt_delegate.h"
+
+QT_BEGIN_NAMESPACE
+class QSGLayer;
+QT_END_NAMESPACE
namespace cc {
class DelegatedFrameData;
}
class MailboxTexture;
-class RenderPassTexture;
// Separating this data allows another DelegatedFrameNode to reconstruct the QSGNode tree from the mailbox textures
// and render pass information.
@@ -69,11 +74,14 @@ public:
DelegatedFrameNode();
~DelegatedFrameNode();
void preprocess();
- void commit(ChromiumCompositorData *chromiumCompositorData, cc::ReturnedResourceArray *resourcesToRelease);
+ void commit(ChromiumCompositorData *chromiumCompositorData, cc::ReturnedResourceArray *resourcesToRelease, RenderWidgetHostViewQtDelegate *apiDelegate);
private:
QExplicitlySharedDataPointer<ChromiumCompositorData> m_chromiumCompositorData;
- QList<QSharedPointer<RenderPassTexture> > m_renderPassTextures;
+ struct SGObjects {
+ QList<QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> > > renderPassLayers;
+ QList<QSharedPointer<QSGRootNode> > renderPassRootNodes;
+ } m_sgObjects;
int m_numPendingSyncPoints;
QMap<uint32, gfx::TransferableFence> m_mailboxGLFences;
QWaitCondition m_mailboxesFetchedWaitCond;
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp
index 3e2ef71cc..99c954595 100644
--- a/src/core/render_widget_host_view_qt.cpp
+++ b/src/core/render_widget_host_view_qt.cpp
@@ -655,7 +655,7 @@ QSGNode *RenderWidgetHostViewQt::updatePaintNode(QSGNode *oldNode)
if (!frameNode)
frameNode = new DelegatedFrameNode;
- frameNode->commit(m_chromiumCompositorData.data(), &m_resourcesToRelease);
+ frameNode->commit(m_chromiumCompositorData.data(), &m_resourcesToRelease, m_delegate.get());
// This is possibly called from the Qt render thread, post the ack back to the UI
// to tell the child compositors to release resources and trigger a new frame.
diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h
index 3f6d9caac..7b9a3e16c 100644
--- a/src/core/render_widget_host_view_qt_delegate.h
+++ b/src/core/render_widget_host_view_qt_delegate.h
@@ -46,6 +46,8 @@ QT_BEGIN_NAMESPACE
class QCursor;
class QEvent;
class QPainter;
+class QSGImageNode;
+class QSGLayer;
class QSGNode;
class QVariant;
class QWindow;
@@ -78,6 +80,8 @@ public:
virtual void hide() = 0;
virtual bool isVisible() const = 0;
virtual QWindow* window() const = 0;
+ virtual QSGLayer *createLayer() = 0;
+ virtual QSGImageNode *createImageNode() = 0;
virtual void update() = 0;
virtual void updateCursor(const QCursor &) = 0;
virtual void resize(int width, int height) = 0;