diff --git a/examples/quick/scenegraph/scenegraph.pro b/examples/quick/scenegraph/scenegraph.pro index 435495444509aacc9dd661d627587437721d6db2..85ae25907ab6540a881bd38b64fb45f6bb91e461 100644 --- a/examples/quick/scenegraph/scenegraph.pro +++ b/examples/quick/scenegraph/scenegraph.pro @@ -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 index 0000000000000000000000000000000000000000..3d66d725781730c7a9376a25113164f8882d9795 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 index 0000000000000000000000000000000000000000..9a9450710b8e2acde33d1d0fef3e7e54cdc048cb --- /dev/null +++ b/examples/quick/scenegraph/sgengine/main.cpp @@ -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 index 0000000000000000000000000000000000000000..c6507a4982e614c3fe1d8c72ed7854cea67a3959 --- /dev/null +++ b/examples/quick/scenegraph/sgengine/sgengine.pro @@ -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 index 0000000000000000000000000000000000000000..5d55bcfb6fc5af6f14844affa5d699dcfa3edc42 --- /dev/null +++ b/examples/quick/scenegraph/sgengine/sgengine.qrc @@ -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 index 0000000000000000000000000000000000000000..9af4029165271d7e1b39b0829ff189a5dfe2c73a --- /dev/null +++ b/examples/quick/scenegraph/sgengine/window.cpp @@ -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 index 0000000000000000000000000000000000000000..2b239ea430379cd6b3d7c47d35f5bf4f854975f5 --- /dev/null +++ b/examples/quick/scenegraph/sgengine/window.h @@ -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; +}; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 12be33d79096766889848883e48aed7edd9ab17b..f1d2f63756c6cccbcf5e734fe22aa0242155e2ba 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -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 index 0000000000000000000000000000000000000000..9409822c8f1e8578f23f209038e2f0c9d4890f70 --- /dev/null +++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp @@ -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 index 0000000000000000000000000000000000000000..671d62e931f255b8273e30824acd60e9f3c41116 --- /dev/null +++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h @@ -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 index 0000000000000000000000000000000000000000..c60a488cc85b19aff51ae9fdf87b63cb03817c5f --- /dev/null +++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer_p.h @@ -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 diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h index 380b7e01e12b7ab5d079957fc4ee66e9e33dffe1..be93fd1fceb6e997d3546181be3c73c66c178575 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.h +++ b/src/quick/scenegraph/coreapi/qsgnode.h @@ -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; }; diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp index c05650772972972895665915e64977a07e97c49f..3c9042fee5d655d134723bc7ae4bc0b52f19e305 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp @@ -40,18 +40,9 @@ ****************************************************************************/ #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(); diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h index e24a6b652f96cc600dafccbed69ea77e682579da..e6e7c13a1d028796ea5e483038e375d245495106 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h @@ -42,54 +42,28 @@ #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; }; diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 1a3565b6307497c35f6bcbceec44f83ed1e6c24b..5bc91992e9780f89d6b64f6241d3c1ca33964d77 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -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); diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index faad57b893bbf206fc8db3fa648a8f982e87da9a..7113ef85301080c339f02374569e904016ccb335 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -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; }; diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri index 570d6b92b50c447cb621fde02930a42122d3a865..d08fce03362a776d57f70fb7b99944cb16d87ca1 100644 --- a/src/quick/scenegraph/scenegraph.pri +++ b/src/quick/scenegraph/scenegraph.pri @@ -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 index 0000000000000000000000000000000000000000..127f624d8b3f77a2322772ed913f46ea73fca254 --- /dev/null +++ b/src/quick/scenegraph/util/qsgengine.cpp @@ -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 index 0000000000000000000000000000000000000000..7aae882a70015c60fb200adf20d8a93be65c0ca5 --- /dev/null +++ b/src/quick/scenegraph/util/qsgengine.h @@ -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 index 0000000000000000000000000000000000000000..a7e1599fd50ba315165a6c3f15a37d0f44295794 --- /dev/null +++ b/src/quick/scenegraph/util/qsgengine_p.h @@ -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