diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2013-10-31 13:59:44 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-11-06 17:34:12 +0100 |
commit | fbf3e79512358a3eb1e6589b10ac01917b2e94d0 (patch) | |
tree | 37de83061cf9f7c7d7f4f42edf26dde2f05b3ab8 | |
parent | a99fdc02797ece15253ff863102d3257945abfab (diff) |
Move DelegatedFrameNode and the SG logic to its own file.
This avoids polluting render_widget_host_view_qt_delegate.cpp
Change-Id: I06af66f01f842e105bbded75b01f9c8346fd5df9
Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
-rw-r--r-- | lib/delegated_frame_node.cpp | 366 | ||||
-rw-r--r-- | lib/delegated_frame_node.h | 76 | ||||
-rw-r--r-- | lib/lib.pro | 2 | ||||
-rw-r--r-- | lib/render_widget_host_view_qt_delegate.cpp | 318 | ||||
-rw-r--r-- | lib/render_widget_host_view_qt_delegate.h | 9 |
5 files changed, 447 insertions, 324 deletions
diff --git a/lib/delegated_frame_node.cpp b/lib/delegated_frame_node.cpp new file mode 100644 index 000000000..dea9605be --- /dev/null +++ b/lib/delegated_frame_node.cpp @@ -0,0 +1,366 @@ +/**************************************************************************** +** +** 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 "delegated_frame_node.h" + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)) + +// On Mac we need to reset this define in order to prevent definition +// of "check" macros etc. The "check" macro collides with a member function name in QtQuick. +// See AssertMacros.h in the Mac SDK. +#include <QtGlobal> // We need this for the Q_OS_MAC define. +#if defined(Q_OS_MAC) +#undef __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES +#define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0 +#endif + +#include "type_conversion.h" + +#include "cc/output/delegated_frame_data.h" +#include "cc/quads/draw_quad.h" +#include "cc/quads/render_pass_draw_quad.h" +#include "cc/quads/texture_draw_quad.h" +#include "cc/quads/tile_draw_quad.h" +#include <QOpenGLFramebufferObject> +#include <QSGSimpleTextureNode> +#include <QSGTexture> +#include <QtQuick/private/qquickclipnode_p.h> +#include <QtQuick/private/qquickwindow_p.h> +#include <QtQuick/private/qsgcontext_p.h> +#include <QtQuick/private/qsgrenderer_p.h> + +class RenderPassTexture : public QSGTexture +{ +public: + RenderPassTexture(const cc::RenderPass::Id &id, QSGRenderContext *context); + + 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; } + void setDevicePixelRatio(qreal ratio) { m_device_pixel_ratio = ratio; } + QSGNode *rootNode() { return m_rootNode.data(); } + + void grab(); + +private: + cc::RenderPass::Id m_id; + QRect m_rect; + qreal m_device_pixel_ratio; + GLenum m_format; + + QScopedPointer<QSGRootNode> m_rootNode; + QScopedPointer<QSGRenderer> m_renderer; + QScopedPointer<QOpenGLFramebufferObject> m_fbo; + + QSGRenderContext *m_context; +}; + +class RawTextureNode : public QSGSimpleTextureNode { +public: + RawTextureNode(GLuint textureId, const QSize &textureSize, bool hasAlpha, QQuickWindow *window); + +private: + QScopedPointer<QSGTexture> m_texture; +}; + + +static inline QSharedPointer<RenderPassTexture> findRenderPassTexture(const cc::RenderPass::Id &id, const QList<QSharedPointer<RenderPassTexture> > &list) +{ + Q_FOREACH (const QSharedPointer<RenderPassTexture> &texture, list) + if (texture->id() == id) + return texture; + return QSharedPointer<RenderPassTexture>(); +} + +static QSGNode *buildRenderPassChain(QSGNode *chainParent, const cc::RenderPass *renderPass) +{ + // Chromium already ordered the quads from back to front for us, however the + // Qt scene graph layers individual geometries in their own z-range and uses + // the depth buffer to visually stack nodes according to their item tree order. + // This finds the z-span of all layers so that we can z-compress them to fit + // them between 0.0 and 1.0 on the z axis. + double minZ = 0; + double maxZ = 1; + double src2[8]; + double dst4[16]; + // topleft.x, topleft.y, topRight.y and bottomLeft.x + src2[0] = src2[1] = src2[3] = src2[4] = 0; + + // Go through each layer in this pass and find out their transformed rect. + cc::SharedQuadStateList::const_iterator it = renderPass->shared_quad_state_list.begin(); + cc::SharedQuadStateList::const_iterator sharedStateEnd = renderPass->shared_quad_state_list.end(); + for (; it != sharedStateEnd; ++it) { + gfx::Size &layerSize = (*it)->content_bounds; + // topRight.x + src2[2] = layerSize.width(); + // bottomLeft.y + src2[5] = layerSize.height(); + // bottomRight + src2[6] = layerSize.width(); + src2[7] = layerSize.height(); + (*it)->content_to_target_transform.matrix().map2(src2, 4, dst4); + // Check the mapped corner's z value and track the boundaries. + minZ = std::min(std::min(std::min(std::min(minZ, dst4[2]), dst4[6]), dst4[10]), dst4[14]); + maxZ = std::max(std::max(std::max(std::max(maxZ, dst4[2]), dst4[6]), dst4[10]), dst4[14]); + } + + QSGTransformNode *zCompressNode = new QSGTransformNode; + QMatrix4x4 zCompressMatrix; + zCompressMatrix.scale(1, 1, 1 / (maxZ - minZ)); + zCompressMatrix.translate(0, 0, -minZ); + zCompressNode->setMatrix(zCompressMatrix); + chainParent->appendChildNode(zCompressNode); + return zCompressNode; +} + +static QSGNode *buildLayerChain(QSGNode *chainParent, const cc::SharedQuadState *layerState) +{ + QSGNode *layerChain = chainParent; + if (layerState->is_clipped) { + QQuickDefaultClipNode *clipNode = new QQuickDefaultClipNode(toQt(layerState->clip_rect)); + clipNode->update(); + layerChain->appendChildNode(clipNode); + layerChain = clipNode; + } + if (!layerState->content_to_target_transform.IsIdentity()) { + QSGTransformNode *transformNode = new QSGTransformNode; + transformNode->setMatrix(toQt(layerState->content_to_target_transform.matrix())); + layerChain->appendChildNode(transformNode); + layerChain = transformNode; + } + if (layerState->opacity < 1.0) { + QSGOpacityNode *opacityNode = new QSGOpacityNode; + opacityNode->setOpacity(layerState->opacity); + layerChain->appendChildNode(opacityNode); + layerChain = opacityNode; + } + return layerChain; +} + + +RenderPassTexture::RenderPassTexture(const cc::RenderPass::Id &id, QSGRenderContext *context) + : QSGTexture() + , m_id(id) + , m_device_pixel_ratio(1) + , m_format(GL_RGBA) + , m_rootNode(new QSGRootNode) + , m_context(context) +{ +} + +void RenderPassTexture::bind() +{ + glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0); + updateBindOptions(); +} + +void RenderPassTexture::grab() +{ + if (!m_rootNode->firstChild()) { + m_renderer.reset(); + m_fbo.reset(); + return; + } + if (!m_renderer) { + m_renderer.reset(m_context->createRenderer()); + m_renderer->setRootNode(m_rootNode.data()); + } + m_renderer->setDevicePixelRatio(m_device_pixel_ratio); + + 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_rootNode->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip and opacity update. + m_renderer->nodeChanged(m_rootNode.data(), QSGNode::DirtyForceUpdate); // Force render list update. + + 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_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))) +{ + setTexture(m_texture.data()); +} + +DelegatedFrameNode::DelegatedFrameNode(QQuickWindow *window) + : m_window(window) + , m_testTexturesSize(sizeof(m_testTextures) / sizeof(GLuint)) +{ + 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(); +} + +void DelegatedFrameNode::commit(cc::DelegatedFrameData *frameData) +{ + // Keep the old list around to find the ones we can re-use. + QList<QSharedPointer<RenderPassTexture> > oldRenderPassTextures; + m_renderPassTextures.swap(oldRenderPassTextures); + + // 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 + // parent, with the last one in the list being the root RenderPass, the one + // that we displayed to the user. + // All RenderPasses except the last one are rendered to an FBO. + cc::RenderPass *rootRenderPass = frameData->render_pass_list.back(); + + for (unsigned i = 0; i < frameData->render_pass_list.size(); ++i) { + cc::RenderPass *pass = frameData->render_pass_list.at(i); + + QSGNode *renderPassParent = 0; + if (pass != rootRenderPass) { + QSharedPointer<RenderPassTexture> rpTexture = findRenderPassTexture(pass->id, oldRenderPassTextures); + if (!rpTexture) { + QSGRenderContext *sgrc = QQuickWindowPrivate::get(m_window)->context; + rpTexture = QSharedPointer<RenderPassTexture>(new RenderPassTexture(pass->id, sgrc)); + } + m_renderPassTextures.append(rpTexture); + rpTexture->setDevicePixelRatio(m_window->devicePixelRatio()); + rpTexture->setRect(toQt(pass->output_rect)); + rpTexture->setFormat(pass->has_transparent_background ? GL_RGBA : GL_RGB); + renderPassParent = rpTexture->rootNode(); + } 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, pass); + const cc::SharedQuadState *currentLayerState = 0; + QSGNode *currentLayerChain = 0; + + cc::QuadList::ConstBackToFrontIterator it = pass->quad_list.BackToFrontBegin(); + cc::QuadList::ConstBackToFrontIterator end = pass->quad_list.BackToFrontEnd(); + for (; it != end; ++it) { + cc::DrawQuad *quad = *it; + + if (currentLayerState != quad->shared_quad_state) { + currentLayerState = quad->shared_quad_state; + 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; + textureNode->setTexture(texture); + } else { + qWarning("Unknown RenderPass layer: Id %d", renderPassQuad->render_pass_id.layer_id); + textureNode = new RawTextureNode(0, QSize(1, 1), false, m_window); + } + 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); + 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); + break; + } default: + qWarning("Unimplemented quad material: %d", quad->material); + textureNode = new RawTextureNode(0, QSize(1, 1), false, m_window); + } + + textureNode->setRect(toQt(quad->rect)); + textureNode->setFiltering(QSGTexture::Linear); + currentLayerChain->appendChildNode(textureNode); + } + } +} + +#endif // QT_VERSION diff --git a/lib/delegated_frame_node.h b/lib/delegated_frame_node.h new file mode 100644 index 000000000..9eb9b5c48 --- /dev/null +++ b/lib/delegated_frame_node.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 DELEGATED_FRAME_NODE_H +#define DELEGATED_FRAME_NODE_H + +#include <QSGNode> +#include <QSharedPointer> + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)) + +QT_BEGIN_NAMESPACE +class QQuickWindow; +QT_END_NAMESPACE + +namespace cc { +class DelegatedFrameData; +} + +class RenderPassTexture; + +class DelegatedFrameNode : public QSGNode { +public: + DelegatedFrameNode(QQuickWindow *window); + ~DelegatedFrameNode(); + void preprocess(); + void commit(cc::DelegatedFrameData *frameData); + +private: + QQuickWindow *m_window; + QList<QSharedPointer<RenderPassTexture> > m_renderPassTextures; + const size_t m_testTexturesSize; + GLuint m_testTextures[Qt::transparent - Qt::red]; +}; + +#endif // QT_VERSION + +#endif // DELEGATED_FRAME_NODE_H diff --git a/lib/lib.pro b/lib/lib.pro index a0f4116fe..d6a546597 100644 --- a/lib/lib.pro +++ b/lib/lib.pro @@ -37,6 +37,7 @@ SOURCES = \ backing_store_qt.cpp \ content_client_qt.cpp \ content_browser_client_qt.cpp \ + delegated_frame_node.cpp \ dev_tools_http_handler_delegate_qt.cpp \ download_manager_delegate_qt.cpp \ javascript_dialog_manager_qt.cpp \ @@ -55,6 +56,7 @@ HEADERS = \ browser_context_qt.h \ content_client_qt.h \ content_browser_client_qt.h \ + delegated_frame_node.h \ dev_tools_http_handler_delegate_qt.h \ download_manager_delegate_qt.h \ javascript_dialog_manager_qt.h \ diff --git a/lib/render_widget_host_view_qt_delegate.cpp b/lib/render_widget_host_view_qt_delegate.cpp index 8916193cf..25a9e69b0 100644 --- a/lib/render_widget_host_view_qt_delegate.cpp +++ b/lib/render_widget_host_view_qt_delegate.cpp @@ -42,6 +42,7 @@ #include "render_widget_host_view_qt_delegate.h" #include "backing_store_qt.h" +#include "delegated_frame_node.h" #include "render_widget_host_view_qt.h" #include "type_conversion.h" @@ -49,240 +50,6 @@ #include <QVariant> -#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)) -#include "cc/quads/draw_quad.h" -#include "cc/quads/render_pass_draw_quad.h" -#include "cc/quads/texture_draw_quad.h" -#include "cc/quads/tile_draw_quad.h" -#include <QSGNode> -#include <QSGSimpleTextureNode> -#include <QSGTexture> -#include <QtQuick/private/qquickclipnode_p.h> -#include <QtQuick/private/qquickwindow_p.h> -#include <QtQuick/private/qsgcontext_p.h> -#include <QtQuick/private/qsgrenderer_p.h> - -class RenderPassTexture : public QSGTexture -{ -public: - RenderPassTexture(const cc::RenderPass::Id &id, QSGRenderContext *context); - - 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; } - void setDevicePixelRatio(qreal ratio) { m_device_pixel_ratio = ratio; } - QSGNode *rootNode() { return m_rootNode.data(); } - - void grab(); - -private: - cc::RenderPass::Id m_id; - QRect m_rect; - qreal m_device_pixel_ratio; - GLenum m_format; - - QScopedPointer<QSGRootNode> m_rootNode; - QScopedPointer<QSGRenderer> m_renderer; - QScopedPointer<QOpenGLFramebufferObject> m_fbo; - - QSGRenderContext *m_context; -}; - -RenderPassTexture::RenderPassTexture(const cc::RenderPass::Id &id, QSGRenderContext *context) - : QSGTexture() - , m_id(id) - , m_device_pixel_ratio(1) - , m_format(GL_RGBA) - , m_rootNode(new QSGRootNode) - , m_context(context) -{ -} - -void RenderPassTexture::bind() -{ - glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0); - updateBindOptions(); -} - -void RenderPassTexture::grab() -{ - if (!m_rootNode->firstChild()) { - m_renderer.reset(); - m_fbo.reset(); - return; - } - if (!m_renderer) { - m_renderer.reset(m_context->createRenderer()); - m_renderer->setRootNode(m_rootNode.data()); - } - m_renderer->setDevicePixelRatio(m_device_pixel_ratio); - - 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_rootNode->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip and opacity update. - m_renderer->nodeChanged(m_rootNode.data(), QSGNode::DirtyForceUpdate); // Force render list update. - - 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_context->renderNextFrame(m_renderer.data(), m_fbo->handle()); -} - -class RawTextureNode : public QSGSimpleTextureNode { -public: - RawTextureNode(GLuint textureId, const QSize &textureSize, bool hasAlpha, QQuickWindow *window); - -private: - QScopedPointer<QSGTexture> m_texture; -}; - -RawTextureNode::RawTextureNode(GLuint textureId, const QSize &textureSize, bool hasAlpha, QQuickWindow *window) - : m_texture(window->createTextureFromId(textureId, textureSize, QQuickWindow::CreateTextureOption(hasAlpha ? QQuickWindow::TextureHasAlphaChannel : 0))) -{ - setTexture(m_texture.data()); -} - -class DelegatedFrameNode : public QSGNode { -public: - DelegatedFrameNode(); - ~DelegatedFrameNode(); - void preprocess(); - QList<QSharedPointer<RenderPassTexture> > renderPassTextures; - - const size_t testTexturesSize; - GLuint testTextures[Qt::transparent - Qt::red]; -}; - -DelegatedFrameNode::DelegatedFrameNode() - : testTexturesSize(sizeof(testTextures) / sizeof(GLuint)) -{ - setFlag(UsePreprocess); - - // Generate plain color textures to be used until we can use the real textures from the ResourceProvider. - glGenTextures(testTexturesSize, testTextures); - for (unsigned i = 0; i < 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, testTextures[i]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.constBits() ); - } -} - -DelegatedFrameNode::~DelegatedFrameNode() -{ - glDeleteTextures(testTexturesSize, testTextures); -} - -void DelegatedFrameNode::preprocess() -{ - // Render any intermediate RenderPass in order. - Q_FOREACH (const QSharedPointer<RenderPassTexture> &texture, renderPassTextures) - texture->grab(); -} - -static inline QSharedPointer<RenderPassTexture> findRenderPassTexture(const cc::RenderPass::Id &id, const QList<QSharedPointer<RenderPassTexture> > &list) -{ - Q_FOREACH (const QSharedPointer<RenderPassTexture> &texture, list) - if (texture->id() == id) - return texture; - return QSharedPointer<RenderPassTexture>(); -} - -static QSGNode *buildRenderPassChain(QSGNode *chainParent, const cc::RenderPass *renderPass) -{ - // Chromium already ordered the quads from back to front for us, however the - // Qt scene graph layers individual geometries in their own z-range and uses - // the depth buffer to visually stack nodes according to their item tree order. - // This finds the z-span of all layers so that we can z-compress them to fit - // them between 0.0 and 1.0 on the z axis. - double minZ = 0; - double maxZ = 1; - double src2[8]; - double dst4[16]; - // topleft.x, topleft.y, topRight.y and bottomLeft.x - src2[0] = src2[1] = src2[3] = src2[4] = 0; - - // Go through each layer in this pass and find out their transformed rect. - cc::SharedQuadStateList::const_iterator it = renderPass->shared_quad_state_list.begin(); - cc::SharedQuadStateList::const_iterator sharedStateEnd = renderPass->shared_quad_state_list.end(); - for (; it != sharedStateEnd; ++it) { - gfx::Size &layerSize = (*it)->content_bounds; - // topRight.x - src2[2] = layerSize.width(); - // bottomLeft.y - src2[5] = layerSize.height(); - // bottomRight - src2[6] = layerSize.width(); - src2[7] = layerSize.height(); - (*it)->content_to_target_transform.matrix().map2(src2, 4, dst4); - // Check the mapped corner's z value and track the boundaries. - minZ = std::min(std::min(std::min(std::min(minZ, dst4[2]), dst4[6]), dst4[10]), dst4[14]); - maxZ = std::max(std::max(std::max(std::max(maxZ, dst4[2]), dst4[6]), dst4[10]), dst4[14]); - } - - QSGTransformNode *zCompressNode = new QSGTransformNode; - QMatrix4x4 zCompressMatrix; - zCompressMatrix.scale(1, 1, 1 / (maxZ - minZ)); - zCompressMatrix.translate(0, 0, -minZ); - zCompressNode->setMatrix(zCompressMatrix); - chainParent->appendChildNode(zCompressNode); - return zCompressNode; -} - -static QSGNode *buildLayerChain(QSGNode *chainParent, const cc::SharedQuadState *layerState) -{ - QSGNode *layerChain = chainParent; - if (layerState->is_clipped) { - QQuickDefaultClipNode *clipNode = new QQuickDefaultClipNode(toQt(layerState->clip_rect)); - clipNode->update(); - layerChain->appendChildNode(clipNode); - layerChain = clipNode; - } - if (!layerState->content_to_target_transform.IsIdentity()) { - QSGTransformNode *transformNode = new QSGTransformNode; - transformNode->setMatrix(toQt(layerState->content_to_target_transform.matrix())); - layerChain->appendChildNode(transformNode); - layerChain = transformNode; - } - if (layerState->opacity < 1.0) { - QSGOpacityNode *opacityNode = new QSGOpacityNode; - opacityNode->setOpacity(layerState->opacity); - layerChain->appendChildNode(opacityNode); - layerChain = opacityNode; - } - return layerChain; -} -#endif // QT_VERSION - RenderWidgetHostViewQtDelegate::RenderWidgetHostViewQtDelegate() : m_view(0), m_backingStore(0) { @@ -308,88 +75,9 @@ QSGNode *RenderWidgetHostViewQtDelegate::updatePaintNode(QSGNode *oldNode, QQuic } DelegatedFrameNode *frameNode = static_cast<DelegatedFrameNode *>(oldNode); if (!frameNode) - frameNode = new DelegatedFrameNode; - - // Keep the old list around to find the ones we can re-use. - QList<QSharedPointer<RenderPassTexture> > oldRenderPassTextures; - frameNode->renderPassTextures.swap(oldRenderPassTextures); + frameNode = new DelegatedFrameNode(window); - // 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 - // parent, with the last one in the list being the root RenderPass, the one - // that we displayed to the user. - // All RenderPasses except the last one are rendered to an FBO. - cc::RenderPass *rootRenderPass = frameData->render_pass_list.back(); - - for (unsigned i = 0; i < frameData->render_pass_list.size(); ++i) { - cc::RenderPass *pass = frameData->render_pass_list.at(i); - - QSGNode *renderPassParent = 0; - if (pass != rootRenderPass) { - QSharedPointer<RenderPassTexture> rpTexture = findRenderPassTexture(pass->id, oldRenderPassTextures); - if (!rpTexture) { - QSGRenderContext *sgrc = QQuickWindowPrivate::get(window)->context; - rpTexture = QSharedPointer<RenderPassTexture>(new RenderPassTexture(pass->id, sgrc)); - } - frameNode->renderPassTextures.append(rpTexture); - rpTexture->setDevicePixelRatio(window->devicePixelRatio()); - rpTexture->setRect(toQt(pass->output_rect)); - rpTexture->setFormat(pass->has_transparent_background ? GL_RGBA : GL_RGB); - renderPassParent = rpTexture->rootNode(); - } else - renderPassParent = frameNode; - - // 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, pass); - const cc::SharedQuadState *currentLayerState = 0; - QSGNode *currentLayerChain = 0; - - cc::QuadList::ConstBackToFrontIterator it = pass->quad_list.BackToFrontBegin(); - cc::QuadList::ConstBackToFrontIterator end = pass->quad_list.BackToFrontEnd(); - for (; it != end; ++it) { - cc::DrawQuad *quad = *it; - - if (currentLayerState != quad->shared_quad_state) { - currentLayerState = quad->shared_quad_state; - 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, frameNode->renderPassTextures).data(); - if (texture) { - textureNode = new QSGSimpleTextureNode; - textureNode->setTexture(texture); - } else { - qWarning("Unknown RenderPass layer: Id %d", renderPassQuad->render_pass_id.layer_id); - textureNode = new RawTextureNode(0, QSize(1, 1), false, window); - } - break; - } case cc::DrawQuad::TEXTURE_CONTENT: { - uint32 resourceId = cc::TextureDrawQuad::MaterialCast(quad)->resource_id; - textureNode = new RawTextureNode(frameNode->testTextures[resourceId % frameNode->testTexturesSize], QSize(1, 1), false, window); - break; - } case cc::DrawQuad::TILED_CONTENT: { - uint32 resourceId = cc::TileDrawQuad::MaterialCast(quad)->resource_id; - textureNode = new RawTextureNode(frameNode->testTextures[resourceId % frameNode->testTexturesSize], QSize(1, 1), false, window); - break; - } default: - qWarning("Unimplemented quad material: %d", quad->material); - textureNode = new RawTextureNode(0, QSize(1, 1), false, window); - } - - textureNode->setRect(toQt(quad->rect)); - textureNode->setFiltering(QSGTexture::Linear); - currentLayerChain->appendChildNode(textureNode); - } - } + frameNode->commit(frameData); content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, base::Bind(&RenderWidgetHostViewQt::releaseAndAckDelegatedFrame, m_view->AsWeakPtr())); diff --git a/lib/render_widget_host_view_qt_delegate.h b/lib/render_widget_host_view_qt_delegate.h index 36a6ceb9d..3486e3f8d 100644 --- a/lib/render_widget_host_view_qt_delegate.h +++ b/lib/render_widget_host_view_qt_delegate.h @@ -42,15 +42,6 @@ #ifndef RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_H #define RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_H -// On Mac we need to reset this define in order to prevent definition -// of "check" macros etc. The "check" macro collides with a member function name in QtQuick. -// See AssertMacros.h in the Mac SDK. -#include <QtGlobal> // We need this for the Q_OS_MAC define. -#if defined(Q_OS_MAC) -#undef __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES -#define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0 -#endif - #include "qtwebengineglobal.h" #include <QRect> |