Expose the scene graph publically through a QSGEngine class
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>
Tue, 1 Jul 2014 17:19:56 +0000 (19:19 +0200)
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>
Fri, 1 Aug 2014 11:49:46 +0000 (13:49 +0200)
This change wraps QSGRenderContext and QSGContext in a new QSGEngine
class, and expose a public interface of QSGRenderer through a
QSGAbstractRenderer to make it usable on a standalone window or FBO.

Change-Id: I2d41187472424f5ea64650a006bcd61f2711f6b9
Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
20 files changed:
examples/quick/scenegraph/scenegraph.pro
examples/quick/scenegraph/sgengine/face-smile.png [new file with mode: 0644]
examples/quick/scenegraph/sgengine/main.cpp [new file with mode: 0644]
examples/quick/scenegraph/sgengine/sgengine.pro [new file with mode: 0644]
examples/quick/scenegraph/sgengine/sgengine.qrc [new file with mode: 0644]
examples/quick/scenegraph/sgengine/window.cpp [new file with mode: 0644]
examples/quick/scenegraph/sgengine/window.h [new file with mode: 0644]
src/quick/items/qquickwindow.cpp
src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp [new file with mode: 0644]
src/quick/scenegraph/coreapi/qsgabstractrenderer.h [new file with mode: 0644]
src/quick/scenegraph/coreapi/qsgabstractrenderer_p.h [new file with mode: 0644]
src/quick/scenegraph/coreapi/qsgnode.h
src/quick/scenegraph/coreapi/qsgrenderer.cpp
src/quick/scenegraph/coreapi/qsgrenderer_p.h
src/quick/scenegraph/qsgcontext.cpp
src/quick/scenegraph/qsgcontext_p.h
src/quick/scenegraph/scenegraph.pri
src/quick/scenegraph/util/qsgengine.cpp [new file with mode: 0644]
src/quick/scenegraph/util/qsgengine.h [new file with mode: 0644]
src/quick/scenegraph/util/qsgengine_p.h [new file with mode: 0644]

index 4354954..85ae259 100644 (file)
@@ -2,6 +2,7 @@ TEMPLATE = subdirs
 SUBDIRS += \
         customgeometry \
         openglunderqml \
+        sgengine \
         simplematerial \
         textureinsgnode \
         textureinthread \
diff --git a/examples/quick/scenegraph/sgengine/face-smile.png b/examples/quick/scenegraph/sgengine/face-smile.png
new file mode 100644 (file)
index 0000000..3d66d72
Binary files /dev/null and b/examples/quick/scenegraph/sgengine/face-smile.png differ
diff --git a/examples/quick/scenegraph/sgengine/main.cpp b/examples/quick/scenegraph/sgengine/main.cpp
new file mode 100644 (file)
index 0000000..9a94507
--- /dev/null
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+**     of its contributors may be used to endorse or promote products derived
+**     from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+#include <QGuiApplication>
+
+int main(int argc, char *argv[])
+{
+    QGuiApplication app(argc, argv);
+
+    Window window;
+    window.show();
+
+    return app.exec();
+}
diff --git a/examples/quick/scenegraph/sgengine/sgengine.pro b/examples/quick/scenegraph/sgengine/sgengine.pro
new file mode 100644 (file)
index 0000000..c6507a4
--- /dev/null
@@ -0,0 +1,11 @@
+QT += quick
+
+HEADERS += window.h
+SOURCES += window.cpp main.cpp
+RESOURCES += \
+    sgengine.qrc \
+    ../../shared/shared.qrc
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/sgengine
+INSTALLS += target
diff --git a/examples/quick/scenegraph/sgengine/sgengine.qrc b/examples/quick/scenegraph/sgengine/sgengine.qrc
new file mode 100644 (file)
index 0000000..5d55bcf
--- /dev/null
@@ -0,0 +1,5 @@
+<RCC>
+    <qresource prefix="/scenegraph/sgengine">
+        <file>face-smile.png</file>
+    </qresource>
+</RCC>
diff --git a/examples/quick/scenegraph/sgengine/window.cpp b/examples/quick/scenegraph/sgengine/window.cpp
new file mode 100644 (file)
index 0000000..9af4029
--- /dev/null
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+**     of its contributors may be used to endorse or promote products derived
+**     from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+
+#include <QOpenGLContext>
+#include <QSGAbstractRenderer>
+#include <QSGEngine>
+#include <QSGSimpleTextureNode>
+#include <QSGTransformNode>
+#include <QScreen>
+#include <QVariantAnimation>
+
+class Item {
+public:
+    Item(QSGNode *parentNode, QSGTexture *texture, const QPointF &fromPos, const QPointF &toPos) {
+        textureNode = new QSGSimpleTextureNode;
+        textureNode->setRect(QRect(QPoint(), texture->textureSize()));
+        textureNode->setTexture(texture);
+
+        transformNode = new QSGTransformNode;
+        transformNode->setFlag(QSGNode::OwnedByParent, false);
+        transformNode->appendChildNode(textureNode);
+        parentNode->appendChildNode(transformNode);
+
+        int duration = qrand() / float(RAND_MAX) * 400 + 800;
+        rotAnimation.setStartValue(qrand() / float(RAND_MAX) * 720 - 180);
+        rotAnimation.setEndValue(qrand() / float(RAND_MAX) * 720 - 180);
+        rotAnimation.setDuration(duration);
+        rotAnimation.start();
+
+        posAnimation.setStartValue(fromPos);
+        posAnimation.setEndValue(toPos);
+        posAnimation.setDuration(duration);
+        posAnimation.start();
+    }
+
+    ~Item() {
+        delete transformNode;
+    }
+
+    bool isDone() const { return posAnimation.state() != QAbstractAnimation::Running; }
+
+    void sync() {
+        QPointF currentPos = posAnimation.currentValue().toPointF();
+        QPointF center = textureNode->rect().center();
+        QMatrix4x4 m;
+        m.translate(currentPos.x(), currentPos.y());
+        m.translate(center.x(), center.y());
+        m.rotate(rotAnimation.currentValue().toFloat(), 0, 0, 1);
+        m.translate(-center.x(), -center.y());
+        transformNode->setMatrix(m);
+    }
+
+private:
+    QSGTransformNode *transformNode;
+    QSGSimpleTextureNode *textureNode;
+    QVariantAnimation posAnimation;
+    QVariantAnimation rotAnimation;
+};
+
+Window::Window()
+    : m_initialized(false)
+    , m_context(new QOpenGLContext)
+    , m_sgEngine(new QSGEngine)
+    , m_sgRootNode(new QSGRootNode)
+{
+    setSurfaceType(QWindow::OpenGLSurface);
+    QRect g(0, 0, 640, 480);
+    g.moveCenter(screen()->geometry().center());
+    setGeometry(g);
+    setTitle(QStringLiteral("Click me!"));
+
+    QSurfaceFormat format;
+    format.setDepthBufferSize(16);
+    setFormat(format);
+    m_context->setFormat(format);
+    m_context->create();
+
+    m_animationDriver.install();
+    connect(&m_animationDriver, &QAnimationDriver::started, this, &Window::update);
+}
+
+Window::~Window()
+{
+}
+
+void Window::timerEvent(QTimerEvent *e)
+{
+    if (e->timerId() == m_updateTimer.timerId()) {
+        m_updateTimer.stop();
+
+        if (!m_context->makeCurrent(this))
+            return;
+
+        if (!m_initialized)
+            initialize();
+
+        sync();
+        render();
+
+        if (m_animationDriver.isRunning()) {
+            m_animationDriver.advance();
+            update();
+        }
+    } else
+        QWindow::timerEvent(e);
+}
+
+void Window::exposeEvent(QExposeEvent *)
+{
+    if (isExposed())
+        update();
+    else
+        invalidate();
+}
+
+void Window::mousePressEvent(QMouseEvent *)
+{
+    addItems();
+}
+
+void Window::keyPressEvent(QKeyEvent *)
+{
+    addItems();
+}
+
+void Window::addItems()
+{
+    if (!m_initialized)
+        return;
+
+    QSGTexture *textures[] = { m_smileTexture.data(), m_qtTexture.data() };
+    for (int i = 0; i < 50; ++i) {
+        QSGTexture *tex = textures[i%2];
+        QPointF fromPos(-tex->textureSize().width(), qrand() / float(RAND_MAX) * (height() - tex->textureSize().height()));
+        QPointF toPos(width(), qrand() / float(RAND_MAX) * height() * 1.5 - height() * 0.25);
+        m_items.append(QSharedPointer<Item>(new Item(m_sgRootNode.data(), tex, fromPos, toPos)));
+    }
+    update();
+}
+
+void Window::update()
+{
+    if (!m_updateTimer.isActive())
+        m_updateTimer.start(0, this);
+}
+
+void Window::sync()
+{
+    QList<QSharedPointer<Item> > validItems;
+    foreach (QSharedPointer<Item> item, m_items) {
+        if (!item->isDone()) {
+            validItems.append(item);
+            item->sync();
+        }
+    }
+    m_items.swap(validItems);
+}
+
+void Window::render()
+{
+    m_sgRenderer->setDeviceRect(size());
+    m_sgRenderer->setViewportRect(size());
+    m_sgRenderer->setProjectionMatrixToRect(QRectF(QPointF(), size()));
+    m_sgRenderer->renderScene();
+
+    m_context->swapBuffers(this);
+}
+
+void Window::initialize()
+{
+    m_sgEngine->initialize(m_context.data());
+    m_sgRenderer.reset(m_sgEngine->createRenderer());
+    m_sgRenderer->setRootNode(m_sgRootNode.data());
+    m_sgRenderer->setClearColor(QColor(32, 32, 32));
+
+    // With QSGEngine::createTextureFromId
+    GLuint glTexture;
+    glGenTextures(1, &glTexture);
+    glBindTexture(GL_TEXTURE_2D, glTexture);
+    QImage smile = QImage(":/scenegraph/sgengine/face-smile.png").scaled(48, 48, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+    smile = smile.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
+    Q_ASSERT(!smile.isNull());
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, smile.width(), smile.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, smile.constBits());
+    m_smileTexture.reset(m_sgEngine->createTextureFromId(glTexture, smile.size(), QFlag(QSGEngine::TextureOwnsGLTexture | QSGEngine::TextureHasAlphaChannel)));
+
+    // With QSGEngine::createTextureFromImage
+    QImage qtLogo = QImage(":/shared/images/qt-logo.png").scaled(48, 48, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+    Q_ASSERT(!qtLogo.isNull());
+    m_qtTexture.reset(m_sgEngine->createTextureFromImage(qtLogo));
+    m_initialized = true;
+}
+
+void Window::invalidate()
+{
+    m_updateTimer.stop();
+    m_items.clear();
+    m_smileTexture.reset();
+    m_qtTexture.reset();
+    m_sgRenderer.reset();
+    m_sgEngine->invalidate();
+    m_initialized = false;
+}
diff --git a/examples/quick/scenegraph/sgengine/window.h b/examples/quick/scenegraph/sgengine/window.h
new file mode 100644 (file)
index 0000000..2b239ea
--- /dev/null
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+**     of its contributors may be used to endorse or promote products derived
+**     from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QWindow>
+
+#include <QAnimationDriver>
+#include <QBasicTimer>
+#include <QSharedPointer>
+
+class Item;
+QT_FORWARD_DECLARE_CLASS(QSGAbstractRenderer)
+QT_FORWARD_DECLARE_CLASS(QSGEngine)
+QT_FORWARD_DECLARE_CLASS(QSGRootNode)
+QT_FORWARD_DECLARE_CLASS(QSGTexture)
+
+class Window : public QWindow
+{
+    Q_OBJECT
+public:
+    Window();
+    ~Window();
+
+    void addItems();
+    void update();
+
+private:
+    void timerEvent(QTimerEvent *);
+    void exposeEvent(QExposeEvent *);
+    void mousePressEvent(QMouseEvent *);
+    void keyPressEvent(QKeyEvent *);
+
+    void sync();
+    void render();
+    void initialize();
+    void invalidate();
+
+    bool m_initialized;
+    QScopedPointer<QOpenGLContext> m_context;
+    QScopedPointer<QSGEngine> m_sgEngine;
+    QScopedPointer<QSGRootNode> m_sgRootNode;
+    QScopedPointer<QSGAbstractRenderer> m_sgRenderer;
+    QScopedPointer<QSGTexture> m_smileTexture;
+    QScopedPointer<QSGTexture> m_qtTexture;
+    QList<QSharedPointer<Item> > m_items;
+
+    QBasicTimer m_updateTimer;
+    QAnimationDriver m_animationDriver;
+};
index 12be33d..f1d2f63 100644 (file)
@@ -350,9 +350,9 @@ void QQuickWindowPrivate::syncSceneGraph()
 
     // Copy the current state of clearing from window into renderer.
     renderer->setClearColor(clearColor);
-    QSGRenderer::ClearMode mode = QSGRenderer::ClearStencilBuffer | QSGRenderer::ClearDepthBuffer;
+    QSGAbstractRenderer::ClearMode mode = QSGAbstractRenderer::ClearStencilBuffer | QSGAbstractRenderer::ClearDepthBuffer;
     if (clearBeforeRendering)
-        mode |= QSGRenderer::ClearColorBuffer;
+        mode |= QSGAbstractRenderer::ClearColorBuffer;
     renderer->setClearMode(mode);
 
     renderer->setCustomRenderMode(customRenderMode);
diff --git a/src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp b/src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp
new file mode 100644 (file)
index 0000000..9409822
--- /dev/null
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick 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 "qsgabstractrenderer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+    \class QSGAbstractRenderer
+    \brief QSGAbstractRenderer gives access to the scene graph nodes and rendering of a QSGEngine.
+    \inmodule QtQuick
+    \since 5.4
+
+    A QSGAbstractRenderer created by a QSGEngine allows you to set your QSGNode
+    tree through setRootNode() and control the rendering viewport through
+    setDeviceRect(), setViewportRect() and setProjectionMatrixToRect().
+    You can finally trigger the rendering to the desired framebuffer through
+    renderScene().
+
+    The QSGAbstractRenderer is only available when used with a QSGEngine
+    and isn't exposed when used internally by QQuickWindow.
+
+    \sa QSGEngine, QSGNode
+ */
+
+/*!
+    \enum QSGAbstractRenderer::ClearModeBit
+
+    Used with setClearMode() to indicate which buffer should
+    be cleared before the scene render.
+
+    \value ClearColorBuffer Clear the color buffer using clearColor().
+    \value ClearDepthBuffer Clear the depth buffer.
+    \value ClearStencilBuffer Clear the stencil buffer.
+
+    \sa setClearMode(), setClearColor()
+ */
+
+/*!
+    \fn void QSGAbstractRenderer::renderScene(GLuint fboId = 0)
+
+    Render the scene to the specified \a fboId
+
+    If \a fboId isn't specified, the scene graph will be rendered
+    to the default framebuffer. You will have to call
+    QOpenGLContext::swapBuffers() yourself afterward.
+
+    The framebuffer specified by \a fboId will be bound automatically.
+
+    \sa QOpenGLContext::swapBuffers(), QOpenGLFramebufferObject::handle()
+ */
+
+/*!
+    \fn void QSGAbstractRenderer::sceneGraphChanged()
+
+    This signal is emitted on the first modification of a node in
+    the tree after the last scene render.
+ */
+
+/*!
+    \internal
+ */
+QSGAbstractRendererPrivate::QSGAbstractRendererPrivate()
+    : m_root_node(0)
+    , m_clear_color(Qt::transparent)
+    , m_clear_mode(QSGAbstractRenderer::ClearColorBuffer | QSGAbstractRenderer::ClearDepthBuffer)
+{
+}
+
+/*!
+    \internal
+ */
+QSGAbstractRenderer::QSGAbstractRenderer(QObject *parent)
+    : QObject(*new QSGAbstractRendererPrivate, parent)
+{
+}
+
+/*!
+    \internal
+ */
+QSGAbstractRenderer::~QSGAbstractRenderer()
+{
+}
+
+/*!
+    Sets the \a node as the root of the QSGNode scene
+    that you want to render. You need to provide a \a node
+    before trying to render the scene.
+
+    \note This doesn't take ownership of \a node.
+
+    \sa rootNode()
+*/
+void QSGAbstractRenderer::setRootNode(QSGRootNode *node)
+{
+    Q_D(QSGAbstractRenderer);
+    if (d->m_root_node == node)
+        return;
+    if (d->m_root_node) {
+        d->m_root_node->m_renderers.removeOne(this);
+        nodeChanged(d->m_root_node, QSGNode::DirtyNodeRemoved);
+    }
+    d->m_root_node = node;
+    if (d->m_root_node) {
+        Q_ASSERT(!d->m_root_node->m_renderers.contains(this));
+        d->m_root_node->m_renderers << this;
+        nodeChanged(d->m_root_node, QSGNode::DirtyNodeAdded);
+    }
+}
+
+/*!
+    Returns the root of the QSGNode scene.
+
+    \sa setRootNode()
+*/
+QSGRootNode *QSGAbstractRenderer::rootNode() const
+{
+    Q_D(const QSGAbstractRenderer);
+    return d->m_root_node;
+}
+
+
+/*!
+    \fn void QSGAbstractRenderer::setDeviceRect(const QSize &size)
+    \overload
+
+    Sets the \a size of the surface being rendered to.
+
+    \sa deviceRect()
+ */
+
+/*!
+    Sets \a rect as the geometry of the surface being rendered to.
+
+    \sa deviceRect()
+ */
+void QSGAbstractRenderer::setDeviceRect(const QRect &rect)
+{
+    Q_D(QSGAbstractRenderer);
+    d->m_device_rect = rect;
+}
+
+/*!
+    Returns the device rect of the surface being rendered to.
+
+    \sa setDeviceRect()
+ */
+QRect QSGAbstractRenderer::deviceRect() const
+{
+    Q_D(const QSGAbstractRenderer);
+    return d->m_device_rect;
+}
+
+/*!
+    \fn void QSGAbstractRenderer::setViewportRect(const QSize &size)
+    \overload
+
+    Sets the \a size of the viewport to render
+    on the surface.
+
+    \sa viewportRect()
+ */
+
+/*!
+    Sets \a rect as the geometry of the viewport to render
+    on the surface.
+
+    \sa viewportRect()
+ */
+void QSGAbstractRenderer::setViewportRect(const QRect &rect)
+{
+    Q_D(QSGAbstractRenderer);
+    d->m_viewport_rect = rect;
+}
+
+/*!
+    Returns the rect of the viewport to render.
+
+    \sa setViewportRect()
+ */
+QRect QSGAbstractRenderer::viewportRect() const
+{
+    Q_D(const QSGAbstractRenderer);
+    return d->m_viewport_rect;
+}
+
+/*!
+    Convenience method that calls setProjectionMatrix() with an
+    orthographic matrix generated from \a rect.
+
+    \sa setProjectionMatrix(), projectionMatrix()
+ */
+void QSGAbstractRenderer::setProjectionMatrixToRect(const QRectF &rect)
+{
+    QMatrix4x4 matrix;
+    matrix.ortho(rect.x(),
+                 rect.x() + rect.width(),
+                 rect.y() + rect.height(),
+                 rect.y(),
+                 1,
+                 -1);
+    setProjectionMatrix(matrix);
+}
+
+/*!
+    Use \a matrix to project the QSGNode coordinates onto surface pixels.
+
+    \sa projectionMatrix(), setProjectionMatrixToRect()
+ */
+void QSGAbstractRenderer::setProjectionMatrix(const QMatrix4x4 &matrix)
+{
+    Q_D(QSGAbstractRenderer);
+    d->m_projection_matrix = matrix;
+}
+
+/*!
+    Returns the projection matrix
+
+    \sa setProjectionMatrix(), setProjectionMatrixToRect()
+ */
+QMatrix4x4 QSGAbstractRenderer::projectionMatrix() const
+{
+    Q_D(const QSGAbstractRenderer);
+    return d->m_projection_matrix;
+}
+
+/*!
+    Use \a color to clear the framebuffer when clearMode() is
+    set to QSGAbstractRenderer::ClearColorBuffer.
+
+    \sa clearColor(), setClearMode()
+ */
+void QSGAbstractRenderer::setClearColor(const QColor &color)
+{
+    Q_D(QSGAbstractRenderer);
+    d->m_clear_color = color;
+}
+
+/*!
+    Returns the color that clears the framebuffer at the beginning
+    of the rendering.
+
+    \sa setClearColor(), clearMode()
+ */
+QColor QSGAbstractRenderer::clearColor() const
+{
+    Q_D(const QSGAbstractRenderer);
+    return d->m_clear_color;
+}
+
+/*!
+    Defines which attachment of the framebuffer should be cleared
+    before each scene render with the \a mode flag.
+
+    \sa clearMode(), setClearColor()
+ */
+void QSGAbstractRenderer::setClearMode(ClearMode mode)
+{
+    Q_D(QSGAbstractRenderer);
+    d->m_clear_mode = mode;
+}
+
+/*!
+    Flags defining which attachment of the framebuffer will be cleared
+    before each scene render.
+
+    \sa setClearMode(), clearColor()
+ */
+QSGAbstractRenderer::ClearMode QSGAbstractRenderer::clearMode() const
+{
+    Q_D(const QSGAbstractRenderer);
+    return d->m_clear_mode;
+}
+
+/*!
+    \fn void QSGAbstractRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
+    \internal
+ */
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgabstractrenderer.h b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h
new file mode 100644 (file)
index 0000000..671d62e
--- /dev/null
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick 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 QSGABSTRACTRENDERER_H
+#define QSGABSTRACTRENDERER_H
+
+#include "qsgnode.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGAbstractRendererPrivate;
+
+class Q_QUICK_EXPORT QSGAbstractRenderer : public QObject
+{
+    Q_OBJECT
+public:
+    enum ClearModeBit
+    {
+        ClearColorBuffer    = 0x0001,
+        ClearDepthBuffer    = 0x0002,
+        ClearStencilBuffer  = 0x0004
+    };
+    Q_DECLARE_FLAGS(ClearMode, ClearModeBit)
+
+    virtual ~QSGAbstractRenderer();
+
+    void setRootNode(QSGRootNode *node);
+    QSGRootNode *rootNode() const;
+    void setDeviceRect(const QRect &rect);
+    inline void setDeviceRect(const QSize &size) { setDeviceRect(QRect(QPoint(), size)); }
+    QRect deviceRect() const;
+
+    void setViewportRect(const QRect &rect);
+    inline void setViewportRect(const QSize &size) { setViewportRect(QRect(QPoint(), size)); }
+    QRect viewportRect() const;
+
+    void setProjectionMatrixToRect(const QRectF &rect);
+    void setProjectionMatrix(const QMatrix4x4 &matrix);
+    QMatrix4x4 projectionMatrix() const;
+
+    void setClearColor(const QColor &color);
+    QColor clearColor() const;
+
+    void setClearMode(ClearMode mode);
+    ClearMode clearMode() const;
+
+    virtual void renderScene(GLuint fboId = 0) = 0;
+
+Q_SIGNALS:
+    void sceneGraphChanged();
+
+protected:
+    QSGAbstractRenderer(QObject *parent = 0);
+    virtual void nodeChanged(QSGNode *node, QSGNode::DirtyState state) = 0;
+
+private:
+    Q_DECLARE_PRIVATE(QSGAbstractRenderer)
+    friend class QSGRootNode;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGAbstractRenderer::ClearMode)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/scenegraph/coreapi/qsgabstractrenderer_p.h b/src/quick/scenegraph/coreapi/qsgabstractrenderer_p.h
new file mode 100644 (file)
index 0000000..c60a488
--- /dev/null
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick 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 QSGABSTRACTRENDERER_P_H
+#define QSGABSTRACTRENDERER_P_H
+
+#include "qsgabstractrenderer.h"
+
+#include "qsgnode.h"
+#include <qcolor.h>
+
+#include <QtCore/private/qobject_p.h>
+#include <QtQuick/private/qtquickglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_PRIVATE_EXPORT QSGAbstractRendererPrivate : public QObjectPrivate
+{
+    Q_DECLARE_PUBLIC(QSGAbstractRenderer)
+public:
+    static const QSGAbstractRendererPrivate *get(const QSGAbstractRenderer *q) { return q->d_func(); }
+
+    QSGAbstractRendererPrivate();
+    void updateProjectionMatrix();
+
+    QSGRootNode *m_root_node;
+    QColor m_clear_color;
+    QSGAbstractRenderer::ClearMode m_clear_mode;
+
+    QRect m_device_rect;
+    QRect m_viewport_rect;
+
+    QMatrix4x4 m_projection_matrix;
+    uint m_mirrored : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif
index 380b7e0..be93fd1 100644 (file)
@@ -53,6 +53,7 @@ QT_BEGIN_NAMESPACE
 #define QSG_RUNTIME_DESCRIPTION
 #endif
 
+class QSGAbstractRenderer;
 class QSGRenderer;
 
 class QSGNode;
@@ -298,11 +299,11 @@ public:
 private:
     void notifyNodeChange(QSGNode *node, DirtyState state);
 
-    friend class QSGRenderer;
+    friend class QSGAbstractRenderer;
     friend class QSGNode;
     friend class QSGGeometryNode;
 
-    QList<QSGRenderer *> m_renderers;
+    QList<QSGAbstractRenderer *> m_renderers;
 };
 
 
index c056507..3c9042f 100644 (file)
 ****************************************************************************/
 
 #include "qsgrenderer_p.h"
-#include "qsgnode.h"
-#include "qsgmaterial.h"
 #include "qsgnodeupdater_p.h"
-#include "qsggeometry_p.h"
-
-#include <private/qsgadaptationlayer_p.h>
-#include <private/qsgshadersourcebuilder_p.h>
 
 #include <qopenglframebufferobject.h>
-#include <QtGui/qguiapplication.h>
-
-#include <qdatetime.h>
 
 #include <private/qquickprofiler_p.h>
 
@@ -63,12 +54,12 @@ static QElapsedTimer frameTimer;
 static qint64 preprocessTime;
 static qint64 updatePassTime;
 
-void QSGBindable::clear(QSGRenderer::ClearMode mode) const
+void QSGBindable::clear(QSGAbstractRenderer::ClearMode mode) const
 {
     GLuint bits = 0;
-    if (mode & QSGRenderer::ClearColorBuffer) bits |= GL_COLOR_BUFFER_BIT;
-    if (mode & QSGRenderer::ClearDepthBuffer) bits |= GL_DEPTH_BUFFER_BIT;
-    if (mode & QSGRenderer::ClearStencilBuffer) bits |= GL_STENCIL_BUFFER_BIT;
+    if (mode & QSGAbstractRenderer::ClearColorBuffer) bits |= GL_COLOR_BUFFER_BIT;
+    if (mode & QSGAbstractRenderer::ClearDepthBuffer) bits |= GL_DEPTH_BUFFER_BIT;
+    if (mode & QSGAbstractRenderer::ClearStencilBuffer) bits |= GL_STENCIL_BUFFER_BIT;
     QOpenGLContext::currentContext()->functions()->glClear(bits);
 }
 
@@ -118,18 +109,13 @@ void QSGBindableFboId::bind() const
 
 
 QSGRenderer::QSGRenderer(QSGRenderContext *context)
-    : QObject()
-    , m_clear_color(Qt::transparent)
-    , m_clear_mode(ClearColorBuffer | ClearDepthBuffer)
-    , m_current_opacity(1)
+    : m_current_opacity(1)
     , m_current_determinant(1)
     , m_device_pixel_ratio(1)
     , m_context(context)
-    , m_root_node(0)
     , m_node_updater(0)
     , m_bindable(0)
     , m_changed_emitted(false)
-    , m_mirrored(false)
     , m_is_rendering(false)
 {
 }
@@ -169,37 +155,30 @@ void QSGRenderer::setNodeUpdater(QSGNodeUpdater *updater)
     m_node_updater = updater;
 }
 
-
-void QSGRenderer::setRootNode(QSGRootNode *node)
+bool QSGRenderer::isMirrored() const
 {
-    if (m_root_node == node)
-        return;
-    if (m_root_node) {
-        m_root_node->m_renderers.removeOne(this);
-        nodeChanged(m_root_node, QSGNode::DirtyNodeRemoved);
-    }
-    m_root_node = node;
-    if (m_root_node) {
-        Q_ASSERT(!m_root_node->m_renderers.contains(this));
-        m_root_node->m_renderers << this;
-        nodeChanged(m_root_node, QSGNode::DirtyNodeAdded);
-    }
+    QMatrix4x4 matrix = projectionMatrix();
+    // Mirrored relative to the usual Qt coordinate system with origin in the top left corner.
+    return matrix(0, 0) * matrix(1, 1) - matrix(0, 1) * matrix(1, 0) > 0;
 }
 
-
-void QSGRenderer::renderScene()
+void QSGRenderer::renderScene(GLuint fboId)
 {
-    class B : public QSGBindable
-    {
-    public:
-        void bind() const { QOpenGLFramebufferObject::bindDefault(); }
-    } b;
-    renderScene(b);
+    if (fboId) {
+        QSGBindableFboId bindable(fboId);
+        renderScene(bindable);
+    } else {
+        class B : public QSGBindable
+        {
+        public:
+            void bind() const { QOpenGLFramebufferObject::bindDefault(); }
+        } bindable;
+        renderScene(bindable);
+    }
 }
-
 void QSGRenderer::renderScene(const QSGBindable &bindable)
 {
-    if (!m_root_node)
+    if (!rootNode())
         return;
 
     m_is_rendering = true;
@@ -255,30 +234,6 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
 
 }
 
-void QSGRenderer::setProjectionMatrixToRect(const QRectF &rect)
-{
-    QMatrix4x4 matrix;
-    matrix.ortho(rect.x(),
-                 rect.x() + rect.width(),
-                 rect.y() + rect.height(),
-                 rect.y(),
-                 1,
-                 -1);
-    setProjectionMatrix(matrix);
-}
-
-void QSGRenderer::setProjectionMatrix(const QMatrix4x4 &matrix)
-{
-    m_projection_matrix = matrix;
-    // Mirrored relative to the usual Qt coordinate system with origin in the top left corner.
-    m_mirrored = matrix(0, 0) * matrix(1, 1) - matrix(0, 1) * matrix(1, 0) > 0;
-}
-
-void QSGRenderer::setClearColor(const QColor &color)
-{
-    m_clear_color = color;
-}
-
 /*!
     Updates internal data structures and emits the sceneGraphChanged() signal.
 
@@ -309,7 +264,8 @@ void QSGRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
 
 void QSGRenderer::preprocess()
 {
-    Q_ASSERT(m_root_node);
+    QSGRootNode *root = rootNode();
+    Q_ASSERT(root);
 
     // We need to take a copy here, in case any of the preprocess calls deletes a node that
     // is in the preprocess list and thus, changes the m_nodes_to_preprocess behind our backs
@@ -319,7 +275,7 @@ void QSGRenderer::preprocess()
     for (QSet<QSGNode *>::const_iterator it = items.constBegin();
          it != items.constEnd(); ++it) {
         QSGNode *n = *it;
-        if (!nodeUpdater()->isNodeBlocked(n, m_root_node)) {
+        if (!nodeUpdater()->isNodeBlocked(n, root)) {
             n->preprocess();
         }
     }
@@ -328,7 +284,7 @@ void QSGRenderer::preprocess()
     if (profileFrames)
         preprocessTime = frameTimer.nsecsElapsed();
 
-    nodeUpdater()->updateStates(m_root_node);
+    nodeUpdater()->updateStates(root);
 
     if (profileFrames)
         updatePassTime = frameTimer.nsecsElapsed();
index e24a6b6..e6e7c13 100644 (file)
 #ifndef QSGRENDERER_P_H
 #define QSGRENDERER_P_H
 
-#include <qcolor.h>
-#include <qset.h>
-#include <qhash.h>
-
+#include "qsgabstractrenderer.h"
+#include "qsgabstractrenderer_p.h"
 #include "qsgnode.h"
 #include "qsgmaterial.h"
-#include <QtQuick/qsgtexture.h>
 
 #include <QtQuick/private/qsgcontext_p.h>
 
 QT_BEGIN_NAMESPACE
 
-class QSGMaterialShader;
-struct QSGMaterialType;
-class QOpenGLFramebufferObject;
-class TextureReference;
 class QSGBindable;
 class QSGNodeUpdater;
 
 Q_QUICK_PRIVATE_EXPORT bool qsg_test_and_clear_fatal_render_error();
 Q_QUICK_PRIVATE_EXPORT void qsg_set_fatal_renderer_error();
 
-class Q_QUICK_PRIVATE_EXPORT QSGRenderer : public QObject
+class Q_QUICK_PRIVATE_EXPORT QSGRenderer : public QSGAbstractRenderer
 {
-    Q_OBJECT
 public:
-    enum ClearModeBit
-    {
-        ClearColorBuffer    = 0x0001,
-        ClearDepthBuffer    = 0x0002,
-        ClearStencilBuffer  = 0x0004
-    };
-    Q_DECLARE_FLAGS(ClearMode, ClearModeBit)
 
     QSGRenderer(QSGRenderContext *context);
     virtual ~QSGRenderer();
 
-    void setRootNode(QSGRootNode *node);
-    QSGRootNode *rootNode() const { return m_root_node; }
-
-    void setDeviceRect(const QRect &rect) { m_device_rect = rect; }
-    inline void setDeviceRect(const QSize &size) { setDeviceRect(QRect(QPoint(), size)); }
-    QRect deviceRect() const { return m_device_rect; }
-
-    void setViewportRect(const QRect &rect) { m_viewport_rect = rect; }
-    inline void setViewportRect(const QSize &size) { setViewportRect(QRect(QPoint(), size)); }
-    QRect viewportRect() const { return m_viewport_rect; }
-
     // Accessed by QSGMaterialShader::RenderState.
     QMatrix4x4 currentProjectionMatrix() const { return m_current_projection_matrix; }
     QMatrix4x4 currentModelViewMatrix() const { return m_current_model_view_matrix; }
@@ -99,36 +73,22 @@ public:
 
     void setDevicePixelRatio(qreal ratio) { m_device_pixel_ratio = ratio; }
     qreal devicePixelRatio() const { return m_device_pixel_ratio; }
-
-    virtual void setProjectionMatrixToRect(const QRectF &rect);
-    void setProjectionMatrix(const QMatrix4x4 &matrix);
-    QMatrix4x4 projectionMatrix() const { return m_projection_matrix; }
-    bool isMirrored() const { return m_mirrored; }
-
-    void setClearColor(const QColor &color);
-    QColor clearColor() const { return m_clear_color; }
-
     QSGRenderContext *context() const { return m_context; }
 
-    void renderScene();
+    bool isMirrored() const;
     void renderScene(const QSGBindable &bindable);
-    virtual void nodeChanged(QSGNode *node, QSGNode::DirtyState state);
+    virtual void renderScene(GLuint fboId = 0) Q_DECL_FINAL Q_DECL_OVERRIDE;
+    virtual void nodeChanged(QSGNode *node, QSGNode::DirtyState state) Q_DECL_OVERRIDE;
 
     QSGNodeUpdater *nodeUpdater() const;
     void setNodeUpdater(QSGNodeUpdater *updater);
 
     inline QSGMaterialShader::RenderState state(QSGMaterialShader::RenderState::DirtyStates dirty) const;
 
-    void setClearMode(ClearMode mode) { m_clear_mode = mode; }
-    ClearMode clearMode() const { return m_clear_mode; }
-
     virtual void setCustomRenderMode(const QByteArray &) { };
 
     void clearChangedFlag() { m_changed_emitted = false; }
 
-Q_SIGNALS:
-    void sceneGraphChanged(); // Add, remove, ChangeFlags changes...
-
 protected:
     virtual void render() = 0;
 
@@ -141,8 +101,6 @@ protected:
 
     void markNodeDirtyState(QSGNode *node, QSGNode::DirtyState state) { node->m_dirtyState |= state; }
 
-    QColor m_clear_color;
-    ClearMode m_clear_mode;
     QMatrix4x4 m_current_projection_matrix;
     QMatrix4x4 m_current_model_view_matrix;
     qreal m_current_opacity;
@@ -152,31 +110,22 @@ protected:
     QSGRenderContext *m_context;
 
 private:
-    QSGRootNode *m_root_node;
     QSGNodeUpdater *m_node_updater;
 
-    QRect m_device_rect;
-    QRect m_viewport_rect;
-
     QSet<QSGNode *> m_nodes_to_preprocess;
 
-    QMatrix4x4 m_projection_matrix;
-
     const QSGBindable *m_bindable;
 
     uint m_changed_emitted : 1;
-    uint m_mirrored : 1;
     uint m_is_rendering : 1;
 };
 
-Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderer::ClearMode)
-
 class Q_QUICK_PRIVATE_EXPORT QSGBindable
 {
 public:
     virtual ~QSGBindable() { }
     virtual void bind() const = 0;
-    virtual void clear(QSGRenderer::ClearMode mode) const;
+    virtual void clear(QSGAbstractRenderer::ClearMode mode) const;
     virtual void reactivate() const;
 };
 
index 1a3565b..5bc9199 100644 (file)
@@ -363,6 +363,7 @@ QSGRenderContext::QSGRenderContext(QSGContext *context)
     , m_distanceFieldCacheManager(0)
     , m_brokenIBOs(false)
     , m_serializedRender(false)
+    , m_attachToGLContext(true)
 {
 }
 
@@ -384,12 +385,7 @@ void QSGRenderContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId)
     if (m_serializedRender)
         qsg_framerender_mutex.lock();
 
-    if (fboId) {
-        QSGBindableFboId bindable(fboId);
-        renderer->renderScene(bindable);
-    } else {
-        renderer->renderScene();
-    }
+    renderer->renderScene(fboId);
 
     if (m_serializedRender)
         qsg_framerender_mutex.unlock();
@@ -441,6 +437,12 @@ QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRaw
     return cache;
 }
 
+void QSGRenderContext::setAttachToGLContext(bool attach)
+{
+    Q_ASSERT(!isValid());
+    m_attachToGLContext = attach;
+}
+
 #define QSG_RENDERCONTEXT_PROPERTY "_q_sgrendercontext"
 
 QSGRenderContext *QSGRenderContext::from(QOpenGLContext *context)
@@ -473,7 +475,10 @@ void QSGRenderContext::initialize(QOpenGLContext *context)
 
     Q_ASSERT_X(!m_gl, "QSGRenderContext::initialize", "already initialized!");
     m_gl = context;
-    m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant::fromValue(this));
+    if (m_attachToGLContext) {
+        Q_ASSERT(!context->property(QSG_RENDERCONTEXT_PROPERTY).isValid());
+        context->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant::fromValue(this));
+    }
     m_sg->renderContextInitialized(this);
 
 #ifdef Q_OS_LINUX
@@ -541,7 +546,8 @@ void QSGRenderContext::invalidate()
     delete m_distanceFieldCacheManager;
     m_distanceFieldCacheManager = 0;
 
-    m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant());
+    if (m_gl->property(QSG_RENDERCONTEXT_PROPERTY) == QVariant::fromValue(this))
+        m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant());
     m_gl = 0;
 
     m_sg->renderContextInvalidated(this);
index faad57b..7113ef8 100644 (file)
@@ -97,6 +97,7 @@ public:
 
     QOpenGLContext *openglContext() const { return m_gl; }
     QSGContext *sceneGraphContext() const { return m_sg; }
+    bool isValid() const { return m_gl; }
 
     virtual void initialize(QOpenGLContext *context);
     virtual void invalidate();
@@ -117,6 +118,7 @@ public:
     virtual void compile(QSGMaterialShader *shader, QSGMaterial *material, const char *vertexCode = 0, const char *fragmentCode = 0);
     virtual void initialize(QSGMaterialShader *shader);
 
+    void setAttachToGLContext(bool attach);
     void registerFontengineForCleanup(QFontEngine *engine);
 
     static QSGRenderContext *from(QOpenGLContext *context);
@@ -146,6 +148,7 @@ protected:
 
     bool m_brokenIBOs;
     bool m_serializedRender;
+    bool m_attachToGLContext;
 };
 
 
index 570d6b9..d08fce0 100644 (file)
@@ -10,12 +10,15 @@ HEADERS += \
     $$PWD/coreapi/qsgnode.h \
     $$PWD/coreapi/qsgnode_p.h \
     $$PWD/coreapi/qsgnodeupdater_p.h \
+    $$PWD/coreapi/qsgabstractrenderer.h \
+    $$PWD/coreapi/qsgabstractrenderer_p.h \
     $$PWD/coreapi/qsgrenderer_p.h \
     $$PWD/coreapi/qsgrendernode_p.h \
     $$PWD/coreapi/qsggeometry_p.h \
     $$PWD/coreapi/qsgmaterialshader_p.h
 
 SOURCES += \
+    $$PWD/coreapi/qsgabstractrenderer.cpp \
     $$PWD/coreapi/qsgbatchrenderer.cpp \
     $$PWD/coreapi/qsggeometry.cpp \
     $$PWD/coreapi/qsgmaterial.cpp \
@@ -30,6 +33,8 @@ HEADERS += \
     $$PWD/util/qsgareaallocator_p.h \
     $$PWD/util/qsgatlastexture_p.h \
     $$PWD/util/qsgdepthstencilbuffer_p.h \
+    $$PWD/util/qsgengine.h \
+    $$PWD/util/qsgengine_p.h \
     $$PWD/util/qsgflatcolormaterial.h \
     $$PWD/util/qsgsimplematerial.h \
     $$PWD/util/qsgsimplerectnode.h \
@@ -48,6 +53,7 @@ SOURCES += \
     $$PWD/util/qsgareaallocator.cpp \
     $$PWD/util/qsgatlastexture.cpp \
     $$PWD/util/qsgdepthstencilbuffer.cpp \
+    $$PWD/util/qsgengine.cpp \
     $$PWD/util/qsgflatcolormaterial.cpp \
     $$PWD/util/qsgsimplerectnode.cpp \
     $$PWD/util/qsgsimpletexturenode.cpp \
diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp
new file mode 100644 (file)
index 0000000..127f624
--- /dev/null
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick 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 "qsgengine_p.h"
+
+#include <QtQuick/qsgtexture.h>
+#include <private/qsgcontext_p.h>
+#include <private/qsgrenderer_p.h>
+#include <private/qsgtexture_p.h>
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+    \class QSGEngine
+    \brief The QSGEngine class allows low level rendering of a scene graph.
+    \inmodule QtQuick
+    \since 5.4
+
+    A QSGEngine can be used to render a tree of QSGNode directly on a QWindow
+    or QOpenGLFramebufferObject without any integration with QML, QQuickWindow
+    or QQuickItem and the convenience that they provide.
+
+    This means that you must handle event propagation, animation timing,
+    and node lifetime yourself.
+
+    \note This class is for very low level access to an independent scene graph.
+    Most of the time you will instead want to subclass QQuickItem and insert
+    your QSGNode in a normal QtQuick scene by overriding QQuickItem::updatePaintNode().
+
+    \sa QSGAbstractRenderer
+ */
+
+/*!
+    \enum QSGEngine::CreateTextureOption
+
+    The CreateTextureOption enums are used to customize how a texture is wrapped.
+
+    \value TextureHasAlphaChannel The texture has an alpha channel and should
+    be drawn using blending.
+
+    \value TextureOwnsGLTexture The texture object owns the texture id and
+    will delete the GL texture when the texture object is deleted.
+
+    \value TextureCanUseAtlas The image can be uploaded into a texture atlas.
+ */
+
+QSGEnginePrivate::QSGEnginePrivate()
+    : sgContext(QSGContext::createDefaultContext())
+    , sgRenderContext(new QSGRenderContext(sgContext.data()))
+{
+}
+
+/*!
+    Constructs a new QSGEngine with its \a parent
+ */
+QSGEngine::QSGEngine(QObject *parent)
+    : QObject(*(new QSGEnginePrivate), parent)
+{
+}
+
+/*!
+    Destroys the engine
+ */
+QSGEngine::~QSGEngine()
+{
+}
+
+/*!
+    Initialize the engine with \a context.
+
+    \warning You have to make sure that you call
+    QOpenGLContext::makeCurrent() on \a context before calling this.
+ */
+void QSGEngine::initialize(QOpenGLContext *context)
+{
+    Q_D(QSGEngine);
+    if (QOpenGLContext::currentContext() != context) {
+        qWarning("WARNING: The context must be current before calling QSGEngine::initialize.");
+        return;
+    }
+
+    if (!d->sgRenderContext->isValid()) {
+        d->sgRenderContext->setAttachToGLContext(false);
+        d->sgRenderContext->initialize(context);
+        connect(context, &QOpenGLContext::aboutToBeDestroyed, this, &QSGEngine::invalidate);
+    }
+}
+
+/*!
+    Invalidate the engine releasing its resources
+
+    You will have to call initialize() and createRenderer() if you
+    want to use it again.
+ */
+void QSGEngine::invalidate()
+{
+    Q_D(QSGEngine);
+    d->sgRenderContext->invalidate();
+}
+
+/*!
+    Returns a renderer that can be used to render a QSGNode tree
+
+    You call initialize() first with the QOpenGLContext that you
+    want to use with this renderer. This will return a null
+    renderer otherwise.
+ */
+QSGAbstractRenderer *QSGEngine::createRenderer() const
+{
+    Q_D(const QSGEngine);
+    if (!d->sgRenderContext->isValid())
+        return 0;
+
+    QSGRenderer *renderer = d->sgRenderContext->createRenderer();
+    renderer->setCustomRenderMode(qgetenv("QSG_VISUALIZE"));
+    return renderer;
+}
+
+/*!
+    Creates a texture using the data of \a image
+
+    Valid \a options are TextureCanUseAtlas
+
+    The caller takes ownership of the texture and the
+    texture should only be used with this engine.
+
+    \sa createTextureFromId(), QSGSimpleTextureNode::setOwnsTexture(), QQuickWindow::createTextureFromImage()
+ */
+QSGTexture *QSGEngine::createTextureFromImage(const QImage &image, CreateTextureOptions options) const
+{
+    Q_D(const QSGEngine);
+    if (!d->sgRenderContext->isValid())
+        return 0;
+
+    if (options & TextureCanUseAtlas)
+        return d->sgRenderContext->createTexture(image);
+    else
+        return d->sgRenderContext->createTextureNoAtlas(image);
+}
+
+/*!
+    Creates a texture object that wraps the GL texture \a id uploaded with \a size
+
+    Valid \a options are TextureHasAlphaChannel and TextureOwnsGLTexture
+
+    The caller takes ownership of the texture object and the
+    texture should only be used with this engine.
+
+    \sa createTextureFromImage(), QSGSimpleTextureNode::setOwnsTexture(), QQuickWindow::createTextureFromId()
+ */
+QSGTexture *QSGEngine::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
+{
+    Q_D(const QSGEngine);
+    if (d->sgRenderContext->isValid()) {
+        QSGPlainTexture *texture = new QSGPlainTexture();
+        texture->setTextureId(id);
+        texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
+        texture->setOwnsTexture(options & TextureOwnsGLTexture);
+        texture->setTextureSize(size);
+        return texture;
+    }
+    return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h
new file mode 100644 (file)
index 0000000..7aae882
--- /dev/null
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick 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 QSGENGINE_H
+#define QSGENGINE_H
+
+#include <QtCore/QObject>
+#include <QtQuick/qtquickglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLContext;
+class QSGAbstractRenderer;
+class QSGEnginePrivate;
+class QSGTexture;
+
+class Q_QUICK_EXPORT QSGEngine : public QObject
+{
+    Q_OBJECT
+    Q_DECLARE_PRIVATE(QSGEngine)
+public:
+    enum CreateTextureOption {
+        TextureHasAlphaChannel  = 0x0001,
+        TextureOwnsGLTexture    = 0x0004,
+        TextureCanUseAtlas      = 0x0008
+    };
+    Q_DECLARE_FLAGS(CreateTextureOptions, CreateTextureOption)
+
+    QSGEngine(QObject *parent = 0);
+    ~QSGEngine();
+
+    void initialize(QOpenGLContext *context);
+    void invalidate();
+
+    QSGAbstractRenderer *createRenderer() const;
+    QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options = CreateTextureOption(0)) const;
+    QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption(0)) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGENGINE_H
diff --git a/src/quick/scenegraph/util/qsgengine_p.h b/src/quick/scenegraph/util/qsgengine_p.h
new file mode 100644 (file)
index 0000000..a7e1599
--- /dev/null
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick 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 QSGENGINE_P_H
+#define QSGENGINE_P_H
+
+#include "qsgengine.h"
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGContext;
+class QSGRenderContext;
+
+class QSGEnginePrivate : public QObjectPrivate
+{
+    Q_DECLARE_PUBLIC(QSGEngine)
+
+public:
+    QSGEnginePrivate();
+
+    QScopedPointer<QSGContext> sgContext;
+    QScopedPointer<QSGRenderContext> sgRenderContext;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGENGINE_P_H