aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/scenegraph')
-rw-r--r--src/quick/scenegraph/adaptations/adaptations.pri1
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp321
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h109
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp81
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation_p.h77
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp192
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h106
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareglyphnode.cpp120
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareglyphnode_p.h84
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode.cpp501
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode_p.h147
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp261
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarelayer_p.h121
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode.cpp109
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode_p.h82
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepainternode.cpp231
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepainternode_p.h132
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp111
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer_p.h76
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaptexture.cpp88
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaptexture_p.h79
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode.cpp451
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode_p.h103
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp328
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h140
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp275
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h137
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp126
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h80
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp163
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h94
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp266
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop_p.h105
-rw-r--r--src/quick/scenegraph/adaptations/software/software.pri39
-rw-r--r--src/quick/scenegraph/coreapi/qsgabstractrenderer.h4
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp82
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h13
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.cpp120
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.h77
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.cpp28
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.h32
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterialshader_p.h2
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.cpp20
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.h6
-rw-r--r--src/quick/scenegraph/coreapi/qsgnodeupdater.cpp7
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer.cpp29
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer_p.h8
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendererinterface.cpp169
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendererinterface.h99
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendernode.cpp236
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendernode.h94
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendernode_p.h51
-rw-r--r--src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp3
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp48
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h132
-rw-r--r--src/quick/scenegraph/qsgbasicglyphnode.cpp95
-rw-r--r--src/quick/scenegraph/qsgbasicglyphnode_p.h92
-rw-r--r--src/quick/scenegraph/qsgbasicimagenode.cpp559
-rw-r--r--src/quick/scenegraph/qsgbasicimagenode_p.h109
-rw-r--r--src/quick/scenegraph/qsgbasicrectanglenode.cpp687
-rw-r--r--src/quick/scenegraph/qsgbasicrectanglenode_p.h99
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp502
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h76
-rw-r--r--src/quick/scenegraph/qsgcontextplugin.cpp161
-rw-r--r--src/quick/scenegraph/qsgcontextplugin_p.h9
-rw-r--r--src/quick/scenegraph/qsgdefaultcontext.cpp269
-rw-r--r--src/quick/scenegraph/qsgdefaultcontext_p.h96
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp2
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode.cpp59
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp3
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.h31
-rw-r--r--src/quick/scenegraph/qsgdefaultimagenode.cpp493
-rw-r--r--src/quick/scenegraph/qsgdefaultimagenode_p.h42
-rw-r--r--src/quick/scenegraph/qsgdefaultlayer.cpp8
-rw-r--r--src/quick/scenegraph/qsgdefaultlayer_p.h10
-rw-r--r--src/quick/scenegraph/qsgdefaultrectanglenode.cpp653
-rw-r--r--src/quick/scenegraph/qsgdefaultrectanglenode_p.h36
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext.cpp302
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext_p.h112
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp55
-rw-r--r--src/quick/scenegraph/qsgrenderloop_p.h6
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp11
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp19
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop_p.h5
-rw-r--r--src/quick/scenegraph/scenegraph.pri255
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture.cpp1
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture_p.h10
-rw-r--r--src/quick/scenegraph/util/qsgdefaultpainternode.cpp3
-rw-r--r--src/quick/scenegraph/util/qsgdefaultpainternode_p.h3
-rw-r--r--src/quick/scenegraph/util/qsgdistancefieldutil.cpp4
-rw-r--r--src/quick/scenegraph/util/qsgengine.cpp33
-rw-r--r--src/quick/scenegraph/util/qsgengine.h2
-rw-r--r--src/quick/scenegraph/util/qsgflatcolormaterial.cpp19
-rw-r--r--src/quick/scenegraph/util/qsgsimplematerial.cpp5
-rw-r--r--src/quick/scenegraph/util/qsgsimplematerial.h9
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp28
-rw-r--r--src/quick/scenegraph/util/qsgtexture_p.h8
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.cpp32
-rw-r--r--src/quick/scenegraph/util/qsgvertexcolormaterial.cpp17
99 files changed, 9422 insertions, 2204 deletions
diff --git a/src/quick/scenegraph/adaptations/adaptations.pri b/src/quick/scenegraph/adaptations/adaptations.pri
new file mode 100644
index 0000000000..40fa739e15
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/adaptations.pri
@@ -0,0 +1 @@
+include(software/software.pri)
diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
new file mode 100644
index 0000000000..eb0e26462a
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
@@ -0,0 +1,321 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgabstractsoftwarerenderer_p.h"
+
+#include "qsgsoftwarerenderablenodeupdater_p.h"
+#include "qsgsoftwarerenderlistbuilder_p.h"
+#include "qsgsoftwarecontext_p.h"
+#include "qsgsoftwarerenderablenode_p.h"
+
+#include <QtCore/QLoggingCategory>
+#include <QtGui/QWindow>
+#include <QtQuick/QSGSimpleRectNode>
+
+Q_LOGGING_CATEGORY(lc2DRender, "qt.scenegraph.softwarecontext.abstractrenderer")
+
+QT_BEGIN_NAMESPACE
+
+QSGAbstractSoftwareRenderer::QSGAbstractSoftwareRenderer(QSGRenderContext *context)
+ : QSGRenderer(context)
+ , m_background(new QSGSimpleRectNode)
+ , m_nodeUpdater(new QSGSoftwareRenderableNodeUpdater(this))
+{
+ // Setup special background node
+ auto backgroundRenderable = new QSGSoftwareRenderableNode(QSGSoftwareRenderableNode::SimpleRect, m_background);
+ addNodeMapping(m_background, backgroundRenderable);
+}
+
+QSGAbstractSoftwareRenderer::~QSGAbstractSoftwareRenderer()
+{
+ // Cleanup RenderableNodes
+ delete m_background;
+
+ for (QSGSoftwareRenderableNode *node : m_nodes.values()) {
+ delete node;
+ }
+
+ delete m_nodeUpdater;
+}
+
+QSGSoftwareRenderableNode *QSGAbstractSoftwareRenderer::renderableNode(QSGNode *node) const
+{
+ return m_nodes.value(node, nullptr);
+}
+
+void QSGAbstractSoftwareRenderer::addNodeMapping(QSGNode *node, QSGSoftwareRenderableNode *renderableNode)
+{
+ m_nodes.insert(node, renderableNode);
+}
+
+void QSGAbstractSoftwareRenderer::appendRenderableNode(QSGSoftwareRenderableNode *node)
+{
+ m_renderableNodes.append(node);
+}
+
+void QSGAbstractSoftwareRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
+{
+ if (state & QSGNode::DirtyGeometry) {
+ nodeGeometryUpdated(node);
+ }
+ if (state & QSGNode::DirtyMaterial) {
+ nodeMaterialUpdated(node);
+ }
+ if (state & QSGNode::DirtyMatrix) {
+ nodeMatrixUpdated(node);
+ }
+ if (state & QSGNode::DirtyNodeAdded) {
+ nodeAdded(node);
+ }
+ if (state & QSGNode::DirtyNodeRemoved) {
+ nodeRemoved(node);
+ }
+ if (state & QSGNode::DirtyOpacity) {
+ nodeOpacityUpdated(node);
+ }
+ if (state & QSGNode::DirtySubtreeBlocked) {
+ m_nodeUpdater->updateNodes(node);
+ }
+ if (state & QSGNode::DirtyForceUpdate) {
+ m_nodeUpdater->updateNodes(node);
+ }
+ QSGRenderer::nodeChanged(node, state);
+}
+
+QRegion QSGAbstractSoftwareRenderer::renderNodes(QPainter *painter)
+{
+ QRegion dirtyRegion;
+ // If there are no nodes, do nothing
+ if (m_renderableNodes.isEmpty())
+ return dirtyRegion;
+
+ auto iterator = m_renderableNodes.begin();
+ // First node is the background and needs to painted without blending
+ auto backgroundNode = *iterator;
+ dirtyRegion += backgroundNode->renderNode(painter, /*force opaque painting*/ true);
+ iterator++;
+
+ for (; iterator != m_renderableNodes.end(); ++iterator) {
+ auto node = *iterator;
+ dirtyRegion += node->renderNode(painter);
+ }
+
+ return dirtyRegion;
+}
+
+void QSGAbstractSoftwareRenderer::buildRenderList()
+{
+ // Clear the previous renderlist
+ m_renderableNodes.clear();
+ // Add the background renderable (always first)
+ m_renderableNodes.append(renderableNode(m_background));
+ // Build the renderlist
+ QSGSoftwareRenderListBuilder(this).visitChildren(rootNode());
+}
+
+void QSGAbstractSoftwareRenderer::optimizeRenderList()
+{
+ // Iterate through the renderlist from front to back
+ // Objective is to update the dirty status and rects.
+ for (auto i = m_renderableNodes.rbegin(); i != m_renderableNodes.rend(); ++i) {
+ auto node = *i;
+ if (!m_dirtyRegion.isEmpty()) {
+ // See if the current dirty regions apply to the current node
+ node->addDirtyRegion(m_dirtyRegion, true);
+ }
+
+ if (!m_obscuredRegion.isEmpty()) {
+ // Don't try to paint things that are covered by opaque objects
+ node->subtractDirtyRegion(m_obscuredRegion);
+ }
+
+ // Keep up with obscured regions
+ if (node->isOpaque()) {
+ m_obscuredRegion += QRegion(node->boundingRect());
+ }
+
+ if (node->isDirty()) {
+ // Don't paint things outside of the rendering area
+ if (!m_background->rect().toRect().contains(node->boundingRect(), /*proper*/ true)) {
+ // Some part(s) of node is(are) outside of the rendering area
+ QRegion renderArea(m_background->rect().toRect());
+ QRegion outsideRegions = node->dirtyRegion().subtracted(renderArea);
+ if (!outsideRegions.isEmpty())
+ node->subtractDirtyRegion(outsideRegions);
+ }
+
+ // Get the dirty region's to pass to the next nodes
+ if (node->isOpaque()) {
+ // if isOpaque, subtract node's dirty rect from m_dirtyRegion
+ m_dirtyRegion -= node->dirtyRegion();
+ } else {
+ // if isAlpha, add node's dirty rect to m_dirtyRegion
+ m_dirtyRegion += node->dirtyRegion();
+ }
+ // if previousDirtyRegion has content outside of boundingRect add to m_dirtyRegion
+ QRegion prevDirty = node->previousDirtyRegion();
+ if (!prevDirty.isNull())
+ m_dirtyRegion += prevDirty;
+ }
+ }
+
+ // Empty dirtyRegion (for second pass)
+ m_dirtyRegion = QRegion();
+ m_obscuredRegion = QRegion();
+
+ // Iterate through the renderlist from back to front
+ // Objective is to make sure all non-opaque items are painted when an item under them is dirty
+ for (auto j = m_renderableNodes.begin(); j != m_renderableNodes.end(); ++j) {
+ auto node = *j;
+
+ if (!node->isOpaque() && !m_dirtyRegion.isEmpty()) {
+ // Only blended nodes need to be updated
+ node->addDirtyRegion(m_dirtyRegion, true);
+ }
+
+ m_dirtyRegion += node->dirtyRegion();
+ }
+
+ // Empty dirtyRegion
+ m_dirtyRegion = QRegion();
+ m_obscuredRegion = QRegion();
+}
+
+void QSGAbstractSoftwareRenderer::setBackgroundColor(const QColor &color)
+{
+ if (m_background->color() == color)
+ return;
+ m_background->setColor(color);
+ renderableNode(m_background)->markMaterialDirty();
+}
+
+void QSGAbstractSoftwareRenderer::setBackgroundSize(const QSize &size)
+{
+ if (m_background->rect().size().toSize() == size)
+ return;
+ m_background->setRect(0.0f, 0.0f, size.width(), size.height());
+ renderableNode(m_background)->markGeometryDirty();
+ // Invalidate the whole scene when the background is resized
+ m_dirtyRegion = QRegion(m_background->rect().toRect());
+}
+
+QColor QSGAbstractSoftwareRenderer::backgroundColor()
+{
+ return m_background->color();
+}
+
+QSize QSGAbstractSoftwareRenderer::backgroundSize()
+{
+ return m_background->rect().size().toSize();
+}
+
+void QSGAbstractSoftwareRenderer::nodeAdded(QSGNode *node)
+{
+ qCDebug(lc2DRender) << "nodeAdded" << (void*)node;
+
+ m_nodeUpdater->updateNodes(node);
+}
+
+void QSGAbstractSoftwareRenderer::nodeRemoved(QSGNode *node)
+{
+ qCDebug(lc2DRender) << "nodeRemoved" << (void*)node;
+
+ auto renderable = renderableNode(node);
+ // remove mapping
+ if (renderable != nullptr) {
+ // Need to mark this region dirty in the other nodes
+ QRegion dirtyRegion = renderable->previousDirtyRegion(true);
+ if (dirtyRegion.isEmpty())
+ dirtyRegion = renderable->boundingRect();
+ m_dirtyRegion += dirtyRegion;
+ m_nodes.remove(node);
+ delete renderable;
+ }
+
+ // Remove all children nodes as well
+ for (QSGNode *child = node->firstChild(); child; child = child->nextSibling()) {
+ nodeRemoved(child);
+ }
+
+ m_nodeUpdater->updateNodes(node, true);
+}
+
+void QSGAbstractSoftwareRenderer::nodeGeometryUpdated(QSGNode *node)
+{
+ qCDebug(lc2DRender) << "nodeGeometryUpdated";
+
+ // Mark node as dirty
+ auto renderable = renderableNode(node);
+ if (renderable != nullptr) {
+ renderable->markGeometryDirty();
+ } else {
+ m_nodeUpdater->updateNodes(node);
+ }
+}
+
+void QSGAbstractSoftwareRenderer::nodeMaterialUpdated(QSGNode *node)
+{
+ qCDebug(lc2DRender) << "nodeMaterialUpdated";
+
+ // Mark node as dirty
+ auto renderable = renderableNode(node);
+ if (renderable != nullptr) {
+ renderable->markMaterialDirty();
+ } else {
+ m_nodeUpdater->updateNodes(node);
+ }
+}
+
+void QSGAbstractSoftwareRenderer::nodeMatrixUpdated(QSGNode *node)
+{
+ qCDebug(lc2DRender) << "nodeMaterialUpdated";
+
+ // Update children nodes
+ m_nodeUpdater->updateNodes(node);
+}
+
+void QSGAbstractSoftwareRenderer::nodeOpacityUpdated(QSGNode *node)
+{
+ qCDebug(lc2DRender) << "nodeOpacityUpdated";
+
+ // Update children nodes
+ m_nodeUpdater->updateNodes(node);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h
new file mode 100644
index 0000000000..a2e953f40d
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGABSTRACTSOFTWARERENDERER_H
+#define QSGABSTRACTSOFTWARERENDERER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgrenderer_p.h>
+
+#include <QtCore/QHash>
+#include <QtCore/QLinkedList>
+
+QT_BEGIN_NAMESPACE
+
+class QSGSimpleRectNode;
+
+class QSGSoftwareRenderableNode;
+class QSGSoftwareRenderableNodeUpdater;
+
+class QSGAbstractSoftwareRenderer : public QSGRenderer
+{
+public:
+ QSGAbstractSoftwareRenderer(QSGRenderContext *context);
+ virtual ~QSGAbstractSoftwareRenderer();
+
+ QSGSoftwareRenderableNode *renderableNode(QSGNode *node) const;
+ void addNodeMapping(QSGNode *node, QSGSoftwareRenderableNode *renderableNode);
+ void appendRenderableNode(QSGSoftwareRenderableNode *node);
+
+ void nodeChanged(QSGNode *node, QSGNode::DirtyState state) override;
+
+protected:
+ QRegion renderNodes(QPainter *painter);
+ void buildRenderList();
+ void optimizeRenderList();
+
+ void setBackgroundColor(const QColor &color);
+ void setBackgroundSize(const QSize &size);
+ QColor backgroundColor();
+ QSize backgroundSize();
+
+private:
+ void nodeAdded(QSGNode *node);
+ void nodeRemoved(QSGNode *node);
+ void nodeGeometryUpdated(QSGNode *node);
+ void nodeMaterialUpdated(QSGNode *node);
+ void nodeMatrixUpdated(QSGNode *node);
+ void nodeOpacityUpdated(QSGNode *node);
+
+ QHash<QSGNode*, QSGSoftwareRenderableNode*> m_nodes;
+ QLinkedList<QSGSoftwareRenderableNode*> m_renderableNodes;
+
+ QSGSimpleRectNode *m_background;
+
+ QRegion m_dirtyRegion;
+ QRegion m_obscuredRegion;
+
+ QSGSoftwareRenderableNodeUpdater *m_nodeUpdater;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGABSTRACTSOFTWARERENDERER_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp
new file mode 100644
index 0000000000..0e2f4f5382
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwareadaptation_p.h"
+#include "qsgsoftwarecontext_p.h"
+#include "qsgsoftwarerenderloop_p.h"
+
+#include <private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwareAdaptation::QSGSoftwareAdaptation(QObject *parent)
+ : QSGContextPlugin(parent)
+{
+}
+
+QStringList QSGSoftwareAdaptation::keys() const
+{
+ return QStringList() << QLatin1String("software");
+}
+
+QSGContext *QSGSoftwareAdaptation::create(const QString &) const
+{
+ if (!instance)
+ instance = new QSGSoftwareContext();
+ return instance;
+}
+
+QSGContextFactoryInterface::Flags QSGSoftwareAdaptation::flags(const QString &) const
+{
+ // Claim we support adaptable shader effects, then return null for the
+ // shader effect node. The result is shader effects not being rendered,
+ // with the application working fine in all other respects.
+ return QSGContextFactoryInterface::SupportsShaderEffectNode;
+}
+
+QSGRenderLoop *QSGSoftwareAdaptation::createWindowManager()
+{
+ return new QSGSoftwareRenderLoop();
+}
+
+QSGSoftwareContext *QSGSoftwareAdaptation::instance = 0;
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation_p.h
new file mode 100644
index 0000000000..ffe54b5d4b
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareadaptation_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PLUGINMAIN_H
+#define PLUGINMAIN_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgcontextplugin_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGContext;
+class QSGRenderLoop;
+class QSGSoftwareContext;
+
+class QSGSoftwareAdaptation : public QSGContextPlugin
+{
+public:
+ QSGSoftwareAdaptation(QObject *parent = 0);
+
+ QStringList keys() const override;
+ QSGContext *create(const QString &key) const override;
+ QSGContextFactoryInterface::Flags flags(const QString &key) const override;
+ QSGRenderLoop *createWindowManager() override;
+private:
+ static QSGSoftwareContext *instance;
+};
+
+QT_END_NAMESPACE
+
+#endif // PLUGINMAIN_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp
new file mode 100644
index 0000000000..15bc32ecb2
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwarecontext_p.h"
+
+#include "qsgsoftwarerectanglenode_p.h"
+#include "qsgsoftwareimagenode_p.h"
+#include "qsgsoftwarepainternode_p.h"
+#include "qsgsoftwarepixmaptexture_p.h"
+#include "qsgsoftwareglyphnode_p.h"
+#include "qsgsoftwareninepatchnode_p.h"
+#include "qsgsoftwarelayer_p.h"
+#include "qsgsoftwarerenderer_p.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QElapsedTimer>
+
+#include <QtGui/QWindow>
+
+#include <QtQuick/QSGFlatColorMaterial>
+#include <QtQuick/QSGVertexColorMaterial>
+#include <QtQuick/QSGOpaqueTextureMaterial>
+#include <QtQuick/QSGTextureMaterial>
+
+// Used for very high-level info about the renderering and gl context
+// Includes GL_VERSION, type of render loop, atlas size, etc.
+Q_LOGGING_CATEGORY(QSG_RASTER_LOG_INFO, "qt.scenegraph.info")
+
+// Used to debug the renderloop logic. Primarily useful for platform integrators
+// and when investigating the render loop logic.
+Q_LOGGING_CATEGORY(QSG_RASTER_LOG_RENDERLOOP, "qt.scenegraph.renderloop")
+
+// GLSL shader compilation
+Q_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_COMPILATION, "qt.scenegraph.time.compilation")
+
+// polish, animations, sync, render and swap in the render loop
+Q_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_RENDERLOOP, "qt.scenegraph.time.renderloop")
+
+// Texture uploads and swizzling
+Q_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_TEXTURE, "qt.scenegraph.time.texture")
+
+// Glyph preparation (only for distance fields atm)
+Q_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_GLYPH, "qt.scenegraph.time.glyph")
+
+// Timing inside the renderer base class
+Q_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_RENDERER, "qt.scenegraph.time.renderer")
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwareRenderContext::QSGSoftwareRenderContext(QSGContext *ctx)
+ : QSGRenderContext(ctx)
+ , m_initialized(false)
+{
+}
+QSGSoftwareContext::QSGSoftwareContext(QObject *parent)
+ : QSGContext(parent)
+{
+}
+
+QSGRectangleNode *QSGSoftwareContext::createRectangleNode()
+{
+ return new QSGSoftwareRectangleNode();
+}
+
+QSGImageNode *QSGSoftwareContext::createImageNode()
+{
+ return new QSGSoftwareImageNode();
+}
+
+QSGPainterNode *QSGSoftwareContext::createPainterNode(QQuickPaintedItem *item)
+{
+ return new QSGSoftwarePainterNode(item);
+}
+
+QSGGlyphNode *QSGSoftwareContext::createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode)
+{
+ Q_UNUSED(rc);
+ Q_UNUSED(preferNativeGlyphNode);
+ return new QSGSoftwareGlyphNode();
+}
+
+QSGNinePatchNode *QSGSoftwareContext::createNinePatchNode()
+{
+ return new QSGSoftwareNinePatchNode();
+}
+
+QSGLayer *QSGSoftwareContext::createLayer(QSGRenderContext *renderContext)
+{
+ return new QSGSoftwareLayer(renderContext);
+}
+
+QSurfaceFormat QSGSoftwareContext::defaultSurfaceFormat() const
+{
+ QSurfaceFormat format = QSurfaceFormat::defaultFormat();
+ format.setRenderableType(QSurfaceFormat::DefaultRenderableType);
+ format.setMajorVersion(0);
+ format.setMinorVersion(0);
+ return format;
+}
+
+void QSGSoftwareRenderContext::initializeIfNeeded()
+{
+ if (m_initialized)
+ return;
+ m_initialized = true;
+ emit initialized();
+}
+
+void QSGSoftwareRenderContext::invalidate()
+{
+ QSGRenderContext::invalidate();
+}
+
+QSGTexture *QSGSoftwareRenderContext::createTexture(const QImage &image, uint flags) const
+{
+ return new QSGSoftwarePixmapTexture(image, flags);
+}
+
+QSGRenderer *QSGSoftwareRenderContext::createRenderer()
+{
+ return new QSGSoftwareRenderer(this);
+}
+
+
+void QSGSoftwareRenderContext::renderNextFrame(QSGRenderer *renderer, uint fbo)
+{
+ renderer->renderScene(fbo);
+}
+
+QSGRendererInterface *QSGSoftwareContext::rendererInterface(QSGRenderContext *renderContext)
+{
+ Q_UNUSED(renderContext);
+ return this;
+}
+
+QSGRendererInterface::GraphicsApi QSGSoftwareContext::graphicsApi() const
+{
+ return Software;
+}
+
+QSGRendererInterface::ShaderType QSGSoftwareContext::shaderType() const
+{
+ return UnknownShadingLanguage;
+}
+
+QSGRendererInterface::ShaderCompilationTypes QSGSoftwareContext::shaderCompilationType() const
+{
+ return 0;
+}
+
+QSGRendererInterface::ShaderSourceTypes QSGSoftwareContext::shaderSourceType() const
+{
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h
new file mode 100644
index 0000000000..992f6f5677
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWARECONTEXT_H
+#define QSGSOFTWARECONTEXT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include "qsgrendererinterface.h"
+
+Q_DECLARE_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_RENDERLOOP)
+Q_DECLARE_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_COMPILATION)
+Q_DECLARE_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_TEXTURE)
+Q_DECLARE_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_GLYPH)
+Q_DECLARE_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_RENDERER)
+Q_DECLARE_LOGGING_CATEGORY(QSG_RASTER_LOG_INFO)
+Q_DECLARE_LOGGING_CATEGORY(QSG_RASTER_LOG_RENDERLOOP)
+
+QT_BEGIN_NAMESPACE
+
+class QSGSoftwareRenderContext : public QSGRenderContext
+{
+ Q_OBJECT
+public:
+ QSGSoftwareRenderContext(QSGContext *ctx);
+ void initializeIfNeeded();
+ void invalidate() override;
+ void renderNextFrame(QSGRenderer *renderer, uint fbo) override;
+ QSGTexture *createTexture(const QImage &image, uint flags = CreateTexture_Alpha) const override;
+ QSGRenderer *createRenderer() override;
+
+ bool m_initialized;
+};
+
+class QSGSoftwareContext : public QSGContext, public QSGRendererInterface
+{
+ Q_OBJECT
+public:
+ explicit QSGSoftwareContext(QObject *parent = nullptr);
+
+ QSGRenderContext *createRenderContext() override { return new QSGSoftwareRenderContext(this); }
+ QSGRectangleNode *createRectangleNode() override;
+ QSGImageNode *createImageNode() override;
+ QSGPainterNode *createPainterNode(QQuickPaintedItem *item) override;
+ QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) override;
+ QSGNinePatchNode *createNinePatchNode() override;
+ QSGLayer *createLayer(QSGRenderContext *renderContext) override;
+ QSurfaceFormat defaultSurfaceFormat() const override;
+ QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override;
+
+ GraphicsApi graphicsApi() const override;
+ ShaderType shaderType() const override;
+ ShaderCompilationTypes shaderCompilationType() const override;
+ ShaderSourceTypes shaderSourceType() const override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWARECONTEXT_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareglyphnode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareglyphnode.cpp
new file mode 100644
index 0000000000..21f20c66cd
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareglyphnode.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwareglyphnode_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwareGlyphNode::QSGSoftwareGlyphNode()
+ : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
+ , m_style(QQuickText::Normal)
+{
+ setMaterial((QSGMaterial*)1);
+ setGeometry(&m_geometry);
+}
+
+
+void QSGSoftwareGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
+{
+ m_position = position;
+ m_glyphRun = glyphs;
+ m_bounding_rect = glyphs.boundingRect().translated(m_position - QPointF(0.0, glyphs.rawFont().ascent()));
+}
+
+void QSGSoftwareGlyphNode::setColor(const QColor &color)
+{
+ m_color = color;
+}
+
+void QSGSoftwareGlyphNode::setStyle(QQuickText::TextStyle style)
+{
+ m_style = style;
+}
+
+void QSGSoftwareGlyphNode::setStyleColor(const QColor &color)
+{
+ m_styleColor = color;
+}
+
+QPointF QSGSoftwareGlyphNode::baseLine() const
+{
+ return QPointF();
+}
+
+void QSGSoftwareGlyphNode::setPreferredAntialiasingMode(QSGGlyphNode::AntialiasingMode)
+{
+}
+
+void QSGSoftwareGlyphNode::update()
+{
+}
+
+void QSGSoftwareGlyphNode::paint(QPainter *painter)
+{
+ painter->setBrush(QBrush());
+ QPointF pos = m_position - QPointF(0, m_glyphRun.rawFont().ascent());
+
+ qreal offset = 1.0;
+ if (painter->device()->devicePixelRatio() != 0)
+ offset = 1.0 / painter->device()->devicePixelRatio();
+
+ switch (m_style) {
+ case QQuickText::Normal: break;
+ case QQuickText::Outline:
+ painter->setPen(m_styleColor);
+ painter->drawGlyphRun(pos + QPointF(0, offset), m_glyphRun);
+ painter->drawGlyphRun(pos + QPointF(0, -offset), m_glyphRun);
+ painter->drawGlyphRun(pos + QPointF(offset, 0), m_glyphRun);
+ painter->drawGlyphRun(pos + QPointF(-offset, 0), m_glyphRun);
+ break;
+ case QQuickText::Raised:
+ painter->setPen(m_styleColor);
+ painter->drawGlyphRun(pos + QPointF(0, offset), m_glyphRun);
+ break;
+ case QQuickText::Sunken:
+ painter->setPen(m_styleColor);
+ painter->drawGlyphRun(pos + QPointF(0, -offset), m_glyphRun);
+ break;
+ }
+
+ painter->setPen(m_color);
+ painter->drawGlyphRun(pos, m_glyphRun);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareglyphnode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareglyphnode_p.h
new file mode 100644
index 0000000000..559b156bf3
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareglyphnode_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWAREGLYPHNODE_H
+#define QSGSOFTWAREGLYPHNODE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgadaptationlayer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGSoftwareGlyphNode : public QSGGlyphNode
+{
+public:
+ QSGSoftwareGlyphNode();
+
+ void setGlyphs(const QPointF &position, const QGlyphRun &glyphs) override;
+ void setColor(const QColor &color) override;
+ void setStyle(QQuickText::TextStyle style) override;
+ void setStyleColor(const QColor &color) override;
+ QPointF baseLine() const override;
+ void setPreferredAntialiasingMode(AntialiasingMode) override;
+ void update() override;
+
+ void paint(QPainter *painter);
+
+private:
+ QPointF m_position;
+ QGlyphRun m_glyphRun;
+ QColor m_color;
+ QSGGeometry m_geometry;
+ QQuickText::TextStyle m_style;
+ QColor m_styleColor;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWAREGLYPHNODE_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode.cpp
new file mode 100644
index 0000000000..c92a032623
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode.cpp
@@ -0,0 +1,501 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwareimagenode_p.h"
+
+#include "qsgsoftwarepixmaptexture_p.h"
+#include "qsgsoftwarelayer_p.h"
+#include <QPainter>
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QSGSoftwareHelpers {
+// Helper from widgets/styles/qdrawutil.cpp
+
+static inline QMargins normalizedMargins(const QMargins &m)
+{
+ return QMargins(qMax(m.left(), 0), qMax(m.top(), 0), qMax(m.right(), 0), qMax(m.bottom(), 0));
+}
+
+void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargins &targetMarginsIn,
+ const QPixmap &pixmap, const QRect &sourceRect, const QMargins &sourceMarginsIn,
+ const QTileRules &rules, QDrawBorderPixmap::DrawingHints hints)
+{
+ QPainter::PixmapFragment d;
+ d.opacity = 1.0;
+ d.rotation = 0.0;
+
+ QPixmapFragmentsArray opaqueData;
+ QPixmapFragmentsArray translucentData;
+
+ QMargins sourceMargins = normalizedMargins(sourceMarginsIn);
+ QMargins targetMargins = normalizedMargins(targetMarginsIn);
+
+ // source center
+ const int sourceCenterTop = sourceRect.top() + sourceMargins.top();
+ const int sourceCenterLeft = sourceRect.left() + sourceMargins.left();
+ const int sourceCenterBottom = sourceRect.bottom() - sourceMargins.bottom() + 1;
+ const int sourceCenterRight = sourceRect.right() - sourceMargins.right() + 1;
+ const int sourceCenterWidth = sourceCenterRight - sourceCenterLeft;
+ const int sourceCenterHeight = sourceCenterBottom - sourceCenterTop;
+ // target center
+ const int targetCenterTop = targetRect.top() + targetMargins.top();
+ const int targetCenterLeft = targetRect.left() + targetMargins.left();
+ const int targetCenterBottom = targetRect.bottom() - targetMargins.bottom() + 1;
+ const int targetCenterRight = targetRect.right() - targetMargins.right() + 1;
+ const int targetCenterWidth = targetCenterRight - targetCenterLeft;
+ const int targetCenterHeight = targetCenterBottom - targetCenterTop;
+
+ QVarLengthArray<qreal, 16> xTarget; // x-coordinates of target rectangles
+ QVarLengthArray<qreal, 16> yTarget; // y-coordinates of target rectangles
+
+ int columns = 3;
+ int rows = 3;
+ if (rules.horizontal != Qt::StretchTile && sourceCenterWidth != 0)
+ columns = qMax(3, 2 + qCeil(targetCenterWidth / qreal(sourceCenterWidth)));
+ if (rules.vertical != Qt::StretchTile && sourceCenterHeight != 0)
+ rows = qMax(3, 2 + qCeil(targetCenterHeight / qreal(sourceCenterHeight)));
+
+ xTarget.resize(columns + 1);
+ yTarget.resize(rows + 1);
+
+ bool oldAA = painter->testRenderHint(QPainter::Antialiasing);
+ if (painter->paintEngine()->type() != QPaintEngine::OpenGL
+ && painter->paintEngine()->type() != QPaintEngine::OpenGL2
+ && oldAA && painter->combinedTransform().type() != QTransform::TxNone) {
+ painter->setRenderHint(QPainter::Antialiasing, false);
+ }
+
+ xTarget[0] = targetRect.left();
+ xTarget[1] = targetCenterLeft;
+ xTarget[columns - 1] = targetCenterRight;
+ xTarget[columns] = targetRect.left() + targetRect.width();
+
+ yTarget[0] = targetRect.top();
+ yTarget[1] = targetCenterTop;
+ yTarget[rows - 1] = targetCenterBottom;
+ yTarget[rows] = targetRect.top() + targetRect.height();
+
+ qreal dx = targetCenterWidth;
+ qreal dy = targetCenterHeight;
+
+ switch (rules.horizontal) {
+ case Qt::StretchTile:
+ dx = targetCenterWidth;
+ break;
+ case Qt::RepeatTile:
+ dx = sourceCenterWidth;
+ break;
+ case Qt::RoundTile:
+ dx = targetCenterWidth / qreal(columns - 2);
+ break;
+ }
+
+ for (int i = 2; i < columns - 1; ++i)
+ xTarget[i] = xTarget[i - 1] + dx;
+
+ switch (rules.vertical) {
+ case Qt::StretchTile:
+ dy = targetCenterHeight;
+ break;
+ case Qt::RepeatTile:
+ dy = sourceCenterHeight;
+ break;
+ case Qt::RoundTile:
+ dy = targetCenterHeight / qreal(rows - 2);
+ break;
+ }
+
+ for (int i = 2; i < rows - 1; ++i)
+ yTarget[i] = yTarget[i - 1] + dy;
+
+ // corners
+ if (targetMargins.top() > 0 && targetMargins.left() > 0 && sourceMargins.top() > 0 && sourceMargins.left() > 0) { // top left
+ d.x = (0.5 * (xTarget[1] + xTarget[0]));
+ d.y = (0.5 * (yTarget[1] + yTarget[0]));
+ d.sourceLeft = sourceRect.left();
+ d.sourceTop = sourceRect.top();
+ d.width = sourceMargins.left();
+ d.height = sourceMargins.top();
+ d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
+ d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
+ if (hints & QDrawBorderPixmap::OpaqueTopLeft)
+ opaqueData.append(d);
+ else
+ translucentData.append(d);
+ }
+ if (targetMargins.top() > 0 && targetMargins.right() > 0 && sourceMargins.top() > 0 && sourceMargins.right() > 0) { // top right
+ d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
+ d.y = (0.5 * (yTarget[1] + yTarget[0]));
+ d.sourceLeft = sourceCenterRight;
+ d.sourceTop = sourceRect.top();
+ d.width = sourceMargins.right();
+ d.height = sourceMargins.top();
+ d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
+ d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
+ if (hints & QDrawBorderPixmap::OpaqueTopRight)
+ opaqueData.append(d);
+ else
+ translucentData.append(d);
+ }
+ if (targetMargins.bottom() > 0 && targetMargins.left() > 0 && sourceMargins.bottom() > 0 && sourceMargins.left() > 0) { // bottom left
+ d.x = (0.5 * (xTarget[1] + xTarget[0]));
+ d.y =(0.5 * (yTarget[rows] + yTarget[rows - 1]));
+ d.sourceLeft = sourceRect.left();
+ d.sourceTop = sourceCenterBottom;
+ d.width = sourceMargins.left();
+ d.height = sourceMargins.bottom();
+ d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
+ d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
+ if (hints & QDrawBorderPixmap::OpaqueBottomLeft)
+ opaqueData.append(d);
+ else
+ translucentData.append(d);
+ }
+ if (targetMargins.bottom() > 0 && targetMargins.right() > 0 && sourceMargins.bottom() > 0 && sourceMargins.right() > 0) { // bottom right
+ d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
+ d.y = (0.5 * (yTarget[rows] + yTarget[rows - 1]));
+ d.sourceLeft = sourceCenterRight;
+ d.sourceTop = sourceCenterBottom;
+ d.width = sourceMargins.right();
+ d.height = sourceMargins.bottom();
+ d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
+ d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
+ if (hints & QDrawBorderPixmap::OpaqueBottomRight)
+ opaqueData.append(d);
+ else
+ translucentData.append(d);
+ }
+
+ // horizontal edges
+ if (targetCenterWidth > 0 && sourceCenterWidth > 0) {
+ if (targetMargins.top() > 0 && sourceMargins.top() > 0) { // top
+ QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueTop ? opaqueData : translucentData;
+ d.sourceLeft = sourceCenterLeft;
+ d.sourceTop = sourceRect.top();
+ d.width = sourceCenterWidth;
+ d.height = sourceMargins.top();
+ d.y = (0.5 * (yTarget[1] + yTarget[0]));
+ d.scaleX = dx / d.width;
+ d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
+ for (int i = 1; i < columns - 1; ++i) {
+ d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
+ data.append(d);
+ }
+ if (rules.horizontal == Qt::RepeatTile)
+ data[data.size() - 1].width = ((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX);
+ }
+ if (targetMargins.bottom() > 0 && sourceMargins.bottom() > 0) { // bottom
+ QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueBottom ? opaqueData : translucentData;
+ d.sourceLeft = sourceCenterLeft;
+ d.sourceTop = sourceCenterBottom;
+ d.width = sourceCenterWidth;
+ d.height = sourceMargins.bottom();
+ d.y = (0.5 * (yTarget[rows] + yTarget[rows - 1]));
+ d.scaleX = dx / d.width;
+ d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
+ for (int i = 1; i < columns - 1; ++i) {
+ d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
+ data.append(d);
+ }
+ if (rules.horizontal == Qt::RepeatTile)
+ data[data.size() - 1].width = ((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX);
+ }
+ }
+
+ // vertical edges
+ if (targetCenterHeight > 0 && sourceCenterHeight > 0) {
+ if (targetMargins.left() > 0 && sourceMargins.left() > 0) { // left
+ QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueLeft ? opaqueData : translucentData;
+ d.sourceLeft = sourceRect.left();
+ d.sourceTop = sourceCenterTop;
+ d.width = sourceMargins.left();
+ d.height = sourceCenterHeight;
+ d.x = (0.5 * (xTarget[1] + xTarget[0]));
+ d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
+ d.scaleY = dy / d.height;
+ for (int i = 1; i < rows - 1; ++i) {
+ d.y = (0.5 * (yTarget[i + 1] + yTarget[i]));
+ data.append(d);
+ }
+ if (rules.vertical == Qt::RepeatTile)
+ data[data.size() - 1].height = ((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY);
+ }
+ if (targetMargins.right() > 0 && sourceMargins.right() > 0) { // right
+ QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueRight ? opaqueData : translucentData;
+ d.sourceLeft = sourceCenterRight;
+ d.sourceTop = sourceCenterTop;
+ d.width = sourceMargins.right();
+ d.height = sourceCenterHeight;
+ d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
+ d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
+ d.scaleY = dy / d.height;
+ for (int i = 1; i < rows - 1; ++i) {
+ d.y = (0.5 * (yTarget[i + 1] + yTarget[i]));
+ data.append(d);
+ }
+ if (rules.vertical == Qt::RepeatTile)
+ data[data.size() - 1].height = ((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY);
+ }
+ }
+
+ // center
+ if (targetCenterWidth > 0 && targetCenterHeight > 0 && sourceCenterWidth > 0 && sourceCenterHeight > 0) {
+ QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueCenter ? opaqueData : translucentData;
+ d.sourceLeft = sourceCenterLeft;
+ d.sourceTop = sourceCenterTop;
+ d.width = sourceCenterWidth;
+ d.height = sourceCenterHeight;
+ d.scaleX = dx / d.width;
+ d.scaleY = dy / d.height;
+
+ qreal repeatWidth = (xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX;
+ qreal repeatHeight = (yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY;
+
+ for (int j = 1; j < rows - 1; ++j) {
+ d.y = (0.5 * (yTarget[j + 1] + yTarget[j]));
+ for (int i = 1; i < columns - 1; ++i) {
+ d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
+ data.append(d);
+ }
+ if (rules.horizontal == Qt::RepeatTile)
+ data[data.size() - 1].width = repeatWidth;
+ }
+ if (rules.vertical == Qt::RepeatTile) {
+ for (int i = 1; i < columns - 1; ++i)
+ data[data.size() - i].height = repeatHeight;
+ }
+ }
+
+ if (opaqueData.size())
+ painter->drawPixmapFragments(opaqueData.data(), opaqueData.size(), pixmap, QPainter::OpaqueHint);
+ if (translucentData.size())
+ painter->drawPixmapFragments(translucentData.data(), translucentData.size(), pixmap);
+
+ if (oldAA)
+ painter->setRenderHint(QPainter::Antialiasing, true);
+}
+
+} // QSGSoftwareHelpers namespace
+
+QSGSoftwareImageNode::QSGSoftwareImageNode()
+ : m_innerSourceRect(0, 0, 1, 1)
+ , m_subSourceRect(0, 0, 1, 1)
+ , m_texture(0)
+ , m_mirror(false)
+ , m_smooth(true)
+ , m_tileHorizontal(false)
+ , m_tileVertical(false)
+ , m_cachedMirroredPixmapIsDirty(false)
+{
+ setMaterial((QSGMaterial*)1);
+ setGeometry((QSGGeometry*)1);
+}
+
+
+void QSGSoftwareImageNode::setTargetRect(const QRectF &rect)
+{
+ if (rect == m_targetRect)
+ return;
+ m_targetRect = rect;
+ markDirty(DirtyGeometry);
+}
+
+void QSGSoftwareImageNode::setInnerTargetRect(const QRectF &rect)
+{
+ if (rect == m_innerTargetRect)
+ return;
+ m_innerTargetRect = rect;
+ markDirty(DirtyGeometry);
+}
+
+void QSGSoftwareImageNode::setInnerSourceRect(const QRectF &rect)
+{
+ if (rect == m_innerSourceRect)
+ return;
+ m_innerSourceRect = rect;
+ markDirty(DirtyGeometry);
+}
+
+void QSGSoftwareImageNode::setSubSourceRect(const QRectF &rect)
+{
+ if (rect == m_subSourceRect)
+ return;
+ m_subSourceRect = rect;
+ markDirty(DirtyGeometry);
+}
+
+void QSGSoftwareImageNode::setTexture(QSGTexture *texture)
+{
+ m_texture = texture;
+ m_cachedMirroredPixmapIsDirty = true;
+ markDirty(DirtyMaterial);
+}
+
+void QSGSoftwareImageNode::setMirror(bool mirror)
+{
+ if (m_mirror != mirror) {
+ m_mirror = mirror;
+ m_cachedMirroredPixmapIsDirty = true;
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGSoftwareImageNode::setMipmapFiltering(QSGTexture::Filtering /*filtering*/)
+{
+}
+
+void QSGSoftwareImageNode::setFiltering(QSGTexture::Filtering filtering)
+{
+ bool smooth = (filtering == QSGTexture::Linear);
+ if (smooth == m_smooth)
+ return;
+
+ m_smooth = smooth;
+ markDirty(DirtyMaterial);
+}
+
+void QSGSoftwareImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
+{
+ bool tileHorizontal = (wrapMode == QSGTexture::Repeat);
+ if (tileHorizontal == m_tileHorizontal)
+ return;
+
+ m_tileHorizontal = tileHorizontal;
+ markDirty(DirtyMaterial);
+}
+
+void QSGSoftwareImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
+{
+ bool tileVertical = (wrapMode == QSGTexture::Repeat);
+ if (tileVertical == m_tileVertical)
+ return;
+
+ m_tileVertical = (wrapMode == QSGTexture::Repeat);
+ markDirty(DirtyMaterial);
+}
+
+void QSGSoftwareImageNode::update()
+{
+ if (m_cachedMirroredPixmapIsDirty) {
+ if (m_mirror) {
+ m_cachedMirroredPixmap = pixmap().transformed(QTransform(-1, 0, 0, 1, 0, 0));
+ } else {
+ //Cleanup cached pixmap if necessary
+ if (!m_cachedMirroredPixmap.isNull())
+ m_cachedMirroredPixmap = QPixmap();
+ }
+ m_cachedMirroredPixmapIsDirty = false;
+ }
+}
+
+void QSGSoftwareImageNode::preprocess()
+{
+ bool doDirty = false;
+ QSGLayer *t = qobject_cast<QSGLayer *>(m_texture);
+ if (t) {
+ doDirty = t->updateTexture();
+ markDirty(DirtyGeometry);
+ }
+ if (doDirty)
+ markDirty(DirtyMaterial);
+}
+
+static Qt::TileRule getTileRule(qreal factor)
+{
+ int ifactor = qRound(factor);
+ if (qFuzzyCompare(factor, ifactor )) {
+ if (ifactor == 1 || ifactor == 0)
+ return Qt::StretchTile;
+ return Qt::RoundTile;
+ }
+ return Qt::RepeatTile;
+}
+
+
+void QSGSoftwareImageNode::paint(QPainter *painter)
+{
+ painter->setRenderHint(QPainter::SmoothPixmapTransform, m_smooth);
+
+ const QPixmap &pm = m_mirror ? m_cachedMirroredPixmap : pixmap();
+
+ if (m_innerTargetRect != m_targetRect) {
+ // border image
+ QMargins margins(m_innerTargetRect.left() - m_targetRect.left(), m_innerTargetRect.top() - m_targetRect.top(),
+ m_targetRect.right() - m_innerTargetRect.right(), m_targetRect.bottom() - m_innerTargetRect.bottom());
+ QSGSoftwareHelpers::QTileRules tilerules(getTileRule(m_subSourceRect.width()), getTileRule(m_subSourceRect.height()));
+ QSGSoftwareHelpers::qDrawBorderPixmap(painter, m_targetRect.toRect(), margins, pm, QRect(0, 0, pm.width(), pm.height()),
+ margins, tilerules, QSGSoftwareHelpers::QDrawBorderPixmap::DrawingHints(0));
+ return;
+ }
+
+ if (m_tileHorizontal || m_tileVertical) {
+ painter->save();
+ qreal sx = m_targetRect.width()/(m_subSourceRect.width()*pm.width());
+ qreal sy = m_targetRect.height()/(m_subSourceRect.height()*pm.height());
+ QMatrix transform(sx, 0, 0, sy, 0, 0);
+ painter->setMatrix(transform, true);
+ painter->drawTiledPixmap(QRectF(m_targetRect.x()/sx, m_targetRect.y()/sy, m_targetRect.width()/sx, m_targetRect.height()/sy),
+ pm,
+ QPointF(m_subSourceRect.left()*pm.width(), m_subSourceRect.top()*pm.height()));
+ painter->restore();
+ } else {
+ QRectF sr(m_subSourceRect.left()*pm.width(), m_subSourceRect.top()*pm.height(),
+ m_subSourceRect.width()*pm.width(), m_subSourceRect.height()*pm.height());
+ painter->drawPixmap(m_targetRect, pm, sr);
+ }
+}
+
+QRectF QSGSoftwareImageNode::rect() const
+{
+ return m_targetRect;
+}
+
+const QPixmap &QSGSoftwareImageNode::pixmap() const
+{
+ if (QSGSoftwarePixmapTexture *pt = qobject_cast<QSGSoftwarePixmapTexture*>(m_texture)) {
+ return pt->pixmap();
+ } else {
+ QSGSoftwareLayer *layer = qobject_cast<QSGSoftwareLayer*>(m_texture);
+ return layer->pixmap();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode_p.h
new file mode 100644
index 0000000000..e42f616757
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareimagenode_p.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWAREIMAGENODE_H
+#define QSGSOFTWAREIMAGENODE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgtexturematerial_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QSGSoftwareHelpers {
+
+typedef QVarLengthArray<QPainter::PixmapFragment, 16> QPixmapFragmentsArray;
+
+struct QTileRules
+{
+ inline QTileRules(Qt::TileRule horizontalRule, Qt::TileRule verticalRule)
+ : horizontal(horizontalRule), vertical(verticalRule) {}
+ inline QTileRules(Qt::TileRule rule = Qt::StretchTile)
+ : horizontal(rule), vertical(rule) {}
+ Qt::TileRule horizontal;
+ Qt::TileRule vertical;
+};
+
+#ifndef Q_QDOC
+// For internal use only.
+namespace QDrawBorderPixmap
+{
+ enum DrawingHint
+ {
+ OpaqueTopLeft = 0x0001,
+ OpaqueTop = 0x0002,
+ OpaqueTopRight = 0x0004,
+ OpaqueLeft = 0x0008,
+ OpaqueCenter = 0x0010,
+ OpaqueRight = 0x0020,
+ OpaqueBottomLeft = 0x0040,
+ OpaqueBottom = 0x0080,
+ OpaqueBottomRight = 0x0100,
+ OpaqueCorners = OpaqueTopLeft | OpaqueTopRight | OpaqueBottomLeft | OpaqueBottomRight,
+ OpaqueEdges = OpaqueTop | OpaqueLeft | OpaqueRight | OpaqueBottom,
+ OpaqueFrame = OpaqueCorners | OpaqueEdges,
+ OpaqueAll = OpaqueCenter | OpaqueFrame
+ };
+
+ Q_DECLARE_FLAGS(DrawingHints, DrawingHint)
+}
+#endif
+
+void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargins &targetMargins,
+ const QPixmap &pixmap, const QRect &sourceRect,const QMargins &sourceMargins,
+ const QTileRules &rules, QDrawBorderPixmap::DrawingHints hints);
+
+} // QSGSoftwareHelpers namespace
+
+class QSGSoftwareImageNode : public QSGImageNode
+{
+public:
+ QSGSoftwareImageNode();
+
+ void setTargetRect(const QRectF &rect) override;
+ void setInnerTargetRect(const QRectF &rect) override;
+ void setInnerSourceRect(const QRectF &rect) override;
+ void setSubSourceRect(const QRectF &rect) override;
+ void setTexture(QSGTexture *texture) override;
+ void setMirror(bool mirror) override;
+ void setMipmapFiltering(QSGTexture::Filtering filtering) override;
+ void setFiltering(QSGTexture::Filtering filtering) override;
+ void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) override;
+ void setVerticalWrapMode(QSGTexture::WrapMode wrapMode) override;
+ void update() override;
+
+ void preprocess() override;
+
+ void paint(QPainter *painter);
+
+ QRectF rect() const;
+
+private:
+ const QPixmap &pixmap() const;
+
+ QRectF m_targetRect;
+ QRectF m_innerTargetRect;
+ QRectF m_innerSourceRect;
+ QRectF m_subSourceRect;
+
+ QSGTexture *m_texture;
+ QPixmap m_cachedMirroredPixmap;
+
+ bool m_mirror;
+ bool m_smooth;
+ bool m_tileHorizontal;
+ bool m_tileVertical;
+ bool m_cachedMirroredPixmapIsDirty;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWAREIMAGENODE_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp
new file mode 100644
index 0000000000..7020283898
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp
@@ -0,0 +1,261 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwarelayer_p.h"
+
+#include "qsgsoftwarecontext_p.h"
+#include "qsgsoftwarepixmaprenderer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwareLayer::QSGSoftwareLayer(QSGRenderContext *renderContext)
+ : m_item(0)
+ , m_context(renderContext)
+ , m_renderer(0)
+ , m_device_pixel_ratio(1)
+ , m_mirrorHorizontal(false)
+ , m_mirrorVertical(false)
+ , m_live(true)
+ , m_grab(true)
+ , m_recursive(false)
+ , m_dirtyTexture(true)
+{
+
+}
+
+QSGSoftwareLayer::~QSGSoftwareLayer()
+{
+ invalidated();
+}
+
+int QSGSoftwareLayer::textureId() const
+{
+ return 0;
+}
+
+QSize QSGSoftwareLayer::textureSize() const
+{
+ return m_pixmap.size();
+}
+
+bool QSGSoftwareLayer::hasAlphaChannel() const
+{
+ return m_pixmap.hasAlphaChannel();
+}
+
+bool QSGSoftwareLayer::hasMipmaps() const
+{
+ return false;
+}
+
+void QSGSoftwareLayer::bind()
+{
+}
+
+bool QSGSoftwareLayer::updateTexture()
+{
+ bool doGrab = (m_live || m_grab) && m_dirtyTexture;
+ if (doGrab)
+ grab();
+ if (m_grab)
+ emit scheduledUpdateCompleted();
+ m_grab = false;
+ return doGrab;
+}
+
+void QSGSoftwareLayer::setItem(QSGNode *item)
+{
+ if (item == m_item)
+ return;
+ m_item = item;
+
+ if (m_live && !m_item)
+ m_pixmap = QPixmap();
+
+ markDirtyTexture();
+}
+
+void QSGSoftwareLayer::setRect(const QRectF &rect)
+{
+ if (rect == m_rect)
+ return;
+ m_rect = rect;
+ markDirtyTexture();
+}
+
+void QSGSoftwareLayer::setSize(const QSize &size)
+{
+ if (size == m_size)
+ return;
+ m_size = size;
+
+ if (m_live && m_size.isNull())
+ m_pixmap = QPixmap();
+
+ markDirtyTexture();
+}
+
+void QSGSoftwareLayer::scheduleUpdate()
+{
+ if (m_grab)
+ return;
+ m_grab = true;
+ if (m_dirtyTexture) {
+ emit updateRequested();
+ }
+}
+
+QImage QSGSoftwareLayer::toImage() const
+{
+ return m_pixmap.toImage();
+}
+
+void QSGSoftwareLayer::setLive(bool live)
+{
+ if (live == m_live)
+ return;
+ m_live = live;
+
+ if (m_live && (!m_item || m_size.isNull()))
+ m_pixmap = QPixmap();
+
+ markDirtyTexture();
+}
+
+void QSGSoftwareLayer::setRecursive(bool recursive)
+{
+ m_recursive = recursive;
+}
+
+void QSGSoftwareLayer::setFormat(uint)
+{
+}
+
+void QSGSoftwareLayer::setHasMipmaps(bool)
+{
+}
+
+void QSGSoftwareLayer::setDevicePixelRatio(qreal ratio)
+{
+ m_device_pixel_ratio = ratio;
+}
+
+void QSGSoftwareLayer::setMirrorHorizontal(bool mirror)
+{
+ if (m_mirrorHorizontal == mirror)
+ return;
+ m_mirrorHorizontal = mirror;
+ markDirtyTexture();
+}
+
+void QSGSoftwareLayer::setMirrorVertical(bool mirror)
+{
+ if (m_mirrorVertical == mirror)
+ return;
+ m_mirrorVertical = mirror;
+ markDirtyTexture();
+}
+
+void QSGSoftwareLayer::markDirtyTexture()
+{
+ m_dirtyTexture = true;
+ if (m_live || m_grab) {
+ emit updateRequested();
+ }
+}
+
+void QSGSoftwareLayer::invalidated()
+{
+ delete m_renderer;
+ m_renderer = 0;
+}
+
+void QSGSoftwareLayer::grab()
+{
+ if (!m_item || m_size.isNull()) {
+ m_pixmap = QPixmap();
+ m_dirtyTexture = false;
+ return;
+ }
+ QSGNode *root = m_item;
+ while (root->firstChild() && root->type() != QSGNode::RootNodeType)
+ root = root->firstChild();
+ if (root->type() != QSGNode::RootNodeType)
+ return;
+
+ if (!m_renderer) {
+ m_renderer = new QSGSoftwarePixmapRenderer(m_context);
+ connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture()));
+ }
+ m_renderer->setDevicePixelRatio(m_device_pixel_ratio);
+ m_renderer->setRootNode(static_cast<QSGRootNode *>(root));
+
+ if (m_pixmap.size() != m_size) {
+ m_pixmap = QPixmap(m_size);
+ m_pixmap.setDevicePixelRatio(m_device_pixel_ratio);
+ // This fill here is wasteful, but necessary because it is the only way
+ // to force a QImage based pixmap to have an alpha channel.
+ m_pixmap.fill(Qt::transparent);
+ }
+
+ // Render texture.
+ root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip and opacity update.
+ m_renderer->nodeChanged(root, QSGNode::DirtyForceUpdate); // Force render list update.
+
+ m_dirtyTexture = false;
+
+ m_renderer->setDeviceRect(m_size);
+ m_renderer->setViewportRect(m_size);
+ QRect mirrored(m_mirrorHorizontal ? m_rect.right() * m_device_pixel_ratio : m_rect.left() * m_device_pixel_ratio,
+ m_mirrorVertical ? m_rect.top() * m_device_pixel_ratio : m_rect.bottom() * m_device_pixel_ratio,
+ m_mirrorHorizontal ? -m_rect.width() * m_device_pixel_ratio : m_rect.width() * m_device_pixel_ratio,
+ m_mirrorVertical ? m_rect.height() * m_device_pixel_ratio : -m_rect.height() * m_device_pixel_ratio);
+ m_renderer->setProjectionRect(mirrored);
+ m_renderer->setClearColor(Qt::transparent);
+
+ m_renderer->renderScene();
+ m_renderer->render(&m_pixmap);
+
+ root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip, opacity and render list update.
+
+ if (m_recursive)
+ markDirtyTexture(); // Continuously update if 'live' and 'recursive'.
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer_p.h
new file mode 100644
index 0000000000..d3f13e40b1
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer_p.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWARELAYER_H
+#define QSGSOFTWARELAYER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGSoftwarePixmapRenderer;
+
+class QSGSoftwareLayer : public QSGLayer
+{
+ Q_OBJECT
+public:
+ QSGSoftwareLayer(QSGRenderContext *renderContext);
+ ~QSGSoftwareLayer();
+
+ const QPixmap &pixmap() const { return m_pixmap; }
+
+ // QSGTexture interface
+public:
+ int textureId() const override;
+ QSize textureSize() const override;
+ bool hasAlphaChannel() const override;
+ bool hasMipmaps() const override;
+ void bind() override;
+
+ // QSGDynamicTexture interface
+public:
+ bool updateTexture() override;
+
+ // QSGLayer interface
+public:
+ void setItem(QSGNode *item) override;
+ void setRect(const QRectF &rect) override;
+ void setSize(const QSize &size) override;
+ void scheduleUpdate() override;
+ QImage toImage() const override;
+ void setLive(bool live) override;
+ void setRecursive(bool recursive) override;
+ void setFormat(uint) override;
+ void setHasMipmaps(bool) override;
+ void setDevicePixelRatio(qreal ratio) override;
+ void setMirrorHorizontal(bool mirror) override;
+ void setMirrorVertical(bool mirror) override;
+
+public slots:
+ void markDirtyTexture() override;
+ void invalidated() override;
+
+private:
+ void grab();
+
+ QSGNode *m_item;
+ QSGRenderContext *m_context;
+ QSGSoftwarePixmapRenderer *m_renderer;
+ QRectF m_rect;
+ QSize m_size;
+ QPixmap m_pixmap;
+ qreal m_device_pixel_ratio;
+ bool m_mirrorHorizontal;
+ bool m_mirrorVertical;
+ bool m_live;
+ bool m_grab;
+ bool m_recursive;
+ bool m_dirtyTexture;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWARELAYER_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode.cpp
new file mode 100644
index 0000000000..36ff1f2229
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwareninepatchnode_p.h"
+#include "qsgsoftwarepixmaptexture_p.h"
+#include "qsgsoftwareimagenode_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwareNinePatchNode::QSGSoftwareNinePatchNode()
+{
+ setMaterial((QSGMaterial*)1);
+ setGeometry((QSGGeometry*)1);
+}
+
+void QSGSoftwareNinePatchNode::setTexture(QSGTexture *texture)
+{
+ QSGSoftwarePixmapTexture *pt = qobject_cast<QSGSoftwarePixmapTexture*>(texture);
+ if (!pt) {
+ qWarning() << "Image used with invalid texture format.";
+ return;
+ }
+ m_pixmap = pt->pixmap();
+ markDirty(DirtyMaterial);
+}
+
+void QSGSoftwareNinePatchNode::setBounds(const QRectF &bounds)
+{
+ if (m_bounds == bounds)
+ return;
+
+ m_bounds = bounds;
+ markDirty(DirtyGeometry);
+}
+
+void QSGSoftwareNinePatchNode::setDevicePixelRatio(qreal ratio)
+{
+ if (m_pixelRatio == ratio)
+ return;
+
+ m_pixelRatio = ratio;
+ markDirty(DirtyGeometry);
+}
+
+void QSGSoftwareNinePatchNode::setPadding(qreal left, qreal top, qreal right, qreal bottom)
+{
+ QMargins margins(qRound(left), qRound(top), qRound(right), qRound(bottom));
+ if (m_margins == margins)
+ return;
+
+ m_margins = QMargins(qRound(left), qRound(top), qRound(right), qRound(bottom));
+ markDirty(DirtyGeometry);
+}
+
+void QSGSoftwareNinePatchNode::update()
+{
+}
+
+void QSGSoftwareNinePatchNode::paint(QPainter *painter)
+{
+ if (m_margins.isNull())
+ painter->drawPixmap(m_bounds, m_pixmap, QRectF(0, 0, m_pixmap.width(), m_pixmap.height()));
+ else
+ QSGSoftwareHelpers::qDrawBorderPixmap(painter, m_bounds.toRect(), m_margins, m_pixmap, QRect(0, 0, m_pixmap.width(), m_pixmap.height()),
+ m_margins, Qt::StretchTile, QSGSoftwareHelpers::QDrawBorderPixmap::DrawingHints(0));
+}
+
+QRectF QSGSoftwareNinePatchNode::bounds() const
+{
+ return m_bounds;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode_p.h
new file mode 100644
index 0000000000..bc7aec1b5a
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareninepatchnode_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWARENINEPATCHNODE_H
+#define QSGSOFTWARENINEPATCHNODE_H
+
+#include <private/qsgadaptationlayer_p.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QSGSoftwareNinePatchNode : public QSGNinePatchNode
+{
+public:
+ QSGSoftwareNinePatchNode();
+
+ void setTexture(QSGTexture *texture) override;
+ void setBounds(const QRectF &bounds) override;
+ void setDevicePixelRatio(qreal ratio) override;
+ void setPadding(qreal left, qreal top, qreal right, qreal bottom) override;
+ void update() override;
+
+ void paint(QPainter *painter);
+
+ QRectF bounds() const;
+
+private:
+ QPixmap m_pixmap;
+ QRectF m_bounds;
+ qreal m_pixelRatio;
+ QMargins m_margins;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWARENINEPATCHNODE_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepainternode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepainternode.cpp
new file mode 100644
index 0000000000..34b0cd5b72
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepainternode.cpp
@@ -0,0 +1,231 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwarepainternode_p.h"
+#include "qsgsoftwarepixmaptexture_p.h"
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwarePainterNode::QSGSoftwarePainterNode(QQuickPaintedItem *item)
+ : QSGPainterNode()
+ , m_preferredRenderTarget(QQuickPaintedItem::Image)
+ , m_item(item)
+ , m_texture(0)
+ , m_dirtyContents(false)
+ , m_opaquePainting(false)
+ , m_linear_filtering(false)
+ , m_mipmapping(false)
+ , m_smoothPainting(false)
+ , m_fastFBOResizing(false)
+ , m_fillColor(Qt::transparent)
+ , m_contentsScale(1.0)
+ , m_dirtyGeometry(false)
+{
+ setMaterial((QSGMaterial*)1);
+ setGeometry((QSGGeometry*)1);
+}
+
+QSGSoftwarePainterNode::~QSGSoftwarePainterNode()
+{
+ delete m_texture;
+}
+
+void QSGSoftwarePainterNode::setPreferredRenderTarget(QQuickPaintedItem::RenderTarget target)
+{
+ if (m_preferredRenderTarget == target)
+ return;
+
+ m_preferredRenderTarget = target;
+}
+
+void QSGSoftwarePainterNode::setSize(const QSize &size)
+{
+ if (size == m_size)
+ return;
+
+ m_size = size;
+
+ m_dirtyGeometry = true;
+}
+
+void QSGSoftwarePainterNode::setDirty(const QRect &dirtyRect)
+{
+ m_dirtyContents = true;
+ m_dirtyRect = dirtyRect;
+ markDirty(DirtyMaterial);
+}
+
+void QSGSoftwarePainterNode::setOpaquePainting(bool opaque)
+{
+ if (opaque == m_opaquePainting)
+ return;
+
+ m_opaquePainting = opaque;
+}
+
+void QSGSoftwarePainterNode::setLinearFiltering(bool linearFiltering)
+{
+ if (linearFiltering == m_linear_filtering)
+ return;
+
+ m_linear_filtering = linearFiltering;
+}
+
+void QSGSoftwarePainterNode::setMipmapping(bool mipmapping)
+{
+ if (mipmapping == m_mipmapping)
+ return;
+
+ m_mipmapping = mipmapping;
+}
+
+void QSGSoftwarePainterNode::setSmoothPainting(bool s)
+{
+ if (s == m_smoothPainting)
+ return;
+
+ m_smoothPainting = s;
+}
+
+void QSGSoftwarePainterNode::setFillColor(const QColor &c)
+{
+ if (c == m_fillColor)
+ return;
+
+ m_fillColor = c;
+ markDirty(DirtyMaterial);
+}
+
+void QSGSoftwarePainterNode::setContentsScale(qreal s)
+{
+ if (s == m_contentsScale)
+ return;
+
+ m_contentsScale = s;
+ markDirty(DirtyMaterial);
+}
+
+void QSGSoftwarePainterNode::setFastFBOResizing(bool dynamic)
+{
+ m_fastFBOResizing = dynamic;
+}
+
+QImage QSGSoftwarePainterNode::toImage() const
+{
+ return m_pixmap.toImage();
+}
+
+void QSGSoftwarePainterNode::update()
+{
+ if (m_dirtyGeometry) {
+ m_pixmap = QPixmap(m_textureSize);
+ if (!m_opaquePainting)
+ m_pixmap.fill(Qt::transparent);
+
+ if (m_texture)
+ delete m_texture;
+ m_texture = new QSGSoftwarePixmapTexture(m_pixmap);
+ }
+
+ if (m_dirtyContents)
+ paint();
+
+ m_dirtyGeometry = false;
+ m_dirtyContents = false;
+}
+
+void QSGSoftwarePainterNode::paint(QPainter *painter)
+{
+ painter->drawPixmap(0, 0, m_size.width(), m_size.height(), m_pixmap);
+}
+
+void QSGSoftwarePainterNode::paint()
+{
+ QRect dirtyRect = m_dirtyRect.isNull() ? QRect(0, 0, m_size.width(), m_size.height()) : m_dirtyRect;
+
+ QPainter painter;
+
+ painter.begin(&m_pixmap);
+ if (m_smoothPainting) {
+ painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
+ }
+
+ QRect clipRect;
+
+ if (m_contentsScale == 1) {
+ qreal scaleX = m_textureSize.width() / (qreal) m_size.width();
+ qreal scaleY = m_textureSize.height() / (qreal) m_size.height();
+ painter.scale(scaleX, scaleY);
+ clipRect = dirtyRect;
+ } else {
+ painter.scale(m_contentsScale, m_contentsScale);
+
+ QRect sclip(qFloor(dirtyRect.x()/m_contentsScale),
+ qFloor(dirtyRect.y()/m_contentsScale),
+ qCeil(dirtyRect.width()/m_contentsScale+dirtyRect.x()/m_contentsScale-qFloor(dirtyRect.x()/m_contentsScale)),
+ qCeil(dirtyRect.height()/m_contentsScale+dirtyRect.y()/m_contentsScale-qFloor(dirtyRect.y()/m_contentsScale)));
+
+ clipRect = sclip;
+ }
+
+ if (!m_dirtyRect.isNull())
+ painter.setClipRect(clipRect);
+
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ painter.fillRect(clipRect, m_fillColor);
+ painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+
+ m_item->paint(&painter);
+ painter.end();
+
+ m_dirtyRect = QRect();
+}
+
+
+void QSGSoftwarePainterNode::setTextureSize(const QSize &size)
+{
+ if (size == m_textureSize)
+ return;
+
+ m_textureSize = size;
+ m_dirtyGeometry = true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepainternode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarepainternode_p.h
new file mode 100644
index 0000000000..67b45354a2
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepainternode_p.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWAREPAINTERNODE_H
+#define QSGSOFTWAREPAINTERNODE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgadaptationlayer_p.h>
+#include <QtQuick/qquickpainteditem.h>
+
+#include <QtGui/QPixmap>
+
+QT_BEGIN_NAMESPACE
+
+class QSGSoftwarePainterNode : public QSGPainterNode
+{
+public:
+ QSGSoftwarePainterNode(QQuickPaintedItem *item);
+ ~QSGSoftwarePainterNode();
+
+ void setPreferredRenderTarget(QQuickPaintedItem::RenderTarget target) override;
+
+ void setSize(const QSize &size) override;
+ QSize size() const { return m_size; }
+
+ void setDirty(const QRect &dirtyRect = QRect()) override;
+
+ void setOpaquePainting(bool opaque) override;
+ bool opaquePainting() const { return m_opaquePainting; }
+
+ void setLinearFiltering(bool linearFiltering) override;
+ bool linearFiltering() const { return m_linear_filtering; }
+
+ void setMipmapping(bool mipmapping) override;
+ bool mipmapping() const { return m_mipmapping; }
+
+ void setSmoothPainting(bool s) override;
+ bool smoothPainting() const { return m_smoothPainting; }
+
+ void setFillColor(const QColor &c) override;
+ QColor fillColor() const { return m_fillColor; }
+
+ void setContentsScale(qreal s) override;
+ qreal contentsScale() const { return m_contentsScale; }
+
+ void setFastFBOResizing(bool dynamic) override;
+ bool fastFBOResizing() const { return m_fastFBOResizing; }
+
+ QImage toImage() const override;
+ void update() override;
+ QSGTexture *texture() const override { return m_texture; }
+
+ void paint(QPainter *painter);
+
+ void paint();
+
+ void setTextureSize(const QSize &size) override;
+ QSize textureSize() const { return m_textureSize; }
+
+private:
+
+ QQuickPaintedItem::RenderTarget m_preferredRenderTarget;
+
+ QQuickPaintedItem *m_item;
+
+ QPixmap m_pixmap;
+ QSGTexture *m_texture;
+
+ QSize m_size;
+ bool m_dirtyContents;
+ QRect m_dirtyRect;
+ bool m_opaquePainting;
+ bool m_linear_filtering;
+ bool m_mipmapping;
+ bool m_smoothPainting;
+ bool m_fastFBOResizing;
+ QColor m_fillColor;
+ qreal m_contentsScale;
+ QSize m_textureSize;
+
+ bool m_dirtyGeometry;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWAREPAINTERNODE_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
new file mode 100644
index 0000000000..304106a84d
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwarepixmaprenderer_p.h"
+
+#include <QtQuick/QSGSimpleRectNode>
+
+#include <QElapsedTimer>
+
+Q_LOGGING_CATEGORY(lcPixmapRenderer, "qt.scenegraph.softwarecontext.pixmapRenderer")
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwarePixmapRenderer::QSGSoftwarePixmapRenderer(QSGRenderContext *context)
+ : QSGAbstractSoftwareRenderer(context)
+{
+
+}
+
+QSGSoftwarePixmapRenderer::~QSGSoftwarePixmapRenderer()
+{
+
+}
+
+void QSGSoftwarePixmapRenderer::renderScene(uint)
+{
+ class B : public QSGBindable
+ {
+ public:
+ void bind() const { }
+ } bindable;
+ QSGRenderer::renderScene(bindable);
+}
+
+void QSGSoftwarePixmapRenderer::render()
+{
+
+}
+
+void QSGSoftwarePixmapRenderer::render(QPaintDevice *target)
+{
+ QElapsedTimer renderTimer;
+
+ // Setup background item
+ setBackgroundSize(QSize(target->width(), target->height()));
+ setBackgroundColor(clearColor());
+
+ QPainter painter(target);
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.setWindow(m_projectionRect);
+
+ renderTimer.start();
+ buildRenderList();
+ qint64 buildRenderListTime = renderTimer.restart();
+
+ // Optimize Renderlist
+ // Right now there is an assumption that when possible the same pixmap will
+ // be reused. So we can treat it like a backing store in that we can assume
+ // that when the pixmap is not being resized, the data can be reused. What is
+ // different though is that everything should be marked as dirty on a resize.
+ optimizeRenderList();
+ qint64 optimizeRenderListTime = renderTimer.restart();
+
+ QRegion paintedRegion = renderNodes(&painter);
+ qint64 renderTime = renderTimer.elapsed();
+
+ qCDebug(lcPixmapRenderer) << "pixmapRender" << paintedRegion << buildRenderListTime << optimizeRenderListTime << renderTime;
+}
+
+void QSGSoftwarePixmapRenderer::setProjectionRect(const QRect &projectionRect)
+{
+ m_projectionRect = projectionRect;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer_p.h
new file mode 100644
index 0000000000..3b4fb304e7
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWAREPIXMAPRENDERER_H
+#define QSGSOFTWAREPIXMAPRENDERER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qsgabstractsoftwarerenderer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGSoftwarePixmapRenderer : public QSGAbstractSoftwareRenderer
+{
+public:
+ QSGSoftwarePixmapRenderer(QSGRenderContext *context);
+ virtual ~QSGSoftwarePixmapRenderer();
+
+ void renderScene(uint fboId = 0) final;
+ void render() final;
+
+ void render(QPaintDevice *target);
+ void setProjectionRect(const QRect &projectionRect);
+
+private:
+ QRect m_projectionRect;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWAREPIXMAPRENDERER_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaptexture.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaptexture.cpp
new file mode 100644
index 0000000000..534a0a4ec6
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaptexture.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwarepixmaptexture_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwarePixmapTexture::QSGSoftwarePixmapTexture(const QImage &image, uint flags)
+{
+ // Prevent pixmap format conversion to reduce memory consumption
+ // and surprises in calling code. (See QTBUG-47328)
+ if (flags & QSGRenderContext::CreateTexture_Alpha) {
+ //If texture should have an alpha
+ m_pixmap = QPixmap::fromImage(image, Qt::NoFormatConversion);
+ } else {
+ //Force opaque texture
+ m_pixmap = QPixmap::fromImage(image.convertToFormat(QImage::Format_RGB32), Qt::NoFormatConversion);
+ }
+}
+
+QSGSoftwarePixmapTexture::QSGSoftwarePixmapTexture(const QPixmap &pixmap)
+ : m_pixmap(pixmap)
+{
+}
+
+
+int QSGSoftwarePixmapTexture::textureId() const
+{
+ return 0;
+}
+
+QSize QSGSoftwarePixmapTexture::textureSize() const
+{
+ return m_pixmap.size();
+}
+
+bool QSGSoftwarePixmapTexture::hasAlphaChannel() const
+{
+ return m_pixmap.hasAlphaChannel();
+}
+
+bool QSGSoftwarePixmapTexture::hasMipmaps() const
+{
+ return false;
+}
+
+void QSGSoftwarePixmapTexture::bind()
+{
+ Q_UNREACHABLE();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaptexture_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaptexture_p.h
new file mode 100644
index 0000000000..034fa25da9
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaptexture_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWAREPIXMAPTEXTURE_H
+#define QSGSOFTWAREPIXMAPTEXTURE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgtexture_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGSoftwarePixmapTexture : public QSGTexture
+{
+ Q_OBJECT
+public:
+ QSGSoftwarePixmapTexture(const QImage &image, uint flags);
+ QSGSoftwarePixmapTexture(const QPixmap &pixmap);
+
+ int textureId() const override;
+ QSize textureSize() const override;
+ bool hasAlphaChannel() const override;
+ bool hasMipmaps() const override;
+ void bind() override;
+
+ const QPixmap &pixmap() const { return m_pixmap; }
+
+private:
+ QPixmap m_pixmap;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWAREPIXMAPTEXTURE_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode.cpp
new file mode 100644
index 0000000000..7672b14371
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode.cpp
@@ -0,0 +1,451 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwarerectanglenode_p.h"
+#include <qmath.h>
+
+#include <QtGui/QPainter>
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwareRectangleNode::QSGSoftwareRectangleNode()
+ : m_penWidth(0)
+ , m_radius(0)
+ , m_cornerPixmapIsDirty(true)
+ , m_devicePixelRatio(1)
+{
+ m_pen.setJoinStyle(Qt::MiterJoin);
+ m_pen.setMiterLimit(0);
+ setMaterial((QSGMaterial*)1);
+ setGeometry((QSGGeometry*)1);
+}
+
+void QSGSoftwareRectangleNode::setRect(const QRectF &rect)
+{
+ QRect alignedRect = rect.toAlignedRect();
+ if (m_rect != alignedRect) {
+ m_rect = alignedRect;
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGSoftwareRectangleNode::setColor(const QColor &color)
+{
+ if (m_color != color) {
+ m_color = color;
+ m_cornerPixmapIsDirty = true;
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGSoftwareRectangleNode::setPenColor(const QColor &color)
+{
+ if (m_penColor != color) {
+ m_penColor = color;
+ m_cornerPixmapIsDirty = true;
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGSoftwareRectangleNode::setPenWidth(qreal width)
+{
+ if (m_penWidth != width) {
+ m_penWidth = width;
+ m_cornerPixmapIsDirty = true;
+ markDirty(DirtyMaterial);
+ }
+}
+
+//Move first stop by pos relative to seconds
+static QGradientStop interpolateStop(const QGradientStop &firstStop, const QGradientStop &secondStop, double newPos)
+{
+ double distance = secondStop.first - firstStop.first;
+ double distanceDelta = newPos - firstStop.first;
+ double modifierValue = distanceDelta / distance;
+ int redDelta = (secondStop.second.red() - firstStop.second.red()) * modifierValue;
+ int greenDelta = (secondStop.second.green() - firstStop.second.green()) * modifierValue;
+ int blueDelta = (secondStop.second.blue() - firstStop.second.blue()) * modifierValue;
+ int alphaDelta = (secondStop.second.alpha() - firstStop.second.alpha()) * modifierValue;
+
+ QGradientStop newStop;
+ newStop.first = newPos;
+ newStop.second = QColor(firstStop.second.red() + redDelta,
+ firstStop.second.green() + greenDelta,
+ firstStop.second.blue() + blueDelta,
+ firstStop.second.alpha() + alphaDelta);
+
+ return newStop;
+}
+
+void QSGSoftwareRectangleNode::setGradientStops(const QGradientStops &stops)
+{
+ //normalize stops
+ bool needsNormalization = false;
+ foreach (const QGradientStop &stop, stops) {
+ if (stop.first < 0.0 || stop.first > 1.0) {
+ needsNormalization = true;
+ continue;
+ }
+ }
+
+ if (needsNormalization) {
+ QGradientStops normalizedStops;
+ if (stops.count() == 1) {
+ //If there is only one stop, then the position does not matter
+ //It is just treated as a color
+ QGradientStop stop = stops.at(0);
+ stop.first = 0.0;
+ normalizedStops.append(stop);
+ } else {
+ //Clip stops to only the first below 0.0 and above 1.0
+ int below = -1;
+ int above = -1;
+ QVector<int> between;
+ for (int i = 0; i < stops.count(); ++i) {
+ if (stops.at(i).first < 0.0) {
+ below = i;
+ } else if (stops.at(i).first > 1.0) {
+ above = i;
+ break;
+ } else {
+ between.append(i);
+ }
+ }
+
+ //Interpoloate new color values for above and below
+ if (below != -1 ) {
+ //If there are more than one stops left, interpolate
+ if (below + 1 < stops.count()) {
+ normalizedStops.append(interpolateStop(stops.at(below), stops.at(below + 1), 0.0));
+ } else {
+ QGradientStop singleStop;
+ singleStop.first = 0.0;
+ singleStop.second = stops.at(below).second;
+ normalizedStops.append(singleStop);
+ }
+ }
+
+ for (int i = 0; i < between.count(); ++i)
+ normalizedStops.append(stops.at(between.at(i)));
+
+ if (above != -1) {
+ //If there stops before above, interpolate
+ if (above >= 1) {
+ normalizedStops.append(interpolateStop(stops.at(above), stops.at(above - 1), 1.0));
+ } else {
+ QGradientStop singleStop;
+ singleStop.first = 1.0;
+ singleStop.second = stops.at(above).second;
+ normalizedStops.append(singleStop);
+ }
+ }
+ }
+
+ m_stops = normalizedStops;
+
+ } else {
+ m_stops = stops;
+ }
+ m_cornerPixmapIsDirty = true;
+ markDirty(DirtyMaterial);
+}
+
+void QSGSoftwareRectangleNode::setRadius(qreal radius)
+{
+ if (m_radius != radius) {
+ m_radius = radius;
+ m_cornerPixmapIsDirty = true;
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGSoftwareRectangleNode::setAligned(bool /*aligned*/)
+{
+}
+
+void QSGSoftwareRectangleNode::update()
+{
+ if (!m_penWidth || m_penColor == Qt::transparent) {
+ m_pen = Qt::NoPen;
+ } else {
+ m_pen = QPen(m_penColor);
+ m_pen.setWidthF(m_penWidth);
+ }
+
+ if (!m_stops.isEmpty()) {
+ QLinearGradient gradient(QPoint(0,0), QPoint(0,1));
+ gradient.setStops(m_stops);
+ gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
+ m_brush = QBrush(gradient);
+ } else {
+ m_brush = QBrush(m_color);
+ }
+
+ if (m_cornerPixmapIsDirty) {
+ generateCornerPixmap();
+ m_cornerPixmapIsDirty = false;
+ }
+}
+
+void QSGSoftwareRectangleNode::paint(QPainter *painter)
+{
+ //We can only check for a device pixel ratio change when we know what
+ //paint device is being used.
+ if (painter->device()->devicePixelRatio() != m_devicePixelRatio) {
+ m_devicePixelRatio = painter->device()->devicePixelRatio();
+ generateCornerPixmap();
+ }
+
+ if (painter->transform().isRotating()) {
+ //Rotated rectangles lose the benefits of direct rendering, and have poor rendering
+ //quality when using only blits and fills.
+
+ if (m_radius == 0 && m_penWidth == 0) {
+ //Non-Rounded Rects without borders (fall back to drawRect)
+ //Most common case
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(m_brush);
+ painter->drawRect(m_rect);
+ } else {
+ //Rounded Rects and Rects with Borders
+ //Avoids broken behaviors of QPainter::drawRect/roundedRect
+ QPixmap pixmap = QPixmap(m_rect.width() * m_devicePixelRatio, m_rect.height() * m_devicePixelRatio);
+ pixmap.fill(Qt::transparent);
+ pixmap.setDevicePixelRatio(m_devicePixelRatio);
+ QPainter pixmapPainter(&pixmap);
+ paintRectangle(&pixmapPainter, QRect(0, 0, m_rect.width(), m_rect.height()));
+
+ QPainter::RenderHints previousRenderHints = painter->renderHints();
+ painter->setRenderHint(QPainter::SmoothPixmapTransform, true);
+ painter->drawPixmap(m_rect, pixmap);
+ painter->setRenderHints(previousRenderHints);
+ }
+
+
+ } else {
+ //Paint directly
+ paintRectangle(painter, m_rect);
+ }
+
+}
+
+bool QSGSoftwareRectangleNode::isOpaque() const
+{
+ if (m_radius > 0.0f)
+ return false;
+ if (m_color.alpha() < 255)
+ return false;
+ if (m_penWidth > 0.0f && m_penColor.alpha() < 255)
+ return false;
+ if (m_stops.count() > 0) {
+ foreach (QGradientStop stop, m_stops) {
+ if (stop.second.alpha() < 255)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+QRectF QSGSoftwareRectangleNode::rect() const
+{
+ //TODO: double check that this is correct.
+ return m_rect;
+}
+
+void QSGSoftwareRectangleNode::paintRectangle(QPainter *painter, const QRect &rect)
+{
+ //Radius should never exceeds half of the width or half of the height
+ int radius = qFloor(qMin(qMin(rect.width(), rect.height()) * 0.5, m_radius));
+
+ QPainter::RenderHints previousRenderHints = painter->renderHints();
+ painter->setRenderHint(QPainter::Antialiasing, false);
+
+ if (m_penWidth > 0) {
+ //Fill border Rects
+
+ //Borders can not be more than half the height/width of a rect
+ double borderWidth = qMin(m_penWidth, rect.width() * 0.5);
+ double borderHeight = qMin(m_penWidth, rect.height() * 0.5);
+
+
+
+ if (borderWidth > radius) {
+ //4 Rects
+ QRectF borderTopOutside(QPointF(rect.x() + radius, rect.y()),
+ QPointF(rect.x() + rect.width() - radius, rect.y() + radius));
+ QRectF borderTopInside(QPointF(rect.x() + borderWidth, rect.y() + radius),
+ QPointF(rect.x() + rect.width() - borderWidth, rect.y() + borderHeight));
+ QRectF borderBottomOutside(QPointF(rect.x() + radius, rect.y() + rect.height() - radius),
+ QPointF(rect.x() + rect.width() - radius, rect.y() + rect.height()));
+ QRectF borderBottomInside(QPointF(rect.x() + borderWidth, rect.y() + rect.height() - borderHeight),
+ QPointF(rect.x() + rect.width() - borderWidth, rect.y() + rect.height() - radius));
+
+ if (borderTopOutside.isValid())
+ painter->fillRect(borderTopOutside, m_penColor);
+ if (borderTopInside.isValid())
+ painter->fillRect(borderTopInside, m_penColor);
+ if (borderBottomOutside.isValid())
+ painter->fillRect(borderBottomOutside, m_penColor);
+ if (borderBottomInside.isValid())
+ painter->fillRect(borderBottomInside, m_penColor);
+
+ } else {
+ //2 Rects
+ QRectF borderTop(QPointF(rect.x() + radius, rect.y()),
+ QPointF(rect.x() + rect.width() - radius, rect.y() + borderHeight));
+ QRectF borderBottom(QPointF(rect.x() + radius, rect.y() + rect.height() - borderHeight),
+ QPointF(rect.x() + rect.width() - radius, rect.y() + rect.height()));
+ if (borderTop.isValid())
+ painter->fillRect(borderTop, m_penColor);
+ if (borderBottom.isValid())
+ painter->fillRect(borderBottom, m_penColor);
+ }
+ QRectF borderLeft(QPointF(rect.x(), rect.y() + radius),
+ QPointF(rect.x() + borderWidth, rect.y() + rect.height() - radius));
+ QRectF borderRight(QPointF(rect.x() + rect.width() - borderWidth, rect.y() + radius),
+ QPointF(rect.x() + rect.width(), rect.y() + rect.height() - radius));
+ if (borderLeft.isValid())
+ painter->fillRect(borderLeft, m_penColor);
+ if (borderRight.isValid())
+ painter->fillRect(borderRight, m_penColor);
+ }
+
+
+ if (radius > 0) {
+
+ if (radius * 2 >= rect.width() && radius * 2 >= rect.height()) {
+ //Blit whole pixmap for circles
+ painter->drawPixmap(rect, m_cornerPixmap, m_cornerPixmap.rect());
+ } else {
+
+ //blit 4 corners to border
+ int scaledRadius = radius * m_devicePixelRatio;
+ QRectF topLeftCorner(QPointF(rect.x(), rect.y()),
+ QPointF(rect.x() + radius, rect.y() + radius));
+ painter->drawPixmap(topLeftCorner, m_cornerPixmap, QRectF(0, 0, scaledRadius, scaledRadius));
+ QRectF topRightCorner(QPointF(rect.x() + rect.width() - radius, rect.y()),
+ QPointF(rect.x() + rect.width(), rect.y() + radius));
+ painter->drawPixmap(topRightCorner, m_cornerPixmap, QRectF(scaledRadius, 0, scaledRadius, scaledRadius));
+ QRectF bottomLeftCorner(QPointF(rect.x(), rect.y() + rect.height() - radius),
+ QPointF(rect.x() + radius, rect.y() + rect.height()));
+ painter->drawPixmap(bottomLeftCorner, m_cornerPixmap, QRectF(0, scaledRadius, scaledRadius, scaledRadius));
+ QRectF bottomRightCorner(QPointF(rect.x() + rect.width() - radius, rect.y() + rect.height() - radius),
+ QPointF(rect.x() + rect.width(), rect.y() + rect.height()));
+ painter->drawPixmap(bottomRightCorner, m_cornerPixmap, QRectF(scaledRadius, scaledRadius, scaledRadius, scaledRadius));
+
+ }
+
+ }
+
+ QRectF brushRect = QRectF(rect).marginsRemoved(QMarginsF(m_penWidth, m_penWidth, m_penWidth, m_penWidth));
+ if (brushRect.width() < 0)
+ brushRect.setWidth(0);
+ if (brushRect.height() < 0)
+ brushRect.setHeight(0);
+ double innerRectRadius = qMax(0.0, radius - m_penWidth);
+
+ //If not completely transparent or has a gradient
+ if (m_color.alpha() > 0 || !m_stops.empty()) {
+ if (innerRectRadius > 0) {
+ //Rounded Rect
+ if (m_stops.empty()) {
+ //Rounded Rects without gradient need 3 blits
+ QRectF centerRect(QPointF(brushRect.x() + innerRectRadius, brushRect.y()),
+ QPointF(brushRect.x() + brushRect.width() - innerRectRadius, brushRect.y() + brushRect.height()));
+ painter->fillRect(centerRect, m_color);
+ QRectF leftRect(QPointF(brushRect.x(), brushRect.y() + innerRectRadius),
+ QPointF(brushRect.x() + innerRectRadius, brushRect.y() + brushRect.height() - innerRectRadius));
+ painter->fillRect(leftRect, m_color);
+ QRectF rightRect(QPointF(brushRect.x() + brushRect.width() - innerRectRadius, brushRect.y() + innerRectRadius),
+ QPointF(brushRect.x() + brushRect.width(), brushRect.y() + brushRect.height() - innerRectRadius));
+ painter->fillRect(rightRect, m_color);
+ } else {
+ //Rounded Rect with gradient (slow)
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(m_brush);
+ painter->drawRoundedRect(brushRect, innerRectRadius, innerRectRadius);
+ }
+ } else {
+ //non-rounded rects only need 1 blit
+ painter->fillRect(brushRect, m_brush);
+ }
+ }
+
+ painter->setRenderHints(previousRenderHints);
+}
+
+void QSGSoftwareRectangleNode::generateCornerPixmap()
+{
+ //Generate new corner Pixmap
+ int radius = qFloor(qMin(qMin(m_rect.width(), m_rect.height()) * 0.5, m_radius));
+
+ m_cornerPixmap = QPixmap(radius * 2 * m_devicePixelRatio, radius * 2 * m_devicePixelRatio);
+ m_cornerPixmap.setDevicePixelRatio(m_devicePixelRatio);
+ m_cornerPixmap.fill(Qt::transparent);
+
+ if (radius > 0) {
+ QPainter cornerPainter(&m_cornerPixmap);
+ cornerPainter.setRenderHint(QPainter::Antialiasing);
+ cornerPainter.setCompositionMode(QPainter::CompositionMode_Source);
+
+ //Paint outer cicle
+ if (m_penWidth > 0) {
+ cornerPainter.setPen(Qt::NoPen);
+ cornerPainter.setBrush(m_penColor);
+ cornerPainter.drawRoundedRect(QRectF(0, 0, radius * 2, radius *2), radius, radius);
+ }
+
+ //Paint inner circle
+ if (radius > m_penWidth) {
+ cornerPainter.setPen(Qt::NoPen);
+ if (m_stops.isEmpty())
+ cornerPainter.setBrush(m_brush);
+ else
+ cornerPainter.setBrush(Qt::transparent);
+
+ QMarginsF adjustmentMargins(m_penWidth, m_penWidth, m_penWidth, m_penWidth);
+ QRectF cornerCircleRect = QRectF(0, 0, radius * 2, radius * 2).marginsRemoved(adjustmentMargins);
+ cornerPainter.drawRoundedRect(cornerCircleRect, radius, radius);
+ }
+ cornerPainter.end();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode_p.h
new file mode 100644
index 0000000000..9cc0823325
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerectanglenode_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWARERECTANGLENODE_H
+#define QSGSOFTWARERECTANGLENODE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgadaptationlayer_p.h>
+
+#include <QPen>
+#include <QBrush>
+#include <QPixmap>
+
+QT_BEGIN_NAMESPACE
+
+class QSGSoftwareRectangleNode : public QSGRectangleNode
+{
+public:
+ QSGSoftwareRectangleNode();
+
+ void setRect(const QRectF &rect) override;
+ void setColor(const QColor &color) override;
+ void setPenColor(const QColor &color) override;
+ void setPenWidth(qreal width) override;
+ void setGradientStops(const QGradientStops &stops) override;
+ void setRadius(qreal radius) override;
+ void setAntialiasing(bool antialiasing) override { Q_UNUSED(antialiasing) }
+ void setAligned(bool aligned) override;
+
+ void update() override;
+
+ void paint(QPainter *);
+
+ bool isOpaque() const;
+ QRectF rect() const;
+private:
+ void paintRectangle(QPainter *painter, const QRect &rect);
+ void generateCornerPixmap();
+
+ QRect m_rect;
+ QColor m_color;
+ QColor m_penColor;
+ double m_penWidth;
+ QGradientStops m_stops;
+ double m_radius;
+ QPen m_pen;
+ QBrush m_brush;
+
+ bool m_cornerPixmapIsDirty;
+ QPixmap m_cornerPixmap;
+
+ int m_devicePixelRatio;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWARERECTANGLENODE_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp
new file mode 100644
index 0000000000..063242c63b
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp
@@ -0,0 +1,328 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwarerenderablenode_p.h"
+
+#include "qsgsoftwareimagenode_p.h"
+#include "qsgsoftwarerectanglenode_p.h"
+#include "qsgsoftwareglyphnode_p.h"
+#include "qsgsoftwareninepatchnode_p.h"
+#include "qsgsoftwarepainternode_p.h"
+#include "qsgsoftwarepixmaptexture_p.h"
+
+#include <QtQuick/QSGSimpleRectNode>
+#include <QtQuick/qsgsimpletexturenode.h>
+#include <private/qsgtexture_p.h>
+
+Q_LOGGING_CATEGORY(lcRenderable, "qt.scenegraph.softwarecontext.renderable")
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwareRenderableNode::QSGSoftwareRenderableNode(NodeType type, QSGNode *node)
+ : m_nodeType(type)
+ , m_isOpaque(true)
+ , m_isDirty(true)
+ , m_opacity(1.0f)
+{
+ switch (m_nodeType) {
+ case QSGSoftwareRenderableNode::SimpleRect:
+ m_handle.simpleRectNode = static_cast<QSGSimpleRectNode*>(node);
+ break;
+ case QSGSoftwareRenderableNode::SimpleTexture:
+ m_handle.simpleTextureNode = static_cast<QSGSimpleTextureNode*>(node);
+ break;
+ case QSGSoftwareRenderableNode::Image:
+ m_handle.imageNode = static_cast<QSGSoftwareImageNode*>(node);
+ break;
+ case QSGSoftwareRenderableNode::Painter:
+ m_handle.painterNode = static_cast<QSGSoftwarePainterNode*>(node);
+ break;
+ case QSGSoftwareRenderableNode::Rectangle:
+ m_handle.rectangleNode = static_cast<QSGSoftwareRectangleNode*>(node);
+ break;
+ case QSGSoftwareRenderableNode::Glyph:
+ m_handle.glpyhNode = static_cast<QSGSoftwareGlyphNode*>(node);
+ break;
+ case QSGSoftwareRenderableNode::NinePatch:
+ m_handle.ninePatchNode = static_cast<QSGSoftwareNinePatchNode*>(node);
+ break;
+ case QSGSoftwareRenderableNode::Invalid:
+ m_handle.simpleRectNode = nullptr;
+ break;
+ }
+}
+
+QSGSoftwareRenderableNode::~QSGSoftwareRenderableNode()
+{
+
+}
+
+void QSGSoftwareRenderableNode::update()
+{
+ // Update the Node properties
+ m_isDirty = true;
+
+ QRect boundingRect;
+
+ switch (m_nodeType) {
+ case QSGSoftwareRenderableNode::SimpleRect:
+ if (m_handle.simpleRectNode->color().alpha() == 255 && !m_transform.isRotating())
+ m_isOpaque = true;
+ else
+ m_isOpaque = false;
+
+ boundingRect = m_handle.simpleRectNode->rect().toRect();
+ break;
+ case QSGSoftwareRenderableNode::SimpleTexture:
+ if (!m_handle.simpleTextureNode->texture()->hasAlphaChannel() && !m_transform.isRotating())
+ m_isOpaque = true;
+ else
+ m_isOpaque = false;
+
+ boundingRect = m_handle.simpleTextureNode->rect().toRect();
+ break;
+ case QSGSoftwareRenderableNode::Image:
+ // There isn't a way to tell, so assume it's not
+ m_isOpaque = false;
+
+ boundingRect = m_handle.imageNode->rect().toRect();
+ break;
+ case QSGSoftwareRenderableNode::Painter:
+ if (m_handle.painterNode->opaquePainting() && !m_transform.isRotating())
+ m_isOpaque = true;
+ else
+ m_isOpaque = false;
+
+ boundingRect = QRect(0, 0, m_handle.painterNode->size().width(), m_handle.painterNode->size().height());
+ break;
+ case QSGSoftwareRenderableNode::Rectangle:
+ if (m_handle.rectangleNode->isOpaque() && !m_transform.isRotating())
+ m_isOpaque = true;
+ else
+ m_isOpaque = false;
+
+ boundingRect = m_handle.rectangleNode->rect().toRect();
+ break;
+ case QSGSoftwareRenderableNode::Glyph:
+ // Always has alpha
+ m_isOpaque = false;
+
+ boundingRect = m_handle.glpyhNode->boundingRect().toAlignedRect();
+ break;
+ case QSGSoftwareRenderableNode::NinePatch:
+ // Difficult to tell, assume non-opaque
+ m_isOpaque = false;
+
+ boundingRect = m_handle.ninePatchNode->bounds().toRect();
+ break;
+ default:
+ break;
+ }
+
+ m_boundingRect = m_transform.mapRect(boundingRect);
+
+ if (m_clipRegion.rectCount() == 1) {
+ m_boundingRect = m_boundingRect.intersected(m_clipRegion.rects().first());
+ }
+
+ // Overrides
+ if (m_opacity < 1.0f)
+ m_isOpaque = false;
+
+ m_dirtyRegion = QRegion(m_boundingRect);
+}
+
+QRegion QSGSoftwareRenderableNode::renderNode(QPainter *painter, bool forceOpaquePainting)
+{
+ Q_ASSERT(painter);
+
+ // Check for don't paint conditions
+ if (!m_isDirty || qFuzzyIsNull(m_opacity) || m_dirtyRegion.isEmpty()) {
+ m_isDirty = false;
+ m_dirtyRegion = QRegion();
+ return QRegion();
+ }
+
+ painter->save();
+ painter->setOpacity(m_opacity);
+
+ // Set clipRegion to m_dirtyRegion (in world coordinates)
+ // as m_dirtyRegion already accounts for clipRegion
+ painter->setClipRegion(m_dirtyRegion, Qt::ReplaceClip);
+ if (m_clipRegion.rectCount() > 1)
+ painter->setClipRegion(m_clipRegion, Qt::IntersectClip);
+
+ painter->setTransform(m_transform, false); //precalculated worldTransform
+ if (forceOpaquePainting || m_isOpaque)
+ painter->setCompositionMode(QPainter::CompositionMode_Source);
+
+ switch (m_nodeType) {
+ case QSGSoftwareRenderableNode::SimpleRect:
+ painter->fillRect(m_handle.simpleRectNode->rect(), m_handle.simpleRectNode->color());
+ break;
+ case QSGSoftwareRenderableNode::SimpleTexture:
+ {
+ QSGTexture *texture = m_handle.simpleTextureNode->texture();
+ if (QSGSoftwarePixmapTexture *pt = dynamic_cast<QSGSoftwarePixmapTexture *>(texture)) {
+ const QPixmap &pm = pt->pixmap();
+ painter->drawPixmap(m_handle.simpleTextureNode->rect(), pm, QRectF(0, 0, pm.width(), pm.height()));
+ } else if (QSGPlainTexture *pt = dynamic_cast<QSGPlainTexture *>(texture)) {
+ const QImage &im = pt->image();
+ painter->drawImage(m_handle.simpleTextureNode->rect(), im, QRectF(0, 0, im.width(), im.height()));
+ }
+ }
+ break;
+ case QSGSoftwareRenderableNode::Image:
+ m_handle.imageNode->paint(painter);
+ break;
+ case QSGSoftwareRenderableNode::Painter:
+ m_handle.painterNode->paint(painter);
+ break;
+ case QSGSoftwareRenderableNode::Rectangle:
+ m_handle.rectangleNode->paint(painter);
+ break;
+ case QSGSoftwareRenderableNode::Glyph:
+ m_handle.glpyhNode->paint(painter);
+ break;
+ case QSGSoftwareRenderableNode::NinePatch:
+ m_handle.ninePatchNode->paint(painter);
+ break;
+ default:
+ break;
+ }
+
+ painter->restore();
+
+ QRegion areaToBeFlushed = m_dirtyRegion;
+ m_previousDirtyRegion = QRegion(m_boundingRect);
+ m_isDirty = false;
+ m_dirtyRegion = QRegion();
+
+ return areaToBeFlushed;
+}
+
+QRect QSGSoftwareRenderableNode::boundingRect() const
+{
+ // This returns the bounding area of a renderable node in world coordinates
+ return m_boundingRect;
+}
+
+bool QSGSoftwareRenderableNode::isDirtyRegionEmpty() const
+{
+ return m_dirtyRegion.isEmpty();
+}
+
+void QSGSoftwareRenderableNode::setTransform(const QTransform &transform)
+{
+ if (m_transform == transform)
+ return;
+ m_transform = transform;
+ update();
+}
+
+void QSGSoftwareRenderableNode::setClipRegion(const QRegion &clipRect)
+{
+ if (m_clipRegion == clipRect)
+ return;
+
+ m_clipRegion = clipRect;
+ update();
+}
+
+void QSGSoftwareRenderableNode::setOpacity(float opacity)
+{
+ if (qFuzzyCompare(m_opacity, opacity))
+ return;
+
+ m_opacity = opacity;
+ update();
+}
+
+void QSGSoftwareRenderableNode::markGeometryDirty()
+{
+ update();
+}
+
+void QSGSoftwareRenderableNode::markMaterialDirty()
+{
+ update();
+}
+
+void QSGSoftwareRenderableNode::addDirtyRegion(const QRegion &dirtyRegion, bool forceDirty)
+{
+ // Check if the dirty region applys to this node
+ QRegion prev = m_dirtyRegion;
+ if (dirtyRegion.intersects(boundingRect())) {
+ if (forceDirty)
+ m_isDirty = true;
+ m_dirtyRegion += dirtyRegion.intersected(boundingRect());
+ }
+ qCDebug(lcRenderable) << "addDirtyRegion: " << dirtyRegion << "old dirtyRegion: " << prev << "new dirtyRegion: " << m_dirtyRegion;
+}
+
+void QSGSoftwareRenderableNode::subtractDirtyRegion(const QRegion &dirtyRegion)
+{
+ QRegion prev = m_dirtyRegion;
+ if (m_isDirty) {
+ // Check if this rect concerns us
+ if (dirtyRegion.intersects(QRegion(boundingRect()))) {
+ m_dirtyRegion -= dirtyRegion;
+ if (m_dirtyRegion.isEmpty())
+ m_isDirty = false;
+ }
+ }
+ qCDebug(lcRenderable) << "subtractDirtyRegion: " << dirtyRegion << "old dirtyRegion" << prev << "new dirtyRegion: " << m_dirtyRegion;
+}
+
+QRegion QSGSoftwareRenderableNode::previousDirtyRegion(bool wasRemoved) const
+{
+ // When removing a node, the boundingRect shouldn't be subtracted
+ // because a deleted node has no valid boundingRect
+ if (wasRemoved)
+ return m_previousDirtyRegion;
+
+ return m_previousDirtyRegion.subtracted(QRegion(m_boundingRect));
+}
+
+QRegion QSGSoftwareRenderableNode::dirtyRegion() const
+{
+ return m_dirtyRegion;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h
new file mode 100644
index 0000000000..9a5e0a5683
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWARERENDERABLENODE_H
+#define QSGSOFTWARERENDERABLENODE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/QRegion>
+#include <QtCore/QRect>
+#include <QtGui/QTransform>
+
+QT_BEGIN_NAMESPACE
+
+class QSGNode;
+class QSGSimpleRectNode;
+class QSGSimpleTextureNode;
+class QSGSoftwareImageNode;
+class QSGSoftwarePainterNode;
+class QSGSoftwareRectangleNode;
+class QSGSoftwareGlyphNode;
+class QSGSoftwareNinePatchNode;
+
+class QSGSoftwareRenderableNode
+{
+public:
+ enum NodeType {
+ Invalid = -1,
+ SimpleRect,
+ SimpleTexture,
+ Image,
+ Painter,
+ Rectangle,
+ Glyph,
+ NinePatch
+ };
+
+ QSGSoftwareRenderableNode(NodeType type, QSGNode *node);
+ ~QSGSoftwareRenderableNode();
+
+ void update();
+
+ QRegion renderNode(QPainter *painter, bool forceOpaquePainting = false);
+ QRect boundingRect() const;
+ NodeType type() const { return m_nodeType; }
+ bool isOpaque() const { return m_isOpaque; }
+ bool isDirty() const { return m_isDirty; }
+ bool isDirtyRegionEmpty() const;
+
+ void setTransform(const QTransform &transform);
+ void setClipRegion(const QRegion &clipRegion);
+ void setOpacity(float opacity);
+ QTransform transform() const { return m_transform; }
+ QRegion clipRegion() const { return m_clipRegion; }
+ float opacity() const { return m_opacity; }
+
+ void markGeometryDirty();
+ void markMaterialDirty();
+
+ void addDirtyRegion(const QRegion &dirtyRegion, bool forceDirty = true);
+ void subtractDirtyRegion(const QRegion &dirtyRegion);
+
+ QRegion previousDirtyRegion(bool wasRemoved = false) const;
+ QRegion dirtyRegion() const;
+
+private:
+ union RenderableNodeHandle {
+ QSGSimpleRectNode *simpleRectNode;
+ QSGSimpleTextureNode *simpleTextureNode;
+ QSGSoftwareImageNode *imageNode;
+ QSGSoftwarePainterNode *painterNode;
+ QSGSoftwareRectangleNode *rectangleNode;
+ QSGSoftwareGlyphNode *glpyhNode;
+ QSGSoftwareNinePatchNode *ninePatchNode;
+ };
+
+ const NodeType m_nodeType;
+ RenderableNodeHandle m_handle;
+
+ bool m_isOpaque;
+
+ bool m_isDirty;
+ QRegion m_dirtyRegion;
+ QRegion m_previousDirtyRegion;
+
+ QTransform m_transform;
+ QRegion m_clipRegion;
+ float m_opacity;
+
+ QRect m_boundingRect;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWARERENDERABLENODE_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp
new file mode 100644
index 0000000000..3d5fe21f7c
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp
@@ -0,0 +1,275 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwarerenderablenodeupdater_p.h"
+
+#include "qsgabstractsoftwarerenderer_p.h"
+#include "qsgsoftwareimagenode_p.h"
+#include "qsgsoftwarerectanglenode_p.h"
+#include "qsgsoftwareglyphnode_p.h"
+#include "qsgsoftwareninepatchnode_p.h"
+#include "qsgsoftwarepainternode_p.h"
+#include "qsgsoftwarepixmaptexture_p.h"
+
+#include <QtQuick/QSGSimpleRectNode>
+#include <QtQuick/qsgsimpletexturenode.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwareRenderableNodeUpdater::QSGSoftwareRenderableNodeUpdater(QSGAbstractSoftwareRenderer *renderer)
+ : m_renderer(renderer)
+{
+ m_opacityState.push(1.0f);
+ // Invalid RectF by default for no clip
+ m_clipState.push(QRegion());
+ m_transformState.push(QTransform());
+}
+
+QSGSoftwareRenderableNodeUpdater::~QSGSoftwareRenderableNodeUpdater()
+{
+
+}
+
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGTransformNode *node)
+{
+ m_transformState.push(node->matrix().toTransform() * m_transformState.top());
+ m_stateMap[node] = currentState(node);
+ return true;
+}
+
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGTransformNode *)
+{
+ m_transformState.pop();
+}
+
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGClipNode *node)
+{
+ // Make sure to translate the clip rect into world coordinates
+ if (m_clipState.top().isEmpty()) {
+ m_clipState.push(m_transformState.top().map(QRegion(node->clipRect().toRect())));
+ } else
+ m_clipState.push(m_transformState.top().map(QRegion(node->clipRect().toRect()).intersected(m_clipState.top())));
+ m_stateMap[node] = currentState(node);
+ return true;
+}
+
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGClipNode *)
+{
+ m_clipState.pop();
+}
+
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGGeometryNode *node)
+{
+ if (QSGSimpleRectNode *rectNode = dynamic_cast<QSGSimpleRectNode *>(node)) {
+ return updateRenderableNode(QSGSoftwareRenderableNode::SimpleRect, rectNode);
+ } else if (QSGSimpleTextureNode *tn = dynamic_cast<QSGSimpleTextureNode *>(node)) {
+ return updateRenderableNode(QSGSoftwareRenderableNode::SimpleTexture, tn);
+ } else {
+ // We dont know, so skip
+ return false;
+ }
+}
+
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGGeometryNode *)
+{
+}
+
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGOpacityNode *node)
+{
+ m_opacityState.push(m_opacityState.top() * node->opacity());
+ m_stateMap[node] = currentState(node);
+ return true;
+}
+
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGOpacityNode *)
+{
+ m_opacityState.pop();
+}
+
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGImageNode *node)
+{
+ return updateRenderableNode(QSGSoftwareRenderableNode::Image, node);
+}
+
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGImageNode *)
+{
+}
+
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGPainterNode *node)
+{
+ return updateRenderableNode(QSGSoftwareRenderableNode::Painter, node);
+}
+
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGPainterNode *)
+{
+}
+
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGRectangleNode *node)
+{
+ return updateRenderableNode(QSGSoftwareRenderableNode::Rectangle, node);
+}
+
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRectangleNode *)
+{
+}
+
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGGlyphNode *node)
+{
+ return updateRenderableNode(QSGSoftwareRenderableNode::Glyph, node);
+}
+
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGGlyphNode *)
+{
+}
+
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGNinePatchNode *node)
+{
+ return updateRenderableNode(QSGSoftwareRenderableNode::NinePatch, node);
+}
+
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGNinePatchNode *)
+{
+}
+
+bool QSGSoftwareRenderableNodeUpdater::visit(QSGRootNode *node)
+{
+ m_stateMap[node] = currentState(node);
+ return true;
+}
+
+void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRootNode *)
+{
+}
+
+void QSGSoftwareRenderableNodeUpdater::updateNodes(QSGNode *node, bool isNodeRemoved)
+{
+ m_opacityState.clear();
+ m_clipState.clear();
+ m_transformState.clear();
+
+ auto parentNode = node->parent();
+ // If the node was deleted, it will have no parent
+ // check if the state map has the previous parent
+ if ((!parentNode || isNodeRemoved ) && m_stateMap.contains(node))
+ parentNode = m_stateMap[node].parent;
+
+ // If we find a parent, use its state for updating the new children
+ if (parentNode && m_stateMap.contains(parentNode)) {
+ auto state = m_stateMap[parentNode];
+ m_opacityState.push(state.opacity);
+ m_transformState.push(state.transform);
+ m_clipState.push(state.clip);
+
+ } else {
+ // There is no parent, and no previous parent, so likely a root node
+ m_opacityState.push(1.0f);
+ m_transformState.push(QTransform());
+ m_clipState.push(QRegion());
+ }
+
+ // If the node is being removed, then cleanup the state data
+ // Then just visit the children without visiting the now removed node
+ if (isNodeRemoved) {
+ m_stateMap.remove(node);
+ return;
+ }
+
+ // Visit the current node itself first
+ switch (node->type()) {
+ case QSGNode::ClipNodeType: {
+ QSGClipNode *c = static_cast<QSGClipNode*>(node);
+ if (visit(c))
+ visitChildren(c);
+ endVisit(c);
+ break;
+ }
+ case QSGNode::TransformNodeType: {
+ QSGTransformNode *c = static_cast<QSGTransformNode*>(node);
+ if (visit(c))
+ visitChildren(c);
+ endVisit(c);
+ break;
+ }
+ case QSGNode::OpacityNodeType: {
+ QSGOpacityNode *c = static_cast<QSGOpacityNode*>(node);
+ if (visit(c))
+ visitChildren(c);
+ endVisit(c);
+ break;
+ }
+ case QSGNode::GeometryNodeType: {
+ if (node->flags() & QSGNode::IsVisitableNode) {
+ QSGVisitableNode *v = static_cast<QSGVisitableNode*>(node);
+ v->accept(this);
+ } else {
+ QSGGeometryNode *c = static_cast<QSGGeometryNode*>(node);
+ if (visit(c))
+ visitChildren(c);
+ endVisit(c);
+ }
+ break;
+ }
+ case QSGNode::RootNodeType: {
+ QSGRootNode *root = static_cast<QSGRootNode*>(node);
+ if (visit(root))
+ visitChildren(root);
+ endVisit(root);
+ break;
+ }
+ case QSGNode::BasicNodeType: {
+ visitChildren(node);
+ break;
+ }
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+}
+
+QSGSoftwareRenderableNodeUpdater::NodeState QSGSoftwareRenderableNodeUpdater::currentState(QSGNode *node) const
+{
+ NodeState state;
+ state.opacity = m_opacityState.top();
+ state.clip = m_clipState.top();
+ state.transform = m_transformState.top();
+ state.parent = node->parent();
+ return state;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h
new file mode 100644
index 0000000000..562d15769e
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWARERENDERABLENODEUPDATER_H
+#define QSGSOFTWARERENDERABLENODEUPDATER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qsgsoftwarerenderablenode_p.h"
+#include "qsgabstractsoftwarerenderer_p.h"
+
+#include <private/qsgadaptationlayer_p.h>
+
+#include <QTransform>
+#include <QStack>
+#include <QRectF>
+
+QT_BEGIN_NAMESPACE
+
+class QSGSoftwareRenderableNodeUpdater : public QSGNodeVisitorEx
+{
+public:
+ QSGSoftwareRenderableNodeUpdater(QSGAbstractSoftwareRenderer *renderer);
+ virtual ~QSGSoftwareRenderableNodeUpdater();
+
+ bool visit(QSGTransformNode *) override;
+ void endVisit(QSGTransformNode *) override;
+ bool visit(QSGClipNode *) override;
+ void endVisit(QSGClipNode *) override;
+ bool visit(QSGGeometryNode *) override;
+ void endVisit(QSGGeometryNode *) override;
+ bool visit(QSGOpacityNode *) override;
+ void endVisit(QSGOpacityNode *) override;
+ bool visit(QSGImageNode *) override;
+ void endVisit(QSGImageNode *) override;
+ bool visit(QSGPainterNode *) override;
+ void endVisit(QSGPainterNode *) override;
+ bool visit(QSGRectangleNode *) override;
+ void endVisit(QSGRectangleNode *) override;
+ bool visit(QSGGlyphNode *) override;
+ void endVisit(QSGGlyphNode *) override;
+ bool visit(QSGNinePatchNode *) override;
+ void endVisit(QSGNinePatchNode *) override;
+ bool visit(QSGRootNode *) override;
+ void endVisit(QSGRootNode *) override;
+
+ void updateNodes(QSGNode *node, bool isNodeRemoved = false);
+
+private:
+ struct NodeState {
+ float opacity;
+ QRegion clip;
+ QTransform transform;
+ QSGNode *parent;
+ };
+
+ NodeState currentState(QSGNode *node) const;
+
+ template<class NODE>
+ bool updateRenderableNode(QSGSoftwareRenderableNode::NodeType type, NODE *node);
+
+ QSGAbstractSoftwareRenderer *m_renderer;
+ QStack<float> m_opacityState;
+ QStack<QRegion> m_clipState;
+ QStack<QTransform> m_transformState;
+ QHash<QSGNode*,NodeState> m_stateMap;
+};
+
+template<class NODE>
+bool QSGSoftwareRenderableNodeUpdater::updateRenderableNode(QSGSoftwareRenderableNode::NodeType type, NODE *node)
+{
+ //Check if we already know about node
+ auto renderableNode = m_renderer->renderableNode(node);
+ if (renderableNode == nullptr) {
+ renderableNode = new QSGSoftwareRenderableNode(type, node);
+ m_renderer->addNodeMapping(node, renderableNode);
+ }
+
+ //Update the node
+ renderableNode->setTransform(m_transformState.top());
+ renderableNode->setOpacity(m_opacityState.top());
+ renderableNode->setClipRegion(m_clipState.top());
+
+ renderableNode->update();
+ m_stateMap[node] = currentState(node);
+
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWARERENDERABLENODEUPDATER_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp
new file mode 100644
index 0000000000..ea00de7a66
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwarerenderer_p.h"
+
+#include "qsgsoftwarerenderablenodeupdater_p.h"
+#include "qsgsoftwarerenderlistbuilder_p.h"
+#include "qsgsoftwarecontext_p.h"
+#include "qsgsoftwarerenderablenode_p.h"
+
+#include <QtGui/QPaintDevice>
+#include <QElapsedTimer>
+
+Q_LOGGING_CATEGORY(lcRenderer, "qt.scenegraph.softwarecontext.renderer")
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwareRenderer::QSGSoftwareRenderer(QSGRenderContext *context)
+ : QSGAbstractSoftwareRenderer(context)
+{
+}
+
+QSGSoftwareRenderer::~QSGSoftwareRenderer()
+{
+}
+
+void QSGSoftwareRenderer::setCurrentPaintDevice(QPaintDevice *device)
+{
+ m_paintDevice = device;
+}
+
+QRegion QSGSoftwareRenderer::flushRegion() const
+{
+ return m_flushRegion;
+}
+
+void QSGSoftwareRenderer::renderScene(uint)
+{
+ class B : public QSGBindable
+ {
+ public:
+ void bind() const { }
+ } bindable;
+ QSGRenderer::renderScene(bindable);
+}
+
+void QSGSoftwareRenderer::render()
+{
+ if (!m_paintDevice)
+ return;
+
+ QElapsedTimer renderTimer;
+
+ setBackgroundColor(clearColor());
+ setBackgroundSize(QSize(m_paintDevice->width() / m_paintDevice->devicePixelRatio(),
+ m_paintDevice->height() / m_paintDevice->devicePixelRatio()));
+
+ QPainter painter(m_paintDevice);
+ painter.setRenderHint(QPainter::Antialiasing);
+
+ // Build Renderlist
+ // The renderlist is created by visiting each node in the tree and when a
+ // renderable node is reach, we find the coorosponding RenderableNode object
+ // and append it to the renderlist. At this point the RenderableNode object
+ // should not need any further updating so it is just a matter of appending
+ // RenderableNodes
+ renderTimer.start();
+ buildRenderList();
+ qint64 buildRenderListTime = renderTimer.restart();
+
+ // Optimize Renderlist
+ // This is a pass through the renderlist to determine what actually needs to
+ // be painted. Without this pass the renderlist will simply render each item
+ // from back to front, with a high potential for overdraw. It would also lead
+ // to the entire window being flushed every frame. The objective of the
+ // optimization pass is to only paint dirty nodes that are not occuluded. A
+ // side effect of this is that additional nodes may need to be marked dirty to
+ // force a repaint. It is also important that any item that needs to be
+ // repainted only paints what is needed, via the use of clip regions.
+ optimizeRenderList();
+ qint64 optimizeRenderListTime = renderTimer.restart();
+
+ // Render the contents Renderlist
+ m_flushRegion = renderNodes(&painter);
+ qint64 renderTime = renderTimer.elapsed();
+
+ qCDebug(lcRenderer) << "render" << m_flushRegion << buildRenderListTime << optimizeRenderListTime << renderTime;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h
new file mode 100644
index 0000000000..e2b8bcddca
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer_p.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWARERENDERER_H
+#define QSGSOFTWARERENDERER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qsgabstractsoftwarerenderer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QPaintDevice;
+
+class Q_QUICK_PRIVATE_EXPORT QSGSoftwareRenderer : public QSGAbstractSoftwareRenderer
+{
+public:
+ QSGSoftwareRenderer(QSGRenderContext *context);
+ virtual ~QSGSoftwareRenderer();
+
+ void setCurrentPaintDevice(QPaintDevice *device);
+ QRegion flushRegion() const;
+
+protected:
+ void renderScene(uint fboId = 0) final;
+ void render() final;
+
+private:
+ QPaintDevice* m_paintDevice;
+ QRegion m_flushRegion;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWARERENDERER_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp
new file mode 100644
index 0000000000..af81ff61c3
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwarerenderlistbuilder_p.h"
+
+#include "qsgsoftwarerenderablenode_p.h"
+#include "qsgabstractsoftwarerenderer_p.h"
+#include "qsgsoftwareimagenode_p.h"
+#include "qsgsoftwarerectanglenode_p.h"
+#include "qsgsoftwareglyphnode_p.h"
+#include "qsgsoftwareninepatchnode_p.h"
+#include "qsgsoftwarepainternode_p.h"
+#include "qsgsoftwarepixmaptexture_p.h"
+
+#include <QtQuick/QSGSimpleRectNode>
+#include <QtQuick/qsgsimpletexturenode.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwareRenderListBuilder::QSGSoftwareRenderListBuilder(QSGAbstractSoftwareRenderer *renderer)
+ : m_renderer(renderer)
+{
+
+}
+
+bool QSGSoftwareRenderListBuilder::visit(QSGTransformNode *)
+{
+ return true;
+}
+
+void QSGSoftwareRenderListBuilder::endVisit(QSGTransformNode *)
+{
+}
+
+bool QSGSoftwareRenderListBuilder::visit(QSGClipNode *)
+{
+ return true;
+}
+
+void QSGSoftwareRenderListBuilder::endVisit(QSGClipNode *)
+{
+}
+
+bool QSGSoftwareRenderListBuilder::visit(QSGGeometryNode *node)
+{
+ return addRenderableNode(node);
+}
+
+void QSGSoftwareRenderListBuilder::endVisit(QSGGeometryNode *)
+{
+}
+
+bool QSGSoftwareRenderListBuilder::visit(QSGOpacityNode *)
+{
+ return true;
+}
+
+void QSGSoftwareRenderListBuilder::endVisit(QSGOpacityNode *)
+{
+}
+
+bool QSGSoftwareRenderListBuilder::visit(QSGImageNode *node)
+{
+ return addRenderableNode(node);
+}
+
+void QSGSoftwareRenderListBuilder::endVisit(QSGImageNode *)
+{
+}
+
+bool QSGSoftwareRenderListBuilder::visit(QSGPainterNode *node)
+{
+ return addRenderableNode(node);
+}
+
+void QSGSoftwareRenderListBuilder::endVisit(QSGPainterNode *)
+{
+}
+
+bool QSGSoftwareRenderListBuilder::visit(QSGRectangleNode *node)
+{
+ return addRenderableNode(node);
+}
+
+void QSGSoftwareRenderListBuilder::endVisit(QSGRectangleNode *)
+{
+}
+
+bool QSGSoftwareRenderListBuilder::visit(QSGGlyphNode *node)
+{
+ return addRenderableNode(node);
+}
+
+void QSGSoftwareRenderListBuilder::endVisit(QSGGlyphNode *)
+{
+}
+
+bool QSGSoftwareRenderListBuilder::visit(QSGNinePatchNode *node)
+{
+ return addRenderableNode(node);
+}
+
+void QSGSoftwareRenderListBuilder::endVisit(QSGNinePatchNode *)
+{
+}
+
+bool QSGSoftwareRenderListBuilder::visit(QSGRootNode *)
+{
+ return true;
+}
+
+void QSGSoftwareRenderListBuilder::endVisit(QSGRootNode *)
+{
+}
+
+bool QSGSoftwareRenderListBuilder::addRenderableNode(QSGNode *node)
+{
+ auto renderableNode = m_renderer->renderableNode(node);
+ if (renderableNode == nullptr) {
+ // Not a node we can render
+ return false;
+ }
+ m_renderer->appendRenderableNode(renderableNode);
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h
new file mode 100644
index 0000000000..94b563564d
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWARERENDERLISTBUILDER_H
+#define QSGSOFTWARERENDERLISTBUILDER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgadaptationlayer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGAbstractSoftwareRenderer;
+
+class QSGSoftwareRenderListBuilder : public QSGNodeVisitorEx
+{
+public:
+ QSGSoftwareRenderListBuilder(QSGAbstractSoftwareRenderer *renderer);
+
+ bool visit(QSGTransformNode *) override;
+ void endVisit(QSGTransformNode *) override;
+ bool visit(QSGClipNode *) override;
+ void endVisit(QSGClipNode *) override;
+ bool visit(QSGGeometryNode *) override;
+ void endVisit(QSGGeometryNode *) override;
+ bool visit(QSGOpacityNode *) override;
+ void endVisit(QSGOpacityNode *) override;
+ bool visit(QSGImageNode *) override;
+ void endVisit(QSGImageNode *) override;
+ bool visit(QSGPainterNode *) override;
+ void endVisit(QSGPainterNode *) override;
+ bool visit(QSGRectangleNode *) override;
+ void endVisit(QSGRectangleNode *) override;
+ bool visit(QSGGlyphNode *) override;
+ void endVisit(QSGGlyphNode *) override;
+ bool visit(QSGNinePatchNode *) override;
+ void endVisit(QSGNinePatchNode *) override;
+ bool visit(QSGRootNode *) override;
+ void endVisit(QSGRootNode *) override;
+
+private:
+ bool addRenderableNode(QSGNode *node);
+
+ QSGAbstractSoftwareRenderer *m_renderer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWARERENDERLISTBUILDER_H
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp
new file mode 100644
index 0000000000..5292e1371f
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgsoftwarerenderloop_p.h"
+
+#include "qsgsoftwarecontext_p.h"
+
+#include <QtCore/QCoreApplication>
+
+#include <private/qquickwindow_p.h>
+#include <QElapsedTimer>
+#include <private/qquickprofiler_p.h>
+#include <private/qsgsoftwarerenderer_p.h>
+#include <qpa/qplatformbackingstore.h>
+
+#include <QtGui/QBackingStore>
+
+QT_BEGIN_NAMESPACE
+
+QSGSoftwareRenderLoop::QSGSoftwareRenderLoop()
+{
+ sg = new QSGSoftwareContext();
+ rc = sg->createRenderContext();
+}
+
+QSGSoftwareRenderLoop::~QSGSoftwareRenderLoop()
+{
+ delete rc;
+ delete sg;
+}
+
+void QSGSoftwareRenderLoop::show(QQuickWindow *window)
+{
+ WindowData data;
+ data.updatePending = false;
+ data.grabOnly = false;
+ m_windows[window] = data;
+
+ if (m_backingStores[window] == nullptr) {
+ m_backingStores[window] = new QBackingStore(window);
+ }
+
+ maybeUpdate(window);
+}
+
+void QSGSoftwareRenderLoop::hide(QQuickWindow *window)
+{
+ QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ cd->fireAboutToStop();
+}
+
+void QSGSoftwareRenderLoop::windowDestroyed(QQuickWindow *window)
+{
+ m_windows.remove(window);
+ delete m_backingStores[window];
+ m_backingStores.remove(window);
+ hide(window);
+
+ QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
+ d->cleanupNodesOnShutdown();
+
+ if (m_windows.size() == 0) {
+ rc->invalidate();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ }
+}
+
+void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window)
+{
+ QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ if (!m_windows.contains(window))
+ return;
+
+ WindowData &data = const_cast<WindowData &>(m_windows[window]);
+
+ //If were not in grabOnly mode, dont render a non-renderable window
+ if (!data.grabOnly && !cd->isRenderable())
+ return;
+
+ //Resize the backing store if necessary
+ if (m_backingStores[window]->size() != window->size()) {
+ m_backingStores[window]->resize(window->size());
+ }
+
+ // ### create QPainter and set up pointer to current window/painter
+ QSGSoftwareRenderContext *ctx = static_cast<QSGSoftwareRenderContext*>(cd->context);
+ ctx->initializeIfNeeded();
+
+ bool alsoSwap = data.updatePending;
+ data.updatePending = false;
+
+ if (!data.grabOnly) {
+ cd->flushFrameSynchronousEvents();
+ // Event delivery/processing triggered the window to be deleted or stop rendering.
+ if (!m_windows.contains(window))
+ return;
+ }
+ QElapsedTimer renderTimer;
+ qint64 renderTime = 0, syncTime = 0, polishTime = 0;
+ bool profileFrames = QSG_RASTER_LOG_TIME_RENDERLOOP().isDebugEnabled();
+ if (profileFrames)
+ renderTimer.start();
+ Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
+
+ cd->polishItems();
+
+ if (profileFrames)
+ polishTime = renderTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
+ QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ emit window->afterAnimating();
+
+ cd->syncSceneGraph();
+
+ if (profileFrames)
+ syncTime = renderTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ //Tell the renderer about the windows backing store
+ auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(cd->renderer);
+ if (softwareRenderer)
+ softwareRenderer->setCurrentPaintDevice(m_backingStores[window]->paintDevice());
+
+ m_backingStores[window]->beginPaint(QRect(0, 0, window->width(), window->height()));
+ cd->renderSceneGraph(window->size());
+ m_backingStores[window]->endPaint();
+
+ if (profileFrames)
+ renderTime = renderTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ if (data.grabOnly) {
+ grabContent = m_backingStores[window]->handle()->toImage();
+ data.grabOnly = false;
+ }
+
+ if (alsoSwap && window->isVisible()) {
+ //Flush backingstore to window
+ m_backingStores[window]->flush(softwareRenderer->flushRegion());
+ cd->fireFrameSwapped();
+ }
+
+ qint64 swapTime = 0;
+ if (profileFrames)
+ swapTime = renderTimer.nsecsElapsed();
+ Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame);
+
+ if (QSG_RASTER_LOG_TIME_RENDERLOOP().isDebugEnabled()) {
+ static QTime lastFrameTime = QTime::currentTime();
+ qCDebug(QSG_RASTER_LOG_TIME_RENDERLOOP,
+ "Frame rendered with 'basic' renderloop in %dms, polish=%d, sync=%d, render=%d, swap=%d, frameDelta=%d",
+ int(swapTime / 1000000),
+ int(polishTime / 1000000),
+ int((syncTime - polishTime) / 1000000),
+ int((renderTime - syncTime) / 1000000),
+ int((swapTime - renderTime) / 10000000),
+ int(lastFrameTime.msecsTo(QTime::currentTime())));
+ lastFrameTime = QTime::currentTime();
+ }
+
+ // Might have been set during syncSceneGraph()
+ if (data.updatePending)
+ maybeUpdate(window);
+}
+
+void QSGSoftwareRenderLoop::exposureChanged(QQuickWindow *window)
+{
+ if (window->isExposed()) {
+ m_windows[window].updatePending = true;
+ renderWindow(window);
+ }
+}
+
+QImage QSGSoftwareRenderLoop::grab(QQuickWindow *window)
+{
+ //If the window was never shown, create a new backing store
+ if (!m_backingStores.contains(window)) {
+ m_backingStores[window] = new QBackingStore(window);
+ // Call create on window to make sure platform window is created
+ window->create();
+ }
+
+ //If there is no WindowData, add one
+ if (!m_windows.contains(window)) {
+ WindowData data;
+ data.updatePending = false;
+ m_windows[window] = data;
+ }
+
+ m_windows[window].grabOnly = true;
+
+ renderWindow(window);
+
+ QImage grabbed = grabContent;
+ grabbed.detach();
+ grabContent = QImage();
+ return grabbed;
+}
+
+
+
+void QSGSoftwareRenderLoop::maybeUpdate(QQuickWindow *window)
+{
+ if (!m_windows.contains(window))
+ return;
+
+ m_windows[window].updatePending = true;
+ window->requestUpdate();
+}
+
+QSurface::SurfaceType QSGSoftwareRenderLoop::windowSurfaceType() const
+{
+ return QSurface::RasterSurface;
+}
+
+
+
+QSGContext *QSGSoftwareRenderLoop::sceneGraphContext() const
+{
+ return sg;
+}
+
+
+void QSGSoftwareRenderLoop::handleUpdateRequest(QQuickWindow *window)
+{
+ renderWindow(window);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop_p.h
new file mode 100644
index 0000000000..02dcf4eefa
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSOFTWARERENDERLOOP_H
+#define QSGSOFTWARERENDERLOOP_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgrenderloop_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBackingStore;
+
+class QSGSoftwareRenderLoop : public QSGRenderLoop
+{
+ Q_OBJECT
+public:
+ QSGSoftwareRenderLoop();
+ ~QSGSoftwareRenderLoop();
+
+ void show(QQuickWindow *window) override;
+ void hide(QQuickWindow *window) override;
+
+ void windowDestroyed(QQuickWindow *window) override;
+
+ void renderWindow(QQuickWindow *window);
+ void exposureChanged(QQuickWindow *window) override;
+ QImage grab(QQuickWindow *window) override;
+
+ void maybeUpdate(QQuickWindow *window) override;
+ void update(QQuickWindow *window) override { maybeUpdate(window); } // identical for this implementation.
+ void handleUpdateRequest(QQuickWindow *) override;
+
+ void releaseResources(QQuickWindow *) override { }
+
+ QSurface::SurfaceType windowSurfaceType() const override;
+
+ QAnimationDriver *animationDriver() const override { return 0; }
+
+ QSGContext *sceneGraphContext() const override;
+ QSGRenderContext *createRenderContext(QSGContext *) const override { return rc; }
+
+ struct WindowData {
+ bool updatePending : 1;
+ bool grabOnly : 1;
+ };
+
+ QHash<QQuickWindow *, WindowData> m_windows;
+ QHash<QQuickWindow *, QBackingStore *> m_backingStores;
+
+ QSGContext *sg;
+ QSGRenderContext *rc;
+
+ QImage grabContent;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGSOFTWARERENDERLOOP_H
diff --git a/src/quick/scenegraph/adaptations/software/software.pri b/src/quick/scenegraph/adaptations/software/software.pri
new file mode 100644
index 0000000000..b8cdbc4a25
--- /dev/null
+++ b/src/quick/scenegraph/adaptations/software/software.pri
@@ -0,0 +1,39 @@
+QT += gui-private core-private qml-private
+
+#DEFINES += QTQUICK2D_DEBUG_FLUSH
+
+SOURCES += \
+ $$PWD/qsgsoftwarecontext.cpp \
+ $$PWD/qsgabstractsoftwarerenderer.cpp \
+ $$PWD/qsgsoftwareglyphnode.cpp \
+ $$PWD/qsgsoftwareimagenode.cpp \
+ $$PWD/qsgsoftwareninepatchnode.cpp \
+ $$PWD/qsgsoftwarepainternode.cpp \
+ $$PWD/qsgsoftwarerectanglenode.cpp \
+ $$PWD/qsgsoftwarepixmaprenderer.cpp \
+ $$PWD/qsgsoftwarepixmaptexture.cpp \
+ $$PWD/qsgsoftwarerenderablenode.cpp \
+ $$PWD/qsgsoftwarerenderablenodeupdater.cpp \
+ $$PWD/qsgsoftwarerenderer.cpp \
+ $$PWD/qsgsoftwarerenderlistbuilder.cpp \
+ $$PWD/qsgsoftwarerenderloop.cpp \
+ $$PWD/qsgsoftwarelayer.cpp \
+ $$PWD/qsgsoftwareadaptation.cpp
+
+HEADERS += \
+ $$PWD/qsgsoftwarecontext_p.h \
+ $$PWD/qsgabstractsoftwarerenderer_p.h \
+ $$PWD/qsgsoftwareglyphnode_p.h \
+ $$PWD/qsgsoftwareimagenode_p.h \
+ $$PWD/qsgsoftwareninepatchnode_p.h \
+ $$PWD/qsgsoftwarepainternode_p.h \
+ $$PWD/qsgsoftwarepixmaprenderer_p.h \
+ $$PWD/qsgsoftwarepixmaptexture_p.h \
+ $$PWD/qsgsoftwarerectanglenode_p.h \
+ $$PWD/qsgsoftwarerenderablenode_p.h \
+ $$PWD/qsgsoftwarerenderablenodeupdater_p.h \
+ $$PWD/qsgsoftwarerenderer_p.h \
+ $$PWD/qsgsoftwarerenderlistbuilder_p.h \
+ $$PWD/qsgsoftwarerenderloop_p.h \
+ $$PWD/qsgsoftwarelayer_p.h \
+ $$PWD/qsgsoftwareadaptation_p.h
diff --git a/src/quick/scenegraph/coreapi/qsgabstractrenderer.h b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h
index d0a22c8c10..eb9e7cea7c 100644
--- a/src/quick/scenegraph/coreapi/qsgabstractrenderer.h
+++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h
@@ -42,6 +42,10 @@
#include <QtQuick/qsgnode.h>
+#ifndef GLuint
+#define GLuint uint
+#endif
+
QT_BEGIN_NAMESPACE
class QSGAbstractRendererPrivate;
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index d91004fbee..9501b3bb3e 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -154,8 +154,8 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material)
p->bindAttributeLocation(attr[i], i);
}
p->bindAttributeLocation("_qt_order", i);
- context->compile(s, material, qsgShaderRewriter_insertZAttributes(s->vertexShader(), profile), 0);
- context->initialize(s);
+ context->compileShader(s, material, qsgShaderRewriter_insertZAttributes(s->vertexShader(), profile), 0);
+ context->initializeShader(s);
if (!p->isLinked())
return 0;
@@ -188,8 +188,8 @@ ShaderManager::Shader *ShaderManager::prepareMaterialNoRewrite(QSGMaterial *mate
Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphContextFrame);
QSGMaterialShader *s = static_cast<QSGMaterialShader *>(material->createShader());
- context->compile(s, material);
- context->initialize(s);
+ context->compileShader(s, material);
+ context->initializeShader(s);
shader = new Shader();
shader->program = s;
@@ -356,17 +356,17 @@ void Updater::visitClipNode(Node *n)
if (m_roots.last() && m_added > 0)
renderer->registerBatchRoot(n, m_roots.last());
- cn->m_clip_list = m_current_clip;
+ cn->setRendererClipList(m_current_clip);
m_current_clip = cn;
m_roots << n;
m_rootMatrices.add(m_rootMatrices.last() * *m_combined_matrix_stack.last());
extra->matrix = m_rootMatrices.last();
- cn->m_matrix = &extra->matrix;
+ cn->setRendererMatrix(&extra->matrix);
m_combined_matrix_stack << &m_identityMatrix;
SHADOWNODE_TRAVERSE(n) visitNode(child);
- m_current_clip = cn->m_clip_list;
+ m_current_clip = cn->clipList();
m_rootMatrices.pop_back();
m_combined_matrix_stack.pop_back();
m_roots.pop_back();
@@ -459,8 +459,8 @@ void Updater::visitGeometryNode(Node *n)
{
QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(n->sgNode);
- gn->m_matrix = m_combined_matrix_stack.last();
- gn->m_clip_list = m_current_clip;
+ gn->setRendererMatrix(m_combined_matrix_stack.last());
+ gn->setRendererClipList(m_current_clip);
gn->setInheritedOpacity(m_opacity_stack.last());
if (m_added) {
@@ -746,8 +746,9 @@ static int qsg_countNodesInBatches(const QDataBuffer<Batch *> &batches)
return sum;
}
-Renderer::Renderer(QSGRenderContext *ctx)
+Renderer::Renderer(QSGDefaultRenderContext *ctx)
: QSGRenderer(ctx)
+ , m_context(ctx)
, m_opaqueRenderList(64)
, m_alphaRenderList(64)
, m_nextRenderOrder(0)
@@ -807,7 +808,7 @@ Renderer::Renderer(QSGRenderContext *ctx)
// If rendering with an OpenGL Core profile context, we need to create a VAO
// to hold our vertex specification state.
- if (context()->openglContext()->format().profile() == QSurfaceFormat::CoreProfile) {
+ if (m_context->openglContext()->format().profile() == QSurfaceFormat::CoreProfile) {
m_vao = new QOpenGLVertexArrayObject(this);
m_vao->create();
}
@@ -845,7 +846,7 @@ Renderer::~Renderer()
for (int i=0; i<m_batchPool.size(); ++i) qsg_wipeBatch(m_batchPool.at(i), this);
}
- foreach (Node *n, m_nodes.values())
+ for (Node *n : qAsConst(m_nodes))
m_nodeAllocator.release(n);
// Remaining elements...
@@ -1101,7 +1102,7 @@ void Renderer::nodeWasRemoved(Node *node)
if (m_renderNodeElements.isEmpty()) {
static bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER");
- m_useDepthBuffer = useDepth && context()->openglContext()->format().depthBufferSize() > 0;
+ m_useDepthBuffer = useDepth && m_context->openglContext()->format().depthBufferSize() > 0;
}
}
}
@@ -2760,6 +2761,21 @@ void Renderer::render()
m_vao->release();
}
+struct RenderNodeState : public QSGRenderNode::RenderState
+{
+ const QMatrix4x4 *projectionMatrix() const override { return m_projectionMatrix; }
+ QRect scissorRect() const { return m_scissorRect; }
+ bool scissorEnabled() const { return m_scissorEnabled; }
+ int stencilValue() const { return m_stencilValue; }
+ bool stencilEnabled() const { return m_stencilEnabled; }
+
+ const QMatrix4x4 *m_projectionMatrix;
+ QRect m_scissorRect;
+ bool m_scissorEnabled;
+ int m_stencilValue;
+ bool m_stencilEnabled;
+};
+
void Renderer::renderRenderNode(Batch *batch)
{
if (Q_UNLIKELY(debug_render()))
@@ -2771,24 +2787,25 @@ void Renderer::renderRenderNode(Batch *batch)
setActiveShader(0, 0);
QSGNode *clip = e->renderNode->parent();
- e->renderNode->m_clip_list = 0;
+ QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(e->renderNode);
+ rd->m_clip_list = 0;
while (clip != rootNode()) {
if (clip->type() == QSGNode::ClipNodeType) {
- e->renderNode->m_clip_list = static_cast<QSGClipNode *>(clip);
+ rd->m_clip_list = static_cast<QSGClipNode *>(clip);
break;
}
clip = clip->parent();
}
- updateClip(e->renderNode->m_clip_list, batch);
+ updateClip(rd->m_clip_list, batch);
- QSGRenderNode::RenderState state;
+ RenderNodeState state;
QMatrix4x4 pm = projectionMatrix();
- state.projectionMatrix = &pm;
- state.scissorEnabled = m_currentClipType & ScissorClip;
- state.stencilEnabled = m_currentClipType & StencilClip;
- state.scissorRect = m_currentScissorRect;
- state.stencilValue = m_currentStencilValue;
+ state.m_projectionMatrix = &pm;
+ state.m_scissorEnabled = m_currentClipType & ScissorClip;
+ state.m_stencilEnabled = m_currentClipType & StencilClip;
+ state.m_scissorRect = m_currentScissorRect;
+ state.m_stencilValue = m_currentStencilValue;
QSGNode *xform = e->renderNode->parent();
QMatrix4x4 matrix;
@@ -2804,13 +2821,13 @@ void Renderer::renderRenderNode(Batch *batch)
}
xform = xform->parent();
}
- e->renderNode->m_matrix = &matrix;
+ rd->m_matrix = &matrix;
QSGNode *opacity = e->renderNode->parent();
- e->renderNode->m_opacity = 1.0;
+ rd->m_opacity = 1.0;
while (opacity != rootNode()) {
if (opacity->type() == QSGNode::OpacityNodeType) {
- e->renderNode->m_opacity = static_cast<QSGOpacityNode *>(opacity)->combinedOpacity();
+ rd->m_opacity = static_cast<QSGOpacityNode *>(opacity)->combinedOpacity();
break;
}
opacity = opacity->parent();
@@ -2822,12 +2839,17 @@ void Renderer::renderRenderNode(Batch *batch)
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- e->renderNode->render(state);
+ QSGRenderNode::StateFlags changes = e->renderNode->changedStates();
- e->renderNode->m_matrix = 0;
- e->renderNode->m_clip_list = 0;
+ GLuint prevFbo = 0;
+ if (changes & QSGRenderNode::RenderTargetState)
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
+
+ e->renderNode->render(&state);
+
+ rd->m_matrix = 0;
+ rd->m_clip_list = 0;
- QSGRenderNode::StateFlags changes = e->renderNode->changedStates();
if (changes & QSGRenderNode::ViewportState) {
QRect r = viewportRect();
glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height());
@@ -2861,6 +2883,8 @@ void Renderer::renderRenderNode(Batch *batch)
glDisable(GL_CULL_FACE);
}
+ if (changes & QSGRenderNode::RenderTargetState)
+ glBindFramebuffer(GL_FRAMEBUFFER, prevFbo);
}
class VisualizeShader : public QOpenGLShaderProgram
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index 8bf4a13af6..01e517e65b 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -54,13 +54,15 @@
//
#include <private/qsgrenderer_p.h>
+#include <private/qsgdefaultrendercontext_p.h>
#include <private/qsgnodeupdater_p.h>
-#include <private/qdatabuffer_p.h>
-
#include <private/qsgrendernode_p.h>
+#include <private/qdatabuffer_p.h>
#include <QtCore/QBitArray>
+#include <QtGui/QOpenGLFunctions>
+
QT_BEGIN_NAMESPACE
class QOpenGLVertexArrayObject;
@@ -527,7 +529,7 @@ public:
float lastOpacity;
};
- ShaderManager(QSGRenderContext *ctx) : visualizeProgram(0), blitProgram(0), context(ctx) { }
+ ShaderManager(QSGDefaultRenderContext *ctx) : visualizeProgram(0), blitProgram(0), context(ctx) { }
~ShaderManager() {
qDeleteAll(rewrittenShaders);
qDeleteAll(stockShaders);
@@ -547,13 +549,13 @@ private:
QHash<QSGMaterialType *, Shader *> stockShaders;
QOpenGLShaderProgram *blitProgram;
- QSGRenderContext *context;
+ QSGDefaultRenderContext *context;
};
class Q_QUICK_PRIVATE_EXPORT Renderer : public QSGRenderer, public QOpenGLFunctions
{
public:
- Renderer(QSGRenderContext *);
+ Renderer(QSGDefaultRenderContext *);
~Renderer();
enum VisualizeMode {
@@ -637,6 +639,7 @@ private:
void visualizeDrawGeometry(const QSGGeometry *g);
void setCustomRenderMode(const QByteArray &mode) Q_DECL_OVERRIDE;
+ QSGDefaultRenderContext *m_context;
QSet<Node *> m_taggedRoots;
QDataBuffer<Element *> m_opaqueRenderList;
QDataBuffer<Element *> m_alphaRenderList;
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.cpp b/src/quick/scenegraph/coreapi/qsggeometry.cpp
index 5012f6a31b..7ec72a6e10 100644
--- a/src/quick/scenegraph/coreapi/qsggeometry.cpp
+++ b/src/quick/scenegraph/coreapi/qsggeometry.cpp
@@ -39,10 +39,11 @@
#include "qsggeometry.h"
#include "qsggeometry_p.h"
-
-#include <qopenglcontext.h>
-#include <qopenglfunctions.h>
-#include <private/qopenglextensions_p.h>
+#ifndef QT_NO_OPENGL
+# include <qopenglcontext.h>
+# include <qopenglfunctions.h>
+# include <private/qopenglextensions_p.h>
+#endif
#ifdef Q_OS_QNX
#include <malloc.h>
@@ -53,10 +54,21 @@ QT_BEGIN_NAMESPACE
QSGGeometry::Attribute QSGGeometry::Attribute::create(int attributeIndex, int tupleSize, int primitiveType, bool isPrimitive)
{
- Attribute a = { attributeIndex, tupleSize, primitiveType, isPrimitive, 0 };
+ Attribute a = { attributeIndex, tupleSize, primitiveType, isPrimitive, UNKNOWN, 0 };
return a;
}
+QSGGeometry::Attribute QSGGeometry::Attribute::createWithSemantic(int pos, int tupleSize, int type, Semantic semantic)
+{
+ Attribute a;
+ a.position = pos;
+ a.tupleSize = tupleSize;
+ a.type = type;
+ a.isVertexCoordinate = semantic == POSITION;
+ a.semantic = semantic;
+ a.reserved = 0;
+ return a;
+}
/*!
Convenience function which returns attributes to be used for 2D solid
@@ -66,7 +78,7 @@ QSGGeometry::Attribute QSGGeometry::Attribute::create(int attributeIndex, int tu
const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_Point2D()
{
static Attribute data[] = {
- QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true)
+ Attribute::createWithSemantic(0, 2, TypeFloat, Attribute::POSITION)
};
static AttributeSet attrs = { 1, sizeof(float) * 2, data };
return attrs;
@@ -79,8 +91,8 @@ const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_Point2D()
const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_TexturedPoint2D()
{
static Attribute data[] = {
- QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),
- QSGGeometry::Attribute::create(1, 2, GL_FLOAT)
+ Attribute::createWithSemantic(0, 2, TypeFloat, Attribute::POSITION),
+ Attribute::createWithSemantic(1, 2, TypeFloat, Attribute::TEXCOORD)
};
static AttributeSet attrs = { 2, sizeof(float) * 4, data };
return attrs;
@@ -93,8 +105,8 @@ const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_TexturedPoint2D(
const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_ColoredPoint2D()
{
static Attribute data[] = {
- QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),
- QSGGeometry::Attribute::create(1, 4, GL_UNSIGNED_BYTE)
+ Attribute::createWithSemantic(0, 2, TypeFloat, Attribute::POSITION),
+ Attribute::createWithSemantic(1, 4, TypeUnsignedByte, Attribute::COLOR)
};
static AttributeSet attrs = { 2, 2 * sizeof(float) + 4 * sizeof(char), data };
return attrs;
@@ -206,9 +218,9 @@ const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_ColoredPoint2D()
The QSGGeometry class stores the geometry of the primitives
rendered with the scene graph. It contains vertex data and
optionally index data. The mode used to draw the geometry is
- specified with setDrawingMode(), which maps directly to the OpenGL
+ specified with setDrawingMode(), which maps directly to the graphics API's
drawing mode, such as \c GL_TRIANGLE_STRIP, \c GL_TRIANGLES, or
- \c GL_POINTS.
+ \c GL_POINTS in case of OpenGL.
Vertices can be as simple as points defined by x and y values or
can be more complex where each vertex contains a normal, texture
@@ -394,7 +406,7 @@ QSGGeometry::QSGGeometry(const QSGGeometry::AttributeSet &attributes,
int vertexCount,
int indexCount,
int indexType)
- : m_drawing_mode(GL_TRIANGLE_STRIP)
+ : m_drawing_mode(DrawTriangleStrip)
, m_vertex_count(0)
, m_index_count(0)
, m_index_type(indexType)
@@ -410,21 +422,20 @@ QSGGeometry::QSGGeometry(const QSGGeometry::AttributeSet &attributes,
Q_UNUSED(m_reserved_bits);
Q_ASSERT(m_attributes.count > 0);
Q_ASSERT(m_attributes.stride > 0);
-
+#ifndef QT_NO_OPENGL
Q_ASSERT_X(indexType != GL_UNSIGNED_INT
|| static_cast<QOpenGLExtensions *>(QOpenGLContext::currentContext()->functions())
->hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint),
"QSGGeometry::QSGGeometry",
"GL_UNSIGNED_INT is not supported, geometry will not render"
);
-
- if (indexType != GL_UNSIGNED_BYTE
- && indexType != GL_UNSIGNED_SHORT
- && indexType != GL_UNSIGNED_INT) {
+#endif
+ if (indexType != TypeUnsignedByte
+ && indexType != TypeUnsignedShort
+ && indexType != TypeUnsignedInt) {
qFatal("QSGGeometry: Unsupported index type, %x.\n", indexType);
}
-
// Because allocate reads m_vertex_count, m_index_count and m_owns_data, these
// need to be set before calling allocate...
allocate(vertexCount, indexCount);
@@ -516,23 +527,63 @@ const void *QSGGeometry::indexData() const
}
/*!
+ \enum QSGGeometry::DrawingMode
+
+ The values correspond to OpenGL enum values like \c GL_POINTS, \c GL_LINES,
+ etc. QSGGeometry provies its own type in order to be able to provide the
+ same API with non-OpenGL backends as well.
+
+ \value DrawPoints
+ \value DrawLines
+ \value DrawLineLoop
+ \value DrawLineStrip
+ \value DrawTriangles
+ \value DrawTriangleStrip
+ \value DrawTriangleFan
+ */
+
+/*!
+ \enum QSGGeometry::Type
+
+ The values correspond to OpenGL type constants like \c GL_BYTE, \c
+ GL_UNSIGNED_BYTE, etc. QSGGeometry provies its own type in order to be able
+ to provide the same API with non-OpenGL backends as well.
+
+ \value TypeByte
+ \value TypeUnsignedByte
+ \value TypeShort
+ \value TypeUnsignedShort
+ \value TypeInt
+ \value TypeUnsignedInt
+ \value TypeFloat
+ */
+
+/*!
Sets the \a mode to be used for drawing this geometry.
- The default value is \c GL_TRIANGLE_STRIP.
+ The default value is QSGGeometry::DrawTriangleStrip.
+
+ \sa DrawingMode
*/
-void QSGGeometry::setDrawingMode(GLenum mode)
+void QSGGeometry::setDrawingMode(unsigned int mode)
{
m_drawing_mode = mode;
}
/*!
- Gets the current line or point width or to be used for this geometry. This property
- only applies to line width when the drawingMode is \c GL_LINES, \c GL_LINE_STRIP, or
- \c GL_LINE_LOOP. For desktop OpenGL, it also applies to point size when the drawingMode
- is \c GL_POINTS.
+ Gets the current line or point width or to be used for this geometry. This
+ property only applies to line width when the drawingMode is DrawLines,
+ DarwLineStrip, or DrawLineLoop. For desktop OpenGL, it also applies to
+ point size when the drawingMode is DrawPoints.
The default value is \c 1.0
+ \note When not using OpenGL, support for point and line drawing may be
+ limited. For example, some APIs do not support point sprites and so setting
+ a size other than 1 is not possible. Some backends may be able implement
+ support via geometry shaders, but this is not guaranteed to be always
+ available.
+
\sa setLineWidth(), drawingMode()
*/
float QSGGeometry::lineWidth() const
@@ -541,14 +592,15 @@ float QSGGeometry::lineWidth() const
}
/*!
- Sets the line or point width to be used for this geometry to \a width. This property
- only applies to line width when the drawingMode is \c GL_LINES, \c GL_LINE_STRIP, or
- \c GL_LINE_LOOP. For Desktop OpenGL, it also applies to point size when the drawingMode
- is \c GL_POINTS.
+ Sets the line or point width to be used for this geometry to \a width. This
+ property only applies to line width when the drawingMode is DrawLines,
+ DrawLineStrip, or DrawLineLoop. For Desktop OpenGL, it also applies to
+ point size when the drawingMode is DrawPoints.
- \note How line width and point size are treated is implementation dependent: The application
- should not rely on these, but rather create triangles or similar to draw areas. On OpenGL ES,
- line width support is limited and point size is unsupported.
+ \note How line width and point size are treated is implementation
+ dependent: The application should not rely on these, but rather create
+ triangles or similar to draw areas. On OpenGL ES, line width support is
+ limited and point size is unsupported.
\sa lineWidth(), drawingMode()
*/
@@ -601,8 +653,8 @@ void QSGGeometry::allocate(int vertexCount, int indexCount)
m_index_data_offset = -1;
m_owns_data = false;
} else {
- Q_ASSERT(m_index_type == GL_UNSIGNED_INT || m_index_type == GL_UNSIGNED_SHORT);
- int indexByteSize = indexCount * (m_index_type == GL_UNSIGNED_SHORT ? sizeof(quint16) : sizeof(quint32));
+ Q_ASSERT(m_index_type == TypeUnsignedInt || m_index_type == TypeUnsignedShort);
+ int indexByteSize = indexCount * (m_index_type == TypeUnsignedShort ? sizeof(quint16) : sizeof(quint32));
m_data = (void *) malloc(vertexByteSize + indexByteSize);
m_index_data_offset = vertexByteSize;
m_owns_data = true;
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.h b/src/quick/scenegraph/coreapi/qsggeometry.h
index 5773b6abd1..1f54b7d81b 100644
--- a/src/quick/scenegraph/coreapi/qsggeometry.h
+++ b/src/quick/scenegraph/coreapi/qsggeometry.h
@@ -54,15 +54,27 @@ public:
struct Q_QUICK_EXPORT Attribute
{
+ enum Semantic {
+ UNKNOWN,
+ POSITION,
+ COLOR,
+ TEXCOORD,
+ TEXCOORD1,
+ TEXCOORD2
+ };
+
int position;
int tupleSize;
int type;
uint isVertexCoordinate : 1;
- uint reserved : 31;
+ Semantic semantic : 4;
+
+ uint reserved : 27;
static Attribute create(int pos, int tupleSize, int primitiveType, bool isPosition = false);
+ static Attribute createWithSemantic(int pos, int tupleSize, int type, Semantic semantic);
};
struct AttributeSet {
@@ -104,14 +116,37 @@ public:
StaticPattern = 3
};
+ // Equivalents to GL_* drawing modes.
+ enum DrawingMode {
+ DrawPoints = 0x0000,
+ DrawLines = 0x0001,
+ DrawLineLoop = 0x0002,
+ DrawLineStrip = 0x0003,
+ DrawTriangles = 0x0004,
+ DrawTriangleStrip = 0x0005,
+ DrawTriangleFan = 0x0006
+ };
+
+ // Equivalents to GL_BYTE and similar type constants.
+ enum Type {
+ TypeByte = 0x1400,
+ TypeUnsignedByte = 0x1401,
+ TypeShort = 0x1402,
+ TypeUnsignedShort = 0x1403,
+ TypeInt = 0x1404,
+ TypeUnsignedInt = 0x1405,
+ TypeFloat = 0x1406
+ };
+
QSGGeometry(const QSGGeometry::AttributeSet &attribs,
int vertexCount,
int indexCount = 0,
- int indexType = GL_UNSIGNED_SHORT);
+ int indexType = TypeUnsignedShort);
virtual ~QSGGeometry();
- void setDrawingMode(GLenum mode);
- inline GLenum drawingMode() const { return m_drawing_mode; }
+ // must use unsigned int to be compatible with the old GLenum to keep BC
+ void setDrawingMode(unsigned int mode);
+ inline unsigned int drawingMode() const { return m_drawing_mode; }
void allocate(int vertexCount, int indexCount = 0);
@@ -187,25 +222,25 @@ private:
inline uint *QSGGeometry::indexDataAsUInt()
{
- Q_ASSERT(m_index_type == GL_UNSIGNED_INT);
+ Q_ASSERT(m_index_type == TypeUnsignedInt);
return static_cast<uint *>(indexData());
}
inline quint16 *QSGGeometry::indexDataAsUShort()
{
- Q_ASSERT(m_index_type == GL_UNSIGNED_SHORT);
+ Q_ASSERT(m_index_type == TypeUnsignedShort);
return static_cast<quint16 *>(indexData());
}
inline const uint *QSGGeometry::indexDataAsUInt() const
{
- Q_ASSERT(m_index_type == GL_UNSIGNED_INT);
+ Q_ASSERT(m_index_type == TypeUnsignedInt);
return static_cast<const uint *>(indexData());
}
inline const quint16 *QSGGeometry::indexDataAsUShort() const
{
- Q_ASSERT(m_index_type == GL_UNSIGNED_SHORT);
+ Q_ASSERT(m_index_type == TypeUnsignedShort);
return static_cast<const quint16 *>(indexData());
}
@@ -214,7 +249,7 @@ inline QSGGeometry::Point2D *QSGGeometry::vertexDataAsPoint2D()
Q_ASSERT(m_attributes.count == 1);
Q_ASSERT(m_attributes.stride == 2 * sizeof(float));
Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].type == TypeFloat);
Q_ASSERT(m_attributes.attributes[0].position == 0);
return static_cast<Point2D *>(m_data);
}
@@ -225,10 +260,10 @@ inline QSGGeometry::TexturedPoint2D *QSGGeometry::vertexDataAsTexturedPoint2D()
Q_ASSERT(m_attributes.stride == 4 * sizeof(float));
Q_ASSERT(m_attributes.attributes[0].position == 0);
Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].type == TypeFloat);
Q_ASSERT(m_attributes.attributes[1].position == 1);
Q_ASSERT(m_attributes.attributes[1].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[1].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].type == TypeFloat);
return static_cast<TexturedPoint2D *>(m_data);
}
@@ -238,10 +273,10 @@ inline QSGGeometry::ColoredPoint2D *QSGGeometry::vertexDataAsColoredPoint2D()
Q_ASSERT(m_attributes.stride == 2 * sizeof(float) + 4 * sizeof(char));
Q_ASSERT(m_attributes.attributes[0].position == 0);
Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].type == TypeFloat);
Q_ASSERT(m_attributes.attributes[1].position == 1);
Q_ASSERT(m_attributes.attributes[1].tupleSize == 4);
- Q_ASSERT(m_attributes.attributes[1].type == GL_UNSIGNED_BYTE);
+ Q_ASSERT(m_attributes.attributes[1].type == TypeUnsignedByte);
return static_cast<ColoredPoint2D *>(m_data);
}
@@ -250,7 +285,7 @@ inline const QSGGeometry::Point2D *QSGGeometry::vertexDataAsPoint2D() const
Q_ASSERT(m_attributes.count == 1);
Q_ASSERT(m_attributes.stride == 2 * sizeof(float));
Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].type == TypeFloat);
Q_ASSERT(m_attributes.attributes[0].position == 0);
return static_cast<const Point2D *>(m_data);
}
@@ -261,10 +296,10 @@ inline const QSGGeometry::TexturedPoint2D *QSGGeometry::vertexDataAsTexturedPoin
Q_ASSERT(m_attributes.stride == 4 * sizeof(float));
Q_ASSERT(m_attributes.attributes[0].position == 0);
Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].type == TypeFloat);
Q_ASSERT(m_attributes.attributes[1].position == 1);
Q_ASSERT(m_attributes.attributes[1].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[1].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].type == TypeFloat);
return static_cast<const TexturedPoint2D *>(m_data);
}
@@ -274,18 +309,18 @@ inline const QSGGeometry::ColoredPoint2D *QSGGeometry::vertexDataAsColoredPoint2
Q_ASSERT(m_attributes.stride == 2 * sizeof(float) + 4 * sizeof(char));
Q_ASSERT(m_attributes.attributes[0].position == 0);
Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
- Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].type == TypeFloat);
Q_ASSERT(m_attributes.attributes[1].position == 1);
Q_ASSERT(m_attributes.attributes[1].tupleSize == 4);
- Q_ASSERT(m_attributes.attributes[1].type == GL_UNSIGNED_BYTE);
+ Q_ASSERT(m_attributes.attributes[1].type == TypeUnsignedByte);
return static_cast<const ColoredPoint2D *>(m_data);
}
int QSGGeometry::sizeOfIndex() const
{
- if (m_index_type == GL_UNSIGNED_SHORT) return 2;
- else if (m_index_type == GL_UNSIGNED_BYTE) return 1;
- else if (m_index_type == GL_UNSIGNED_INT) return 4;
+ if (m_index_type == TypeUnsignedShort) return 2;
+ else if (m_index_type == TypeUnsignedByte) return 1;
+ else if (m_index_type == TypeUnsignedInt) return 4;
return 0;
}
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
index ceb53d0d14..42a4c4abd3 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
@@ -40,7 +40,13 @@
#include "qsgmaterial.h"
#include "qsgrenderer_p.h"
#include "qsgmaterialshader_p.h"
-#include <private/qsgshadersourcebuilder_p.h>
+#ifndef QT_NO_OPENGL
+# include <private/qsgshadersourcebuilder_p.h>
+# include <private/qsgdefaultcontext_p.h>
+# include <private/qsgdefaultrendercontext_p.h>
+# include <QtGui/QOpenGLFunctions>
+# include <QtGui/QOpenGLContext>
+#endif
QT_BEGIN_NAMESPACE
@@ -58,7 +64,7 @@ void qsg_set_material_failure()
qsg_material_failure = true;
}
#endif
-
+#ifndef QT_NO_OPENGL
const char *QSGMaterialShaderPrivate::loadShaderSource(QOpenGLShader::ShaderType type) const
{
QStringList files = m_sourceFiles[type];
@@ -68,6 +74,7 @@ const char *QSGMaterialShaderPrivate::loadShaderSource(QOpenGLShader::ShaderType
m_sources[type] = builder.source();
return m_sources[type].constData();
}
+#endif
#ifndef QT_NO_DEBUG
static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK");
@@ -220,7 +227,7 @@ QSGMaterialShader::~QSGMaterialShader()
defines the attribute register position in the vertex shader.
*/
-
+#ifndef QT_NO_OPENGL
/*!
\fn const char *QSGMaterialShader::vertexShader() const
@@ -256,7 +263,7 @@ const char *QSGMaterialShader::fragmentShader() const
Returns the shader program used by this QSGMaterialShader.
*/
-
+#endif
/*!
\fn void QSGMaterialShader::initialize()
@@ -313,6 +320,7 @@ void QSGMaterialShader::updateState(const RenderState & /* state */, QSGMaterial
{
}
+#ifndef QT_NO_OPENGL
/*!
Sets the GLSL source file for the shader stage \a type to \a sourceFile. The
default implementation of the vertexShader() and fragmentShader() functions
@@ -388,7 +396,7 @@ void QSGMaterialShader::compile()
}
}
-
+#endif
/*!
\class QSGMaterialShader::RenderState
@@ -542,7 +550,7 @@ QRect QSGMaterialShader::RenderState::deviceRect() const
return static_cast<const QSGRenderer *>(m_data)->deviceRect();
}
-
+#ifndef QT_NO_OPENGL
/*!
Returns the QOpenGLContext that is being used for rendering
@@ -550,9 +558,15 @@ QRect QSGMaterialShader::RenderState::deviceRect() const
QOpenGLContext *QSGMaterialShader::RenderState::context() const
{
- return static_cast<const QSGRenderer *>(m_data)->context()->openglContext();
+ // Only the QSGDefaultRenderContext will have an OpenGL Context to query
+ auto openGLRenderContext = static_cast<const QSGDefaultRenderContext *>(static_cast<const QSGRenderer *>(m_data)->context());
+ if (openGLRenderContext != nullptr)
+ return openGLRenderContext->openglContext();
+ else
+ return nullptr;
}
+#endif
#ifndef QT_NO_DEBUG
static int qt_material_count = 0;
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.h b/src/quick/scenegraph/coreapi/qsgmaterial.h
index 0a6a340092..114651653f 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.h
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.h
@@ -41,7 +41,11 @@
#define QSGMATERIAL_H
#include <QtQuick/qtquickglobal.h>
-#include <QtGui/qopenglshaderprogram.h>
+#ifndef QT_NO_OPENGL
+# include <QtGui/qopenglshaderprogram.h>
+#endif
+#include <QtGui/QMatrix4x4>
+#include <QtCore/QRect>
QT_BEGIN_NAMESPACE
@@ -59,8 +63,10 @@ public:
public:
enum DirtyState
{
- DirtyMatrix = 0x0001,
- DirtyOpacity = 0x0002
+ DirtyMatrix = 0x0001,
+ DirtyOpacity = 0x0002,
+ DirtyCachedMaterialData = 0x0004,
+ DirtyAll = 0xFFFF
};
Q_DECLARE_FLAGS(DirtyStates, DirtyState)
@@ -68,6 +74,7 @@ public:
inline bool isMatrixDirty() const { return m_dirty & DirtyMatrix; }
inline bool isOpacityDirty() const { return m_dirty & DirtyOpacity; }
+ bool isCachedMaterialDataDirty() const { return m_dirty & DirtyCachedMaterialData; }
float opacity() const;
QMatrix4x4 combinedMatrix() const;
@@ -77,9 +84,9 @@ public:
QRect deviceRect() const;
float determinant() const;
float devicePixelRatio() const;
-
+#ifndef QT_NO_OPENGL
QOpenGLContext *context() const;
-
+#endif
private:
friend class QSGRenderer;
DirtyStates m_dirty;
@@ -94,27 +101,30 @@ public:
// First time a material is used, oldMaterial is null.
virtual void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial);
virtual char const *const *attributeNames() const = 0; // Array must end with null.
-
+#ifndef QT_NO_OPENGL
inline QOpenGLShaderProgram *program() { return &m_program; }
-
+#endif
protected:
Q_DECLARE_PRIVATE(QSGMaterialShader)
QSGMaterialShader(QSGMaterialShaderPrivate &dd);
- friend class QSGRenderContext;
+ friend class QSGDefaultRenderContext;
friend class QSGBatchRenderer::ShaderManager;
-
+#ifndef QT_NO_OPENGL
void setShaderSourceFile(QOpenGLShader::ShaderType type, const QString &sourceFile);
void setShaderSourceFiles(QOpenGLShader::ShaderType type, const QStringList &sourceFiles);
virtual void compile();
+#endif
virtual void initialize() { }
-
+#ifndef QT_NO_OPENGL
virtual const char *vertexShader() const;
virtual const char *fragmentShader() const;
-
+#endif
private:
+#ifndef QT_NO_OPENGL
QOpenGLShaderProgram m_program;
+#endif
QScopedPointer<QSGMaterialShaderPrivate> d_ptr;
};
diff --git a/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h b/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h
index 291c0cc57c..0dbce010db 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h
+++ b/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h
@@ -59,10 +59,12 @@ QT_BEGIN_NAMESPACE
class Q_QUICK_PRIVATE_EXPORT QSGMaterialShaderPrivate
{
public:
+#ifndef QT_NO_OPENGL
const char *loadShaderSource(QOpenGLShader::ShaderType type) const;
QHash<QOpenGLShader::ShaderType, QStringList> m_sourceFiles;
mutable QHash<QOpenGLShader::ShaderType, QByteArray> m_sources;
+#endif
};
#ifndef QT_NO_DEBUG
diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp
index 53798f0e07..92f783d500 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnode.cpp
@@ -778,6 +778,18 @@ QSGBasicGeometryNode::~QSGBasicGeometryNode()
\internal
*/
+/*!
+ \fn void QSGBasicGeometryNode::setRendererMatrix(const QMatrix4x4 *m)
+
+ \internal
+ */
+
+/*!
+ \fn void QSGBasicGeometryNode::setRendererClipList(const QSGClipNode *c)
+
+ \internal
+ */
+
/*!
Sets the geometry of this node to \a geometry.
@@ -1472,15 +1484,15 @@ QDebug operator<<(QDebug d, const QSGGeometryNode *n)
} else {
switch (g->drawingMode()) {
- case GL_TRIANGLE_STRIP: d << "strip"; break;
- case GL_TRIANGLE_FAN: d << "fan"; break;
- case GL_TRIANGLES: d << "triangles"; break;
+ case QSGGeometry::DrawTriangleStrip: d << "strip"; break;
+ case QSGGeometry::DrawTriangleFan: d << "fan"; break;
+ case QSGGeometry::DrawTriangles: d << "triangles"; break;
default: break;
}
d << "#V:" << g->vertexCount() << "#I:" << g->indexCount();
- if (g->attributeCount() > 0 && g->attributes()->type == GL_FLOAT) {
+ if (g->attributeCount() > 0 && g->attributes()->type == QSGGeometry::TypeFloat) {
float x1 = 1e10, x2 = -1e10, y1=1e10, y2=-1e10;
int stride = g->sizeOfVertex();
for (int i = 0; i < g->vertexCount(); ++i) {
diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h
index 9d14ae04df..f7ea6dbe23 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.h
+++ b/src/quick/scenegraph/coreapi/qsgnode.h
@@ -79,8 +79,8 @@ public:
OpacityNodeType,
#ifndef qdoc
RootNodeType,
- RenderNodeType
#endif
+ RenderNodeType
};
enum Flag {
@@ -204,13 +204,15 @@ public:
const QMatrix4x4 *matrix() const { return m_matrix; }
const QSGClipNode *clipList() const { return m_clip_list; }
+ void setRendererMatrix(const QMatrix4x4 *m) { m_matrix = m; }
+ void setRendererClipList(const QSGClipNode *c) { m_clip_list = c; }
+
protected:
QSGBasicGeometryNode(NodeType type);
QSGBasicGeometryNode(QSGBasicGeometryNodePrivate &dd, NodeType type);
private:
friend class QSGNodeUpdater;
- friend class QSGBatchRenderer::Updater;
QSGGeometry *m_geometry;
diff --git a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
index 372ffce9d6..d6d533307e 100644
--- a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
@@ -175,9 +175,10 @@ void QSGNodeUpdater::enterRenderNode(QSGRenderNode *r)
qDebug() << "enter render:" << r;
#endif
- r->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.last();
- r->m_clip_list = m_current_clip;
- r->setInheritedOpacity(m_opacity_stack.last());
+ QSGRenderNodePrivate *rd = QSGRenderNodePrivate::get(r);
+ rd->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.last();
+ rd->m_clip_list = m_current_clip;
+ rd->m_opacity = m_opacity_stack.last();
}
void QSGNodeUpdater::leaveRenderNode(QSGRenderNode *r)
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
index ace10661c0..220e6ab212 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
@@ -39,11 +39,15 @@
#include "qsgrenderer_p.h"
#include "qsgnodeupdater_p.h"
-
-#include <qopenglframebufferobject.h>
-
+#ifndef QT_NO_OPENGL
+# include <QtGui/QOpenGLFramebufferObject>
+# include <QtGui/QOpenGLContext>
+# include <QtGui/QOpenGLFunctions>
+#endif
#include <private/qquickprofiler_p.h>
+#include <QtCore/QElapsedTimer>
+
QT_BEGIN_NAMESPACE
static const bool qsg_sanity_check = qEnvironmentVariableIntValue("QSG_SANITY_CHECK");
@@ -63,19 +67,25 @@ int qt_sg_envInt(const char *name, int defaultValue)
void QSGBindable::clear(QSGAbstractRenderer::ClearMode mode) const
{
+#ifndef QT_NO_OPENGL
GLuint bits = 0;
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);
+#else
+ Q_UNUSED(mode)
+#endif
}
// Reactivate the color buffer after switching to the stencil.
void QSGBindable::reactivate() const
{
+#ifndef QT_NO_OPENGL
QOpenGLContext::currentContext()->functions()->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+#endif
}
-
+#ifndef QT_NO_OPENGL
QSGBindableFboId::QSGBindableFboId(GLuint id)
: m_id(id)
{
@@ -86,7 +96,7 @@ void QSGBindableFboId::bind() const
{
QOpenGLContext::currentContext()->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_id);
}
-
+#endif
/*!
\class QSGRenderer
\brief The renderer class is the abstract baseclass use for rendering the
@@ -169,8 +179,9 @@ bool QSGRenderer::isMirrored() const
return matrix(0, 0) * matrix(1, 1) - matrix(0, 1) * matrix(1, 0) > 0;
}
-void QSGRenderer::renderScene(GLuint fboId)
+void QSGRenderer::renderScene(uint fboId)
{
+#ifndef QT_NO_OPENGL
if (fboId) {
QSGBindableFboId bindable(fboId);
renderScene(bindable);
@@ -182,7 +193,11 @@ void QSGRenderer::renderScene(GLuint fboId)
} bindable;
renderScene(bindable);
}
+#else
+ Q_UNUSED(fboId)
+#endif
}
+
void QSGRenderer::renderScene(const QSGBindable &bindable)
{
if (!rootNode())
@@ -207,6 +222,7 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
bindTime = frameTimer.nsecsElapsed();
Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame);
+#ifndef QT_NO_OPENGL
// Sanity check that attribute registers are disabled
if (qsg_sanity_check) {
GLint count = 0;
@@ -219,6 +235,7 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
}
}
}
+#endif
render();
if (profileFrames)
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
index 5c7a32c161..94b78a85b4 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
@@ -86,14 +86,12 @@ public:
bool isMirrored() const;
void renderScene(const QSGBindable &bindable);
- virtual void renderScene(GLuint fboId = 0) Q_DECL_OVERRIDE;
+ virtual void renderScene(uint fboId = 0) 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;
-
virtual void setCustomRenderMode(const QByteArray &) { };
void clearChangedFlag() { m_changed_emitted = false; }
@@ -135,7 +133,7 @@ public:
virtual void clear(QSGAbstractRenderer::ClearMode mode) const;
virtual void reactivate() const;
};
-
+#ifndef QT_NO_OPENGL
class QSGBindableFboId : public QSGBindable
{
public:
@@ -144,7 +142,7 @@ public:
private:
GLuint m_id;
};
-
+#endif
QSGMaterialShader::RenderState QSGRenderer::state(QSGMaterialShader::RenderState::DirtyStates dirty) const
diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp
new file mode 100644
index 0000000000..ffde9d8930
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgrendererinterface.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGRendererInterface
+ \brief An interface providing access to some of the graphics API specific internals
+ of the scenegraph.
+ \inmodule QtQuick
+ \since 5.8
+
+ Renderer interfaces allow accessing graphics API specific functionality in
+ the scenegraph. Such internals are not typically exposed. However, when
+ integrating custom rendering via QSGRenderNode for example, it may become
+ necessary to query certain values, for instance the graphics device (e.g.
+ the Direct3D or Vulkan device) that is used by the scenegraph.
+
+ \note QSGRendererInterface is only available after the scenegraph is
+ initialized. Additionally, there may be backend-specific limitations on
+ when the functions can be called. The only way that is guaranteed to
+ succeed is calling them when the rendering of a node (i.e. the preparation
+ of the command list for the next frame) is active. In practice this
+ typically means QSGRenderNode::render().
+ */
+
+/*!
+ \enum QSGRendererInterface::GraphicsApi
+ \value Unknown An unknown graphics API is in use
+ \value Software The Qt Quick 2D Renderer is in use
+ \value OpenGL OpenGL ES 2.0 or higher
+ \value Direct3D12 Direct3D 12
+ \value Vulkan Vulkan
+ \value Metal Metal
+ */
+
+/*!
+ \enum QSGRendererInterface::Resource
+ \value Device The graphics device
+ \value CommandQueue The graphics command queue used by the scenergaph
+ \value CommandList The command list or buffer used by the scenegraph
+ */
+
+QSGRendererInterface::~QSGRendererInterface()
+{
+}
+
+/*!
+ \fn QSGRendererInterface::GraphicsApi QSGRendererInterface::graphicsApi() const
+
+ Returns the graphics API that is in use by the Qt Quick scenegraph.
+
+ \note This function can be called on any thread. However, the renderer
+ interface's lifetime may be tied to the render thread and therefore calling
+ this function from other threads during the process of application shutdown
+ or QQuickWindow closing is likely to become invalid.
+ */
+
+/*!
+ Queries a graphics \a resource. Returns null when the resource in question is
+ not supported or not available.
+
+ When successful, the returned pointer is either a direct pointer to an
+ interface (and can be cast, for example, to \c{ID3D12Device *}) or a
+ pointer to an opaque handle that needs to be dereferenced first (for
+ example, \c{VkDevice dev = *static_cast<VkDevice *>(result)}). The latter
+ is necessary since such handles may have sizes different from a pointer.
+
+ \note This function must only be called on the render thread.
+ */
+void *QSGRendererInterface::getResource(Resource resource) const
+{
+ Q_UNUSED(resource);
+ return nullptr;
+}
+
+/*!
+ Queries a graphics resource. \a resource is a backend-specific key. This
+ allows supporting any future resources that are not listed in the
+ Resource enum.
+
+ \note This function must only be called on the render thread.
+ */
+void *QSGRendererInterface::getResource(const char *resource) const
+{
+ Q_UNUSED(resource);
+ return nullptr;
+}
+
+/*!
+ \fn QSGRendererInterface::ShaderType QSGRendererInterface::shaderType() const
+
+ \return the shading language supported by the Qt Quick backend the
+ application is using.
+
+ \note This function can be called on any thread. However, the renderer
+ interface's lifetime may be tied to the render thread and therefore calling
+ this function from other threads during the process of application shutdown
+ or QQuickWindow closing is likely to become invalid.
+
+ \sa QtQuick::GraphicsInfo
+ */
+
+/*!
+ \fn QSGRendererInterface::ShaderCompilationTypes QSGRendererInterface::shaderCompilationType() const
+
+ \return a bitmask of the shader compilation approaches supported by the Qt
+ Quick backend the application is using.
+
+ \note This function can be called on any thread. However, the renderer
+ interface's lifetime may be tied to the render thread and therefore calling
+ this function from other threads during the process of application shutdown
+ or QQuickWindow closing is likely to become invalid.
+
+ \sa QtQuick::GraphicsInfo
+ */
+
+/*!
+ \fn QSGRendererInterface::ShaderSourceTypes QSGRendererInterface::shaderSourceType() const
+
+ \return a bitmask of the supported ways of providing shader sources.
+
+ \note This function can be called on any thread. However, the renderer
+ interface's lifetime may be tied to the render thread and therefore calling
+ this function from other threads during the process of application shutdown
+ or QQuickWindow closing is likely to become invalid.
+
+ \sa QtQuick::GraphicsInfo
+ */
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.h b/src/quick/scenegraph/coreapi/qsgrendererinterface.h
new file mode 100644
index 0000000000..234a061d0e
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGRENDERERINTERFACE_H
+#define QSGRENDERERINTERFACE_H
+
+#include <QtQuick/qsgnode.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_EXPORT QSGRendererInterface
+{
+public:
+ enum GraphicsApi {
+ Unknown,
+ Software,
+ OpenGL,
+ Direct3D12
+ };
+
+ enum Resource {
+ Device,
+ CommandQueue,
+ CommandList
+ };
+
+ enum ShaderType {
+ UnknownShadingLanguage,
+ GLSL,
+ HLSL
+ };
+
+ enum ShaderCompilationType {
+ RuntimeCompilation = 0x01,
+ OfflineCompilation = 0x02
+ };
+ Q_DECLARE_FLAGS(ShaderCompilationTypes, ShaderCompilationType)
+
+ enum ShaderSourceType {
+ ShaderSourceString = 0x01,
+ ShaderSourceFile = 0x02,
+ ShaderByteCode = 0x04
+ };
+ Q_DECLARE_FLAGS(ShaderSourceTypes, ShaderSourceType)
+
+ virtual ~QSGRendererInterface();
+
+ virtual GraphicsApi graphicsApi() const = 0;
+
+ virtual void *getResource(Resource resource) const;
+ virtual void *getResource(const char *resource) const;
+
+ virtual ShaderType shaderType() const = 0;
+ virtual ShaderCompilationTypes shaderCompilationType() const = 0;
+ virtual ShaderSourceTypes shaderSourceType() const = 0;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRendererInterface::ShaderCompilationTypes)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRendererInterface::ShaderSourceTypes)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
index 1a38f6495e..6c61b35aa1 100644
--- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
@@ -37,28 +37,51 @@
**
****************************************************************************/
+#include "qsgrendernode.h"
#include "qsgrendernode_p.h"
QT_BEGIN_NAMESPACE
+/*!
+ \class QSGRenderNode
+ \brief The QSGMaterialShader class represents a set of custom rendering commands
+ targeting the graphics API that is in use by the scenegraph.
+ \inmodule QtQuick
+ \since 5.8
+ */
+
QSGRenderNode::QSGRenderNode()
- : QSGNode(RenderNodeType)
- , m_matrix(0)
- , m_clip_list(0)
- , m_opacity(1)
+ : QSGNode(RenderNodeType),
+ d(new QSGRenderNodePrivate)
{
}
-void QSGRenderNode::setInheritedOpacity(qreal opacity)
+/*!
+ Destructs the render node. Derived classes are expected to perform cleanup
+ similar to releaseResources() in here.
+
+ When a low-level graphics API is in use, the scenegraph will make sure
+ there is a CPU-side wait for the GPU to complete all work submitted to the
+ scenegraph's graphics command queue before the scenegraph's nodes are
+ deleted. Therefore there is no need to issue additional waits here, unless
+ the render() implementation is using additional command queues.
+
+ \sa releaseResources()
+ */
+QSGRenderNode::~QSGRenderNode()
{
- Q_ASSERT(opacity >= 0 && opacity <= 1);
- m_opacity = opacity;
+ delete d;
}
-/*!
- \fn QSGRenderNode::StateFlags QSGRenderNode::changedStates()
+QSGRenderNodePrivate::QSGRenderNodePrivate()
+ : m_matrix(0)
+ , m_clip_list(0)
+ , m_opacity(1)
+{
+}
- This function should return a mask where each bit represents OpenGL states changed by
+/*!
+ This function should return a mask where each bit represents graphics states changed by
the \l render() function:
\list
\li DepthState - depth write mask, depth test enabled, depth comparison function
@@ -69,30 +92,72 @@ void QSGRenderNode::setInheritedOpacity(qreal opacity)
\li BlendState - blend enabled, blend function
\li CullState - front face, cull face enabled
\li ViewportState - viewport
+ \li RenderTargetState - render target
\endlist
- The function is called by the renderer so it can reset the OpenGL states after rendering this
- node.
+ The function is called by the renderer so it can reset the states after
+ rendering this node. This makes the implementation of render() simpler
+ since it does not have to query and restore these states.
- \internal
+ The default implementation returns 0, meaning no relevant state was changed
+ in render().
+
+ With APIs other than OpenGL the relevant states are only those that are set
+ via the command list (for example, OMSetRenderTargets, RSSetViewports,
+ RSSetScissorRects, OMSetBlendFactor, OMSetStencilRef in case of D3D12), and
+ only when such commands were added to the scenegraph's command list queried
+ via the QSGRendererInterface::CommandList resource enum. States set in
+ pipeline state objects do not need to be reported here. Similarly, draw
+ call related settings (root signature, descriptor heaps, etc.) are always
+ set again by the scenegraph so render() can freely change them.
+
+ \note This function may be called before render().
*/
+QSGRenderNode::StateFlags QSGRenderNode::changedStates() const
+{
+ return 0;
+}
/*!
- \fn void QSGRenderNode::render(const RenderState &state)
+ \fn void QSGRenderNode::render(const RenderState *state)
- This function is called by the renderer and should paint this node with OpenGL commands.
+ This function is called by the renderer and should paint this node with
+ directly invoking commands in the graphics API (OpenGL, Direct3D, etc.)
+ currently in use.
- The states necessary for clipping has already been set before the function is called.
- The clip is a combination of a stencil clip and scissor clip. Information about the clip is
- found in \a state.
+ The states necessary for clipping has already been set before the function
+ is called. The clip is a combination of a stencil clip and scissor clip.
+ Information about the clip is found in \a state.
+
+ \note This means that setting viewport, scissor rectangle, stencil
+ reference value, and similar is not necessary in render() since the
+ corresponding commands are on the command list (or, in case of OpenGL, the
+ context) already. However, for APIs other than OpenGL stencil-based
+ clipping will need enabling stencil testing in the pipeline state that is
+ used by render().
The effective opacity can be retrieved with \l inheritedOpacity().
- The projection matrix is available through \a state, while the model-view matrix can be
- fetched with \l matrix(). The combined matrix is then the projection matrix times the
- model-view matrix.
+ The projection matrix is available through \a state, while the model-view
+ matrix can be fetched with \l matrix(). The combined matrix is then the
+ projection matrix times the model-view matrix. The correct stacking of the
+ items in the scene is ensured by the projection matrix.
+
+ When using the provided matrices, the coordinate system for vertex data
+ follows the usual QQuickItem conventions: top-left is (0, 0), bottom-right
+ is the corresponding QQuickItem's width() and height() minus one. For
+ example, assuming a two float (x-y) per vertex coordinate layout, a
+ triangle covering half of the item can be specified as (width - 1, height - 1),
+ (0, 0), (0, height - 1) using counter-clockwise direction.
+
+ \note QSGRenderNode is provided as a means to implement custom 2D or 2.5D
+ Qt Quick items. It is not intended for integrating true 3D content into the
+ Qt Quick scene. That use case is better supported by
+ QQuickFramebufferObject, QQuickWindow::beforeRendering(), or the
+ equivalents of those for APIs other than OpenGL.
- The following states are set before this function is called:
+ For OpenGL the following states are set on the render thread's context
+ before this function is called:
\list
\li glDepthMask(false)
\li glDisable(GL_DEPTH_TEST)
@@ -107,14 +172,129 @@ void QSGRenderNode::setInheritedOpacity(qreal opacity)
\li glDisable(GL_CULL_FACE)
\endlist
- States that are not listed above, but are included in \l StateFlags, can have arbitrary
- values.
+ States that are not listed above, but are included in \l StateFlags, can
+ have arbitrary values.
- \l changedStates() should return which states this function has changed. If a state is not
- covered by \l StateFlags, the state should be set to the default value according to the
- OpenGL specification.
+ \l changedStates() should return which states this function changes. If a
+ state is not covered by \l StateFlags, the state should be set to the
+ default value according to the OpenGL specification. For other APIs, see
+ the documentation for changedStates() for more information.
- \internal
+ For APIs other than OpenGL, it will likely be necessary to query certain
+ API-specific resources (for example, the graphics device or the command
+ list/buffer to add the commands to). This is done via QSGRendererInterface.
+
+ \sa QSGRendererInterface, QQuickWindow::rendererInterface()
*/
+/*!
+ This function is called when all custom graphics resources allocated by
+ this node have to be freed immediately. In case the node does not directly
+ allocate graphics resources (buffers, textures, render targets, fences,
+ etc.) through the graphics API that is in use, there is nothing to do here.
+
+ Failing to release all custom resources can lead to incorrect behavior in
+ graphics device loss scenarios on some systems since subsequent
+ reinitialization of the graphics system may fail.
+
+ \note Some scenegraph backends may choose not to call this function.
+ Therefore it is expected that QSGRenderNode implementations perform cleanup
+ both in their destructor and in releaseResources().
+
+ Unlike with the destructor, it is expected that render() can reinitialize
+ all resources it needs when called after a call to releaseResources().
+
+ With OpenGL, the scenegraph's OpenGL context will be current both when
+ calling the destructor and this function.
+ */
+void QSGRenderNode::releaseResources()
+{
+}
+
+/*!
+ \return pointer to the current model-view matrix.
+ */
+const QMatrix4x4 *QSGRenderNode::matrix() const
+{
+ return d->m_matrix;
+}
+
+/*!
+ \return the current clip list.
+ */
+const QSGClipNode *QSGRenderNode::clipList() const
+{
+ return d->m_clip_list;
+}
+
+/*!
+ \return the current effective opacity.
+ */
+qreal QSGRenderNode::inheritedOpacity() const
+{
+ return d->m_opacity;
+}
+
+QSGRenderNode::RenderState::~RenderState()
+{
+}
+
+/*!
+ \fn const QMatrix4x4 *QSGRenderNode::RenderState::projectionMatrix() const
+
+ \return pointer to the current projection matrix.
+
+ The model-view matrix can be retrieved with QSGRenderNode::matrix().
+ Typically \c{projection * modelview} is the matrix that is then used in the
+ vertex shader to transform the vertices.
+ */
+
+/*!
+ \fn const QMatrix4x4 *QSGRenderNode::RenderState::scissorRect() const
+
+ \return the current scissor rectangle when clipping is active.
+
+ \note Be aware of the differences between graphics APIs: for some the
+ scissor rect is only active when scissoring is enabled (for example,
+ OpenGL), while for others the scissor rect is equal to the viewport rect
+ when there is no need to scissor away anything (for example, Direct3D 12).
+ */
+
+/*!
+ \fn const QMatrix4x4 *QSGRenderNode::RenderState::scissorEnabled() const
+
+ \return the current state of scissoring.
+
+ \note Only relevant for graphics APIs that have a dedicated on/off state of
+ scissoring.
+ */
+
+/*!
+ \fn const QMatrix4x4 *QSGRenderNode::RenderState::stencilValue() const
+
+ \return the current stencil reference value when clipping is active.
+ */
+
+/*!
+ \fn const QMatrix4x4 *QSGRenderNode::RenderState::stencilEnabled() const
+
+ \return the current state of stencil testing.
+
+ \note With graphics APIs where stencil testing is enabled in pipeline state
+ objects, instead of individual state-setting commands, it is up to the
+ implementation of render() to enable stencil testing with operations
+ \c KEEP, comparison function \c EQUAL, and a read and write mask of \c 0xFF.
+ */
+
+/*!
+ \return pointer to a \a state value.
+
+ Reserved for future use.
+ */
+void *QSGRenderNode::RenderState::get(const char *state) const
+{
+ Q_UNUSED(state);
+ return nullptr;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.h b/src/quick/scenegraph/coreapi/qsgrendernode.h
new file mode 100644
index 0000000000..17569f8c59
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgrendernode.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGRENDERNODE_H
+#define QSGRENDERNODE_H
+
+#include <QtQuick/qsgnode.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGRenderNodePrivate;
+
+class Q_QUICK_EXPORT QSGRenderNode : public QSGNode
+{
+public:
+ enum StateFlag {
+ DepthState = 0x01,
+ StencilState = 0x02,
+ ScissorState = 0x04,
+ ColorState = 0x08,
+ BlendState = 0x10,
+ CullState = 0x20,
+ ViewportState = 0x40,
+ RenderTargetState = 0x80
+ };
+ Q_DECLARE_FLAGS(StateFlags, StateFlag)
+
+ struct Q_QUICK_EXPORT RenderState {
+ virtual ~RenderState();
+ virtual const QMatrix4x4 *projectionMatrix() const = 0;
+ virtual QRect scissorRect() const = 0;
+ virtual bool scissorEnabled() const = 0;
+ virtual int stencilValue() const = 0;
+ virtual bool stencilEnabled() const = 0;
+ virtual void *get(const char *state) const;
+ };
+
+ QSGRenderNode();
+ ~QSGRenderNode();
+
+ virtual StateFlags changedStates() const;
+ virtual void render(const RenderState *state) = 0;
+ virtual void releaseResources();
+
+ const QMatrix4x4 *matrix() const;
+ const QSGClipNode *clipList() const;
+ qreal inheritedOpacity() const;
+
+private:
+ QSGRenderNodePrivate *d;
+ friend class QSGRenderNodePrivate;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderNode::StateFlags)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode_p.h b/src/quick/scenegraph/coreapi/qsgrendernode_p.h
index 8659b0e62c..5c42e55689 100644
--- a/src/quick/scenegraph/coreapi/qsgrendernode_p.h
+++ b/src/quick/scenegraph/coreapi/qsgrendernode_p.h
@@ -51,64 +51,23 @@
// We mean it.
//
-#include "qsgnode.h"
-#include <private/qtquickglobal_p.h>
+#include <QtQuick/qsgnode.h>
+#include <QtQuick/qsgrendernode.h>
QT_BEGIN_NAMESPACE
-namespace QSGBatchRenderer {
- class Renderer;
-}
-
-class Q_QUICK_PRIVATE_EXPORT QSGRenderNode : public QSGNode
+class QSGRenderNodePrivate
{
public:
- enum StateFlag
- {
- DepthState = 0x01, // depth mask, depth test enable, depth func, clear depth
- StencilState = 0x02, // stencil mask, stencil test enable, stencil op, stencil func, clear stencil
- ScissorState = 0x04, // scissor enable, scissor test enable
- ColorState = 0x08, // clear color, color mask
- BlendState = 0x10, // blend enable, blend func
- CullState = 0x20, // front face, cull face enable
- ViewportState = 0x40 // viewport
- };
- Q_DECLARE_FLAGS(StateFlags, StateFlag)
-
- struct RenderState
- {
- // The model-view matrix can be retrieved with matrix().
- // The opacity can be retrieved with inheritedOpacity().
- const QMatrix4x4 *projectionMatrix;
- QRect scissorRect;
- int stencilValue;
-
- bool stencilEnabled;
- bool scissorEnabled;
- };
-
- QSGRenderNode();
+ QSGRenderNodePrivate();
- virtual StateFlags changedStates() = 0;
- virtual void render(const RenderState &state) = 0;
-
- const QMatrix4x4 *matrix() const { return m_matrix; }
- const QSGClipNode *clipList() const { return m_clip_list; }
-
- void setInheritedOpacity(qreal opacity);
- qreal inheritedOpacity() const { return m_opacity; }
-
-private:
- friend class QSGNodeUpdater;
- friend class QSGBatchRenderer::Renderer;
+ static QSGRenderNodePrivate *get(QSGRenderNode *node) { return node->d; }
const QMatrix4x4 *m_matrix;
const QSGClipNode *m_clip_list;
qreal m_opacity;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderNode::StateFlags)
-
QT_END_NAMESPACE
#endif
diff --git a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
index 97d7e69407..3a35632d5c 100644
--- a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
+++ b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
@@ -89,9 +89,6 @@ void Tokenizer::initialize(const char *input)
identifier = input;
}
-#define foo
-
-
Tokenizer::Token Tokenizer::next()
{
while (*pos != 0) {
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index 682423726e..50986e2528 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -65,15 +65,18 @@ QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCach
QRawFontPrivate *fontD = QRawFontPrivate::get(font);
m_glyphCount = fontD->fontEngine->glyphCount();
- m_doubleGlyphResolution = qt_fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT;
+ m_doubleGlyphResolution = qt_fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT();
m_referenceFont = font;
// we set the same pixel size as used by the distance field internally.
// this allows us to call pathForGlyph once and reuse the result.
m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(m_doubleGlyphResolution) * QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
Q_ASSERT(m_referenceFont.isValid());
-
+#ifndef QT_NO_OPENGL
m_coreProfile = (c->format().profile() == QSurfaceFormat::CoreProfile);
+#else
+ Q_UNUSED(c)
+#endif
}
QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache()
@@ -291,7 +294,7 @@ void QSGDistanceFieldGlyphCache::markGlyphsToRender(const QVector<glyph_t> &glyp
m_pendingGlyphs.add(glyphs.at(i));
}
-void QSGDistanceFieldGlyphCache::updateTexture(GLuint oldTex, GLuint newTex, const QSize &newTexSize)
+void QSGDistanceFieldGlyphCache::updateTexture(uint oldTex, uint newTex, const QSize &newTexSize)
{
int count = m_textures.count();
for (int i = 0; i < count; ++i) {
@@ -516,4 +519,43 @@ void QSGNodeVisitorEx::visitChildren(QSGNode *node)
}
}
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QSGGuiThreadShaderEffectManager::ShaderInfo::InputParameter &p)
+{
+ QDebugStateSaver saver(debug);
+ debug.space();
+ debug << p.semanticName << "semindex" << p.semanticIndex;
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &v)
+{
+ QDebugStateSaver saver(debug);
+ debug.space();
+ debug << v.name;
+ switch (v.type) {
+ case QSGGuiThreadShaderEffectManager::ShaderInfo::Constant:
+ debug << "cvar" << "offset" << v.offset << "size" << v.size;
+ break;
+ case QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler:
+ debug << "sampler" << "bindpoint" << v.bindPoint;
+ break;
+ case QSGGuiThreadShaderEffectManager::ShaderInfo::Texture:
+ debug << "texture" << "bindpoint" << v.bindPoint;
+ break;
+ default:
+ break;
+ }
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const QSGShaderEffectNode::VariableData &vd)
+{
+ QDebugStateSaver saver(debug);
+ debug.space();
+ debug << vd.specialType;
+ return debug;
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index 8579b0a57b..8fdcf7af64 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -210,7 +210,7 @@ public:
virtual QImage toImage() const = 0;
virtual void setLive(bool live) = 0;
virtual void setRecursive(bool recursive) = 0;
- virtual void setFormat(GLenum format) = 0;
+ virtual void setFormat(uint format) = 0;
virtual void setHasMipmaps(bool mipmap) = 0;
virtual void setDevicePixelRatio(qreal ratio) = 0;
virtual void setMirrorHorizontal(bool mirror) = 0;
@@ -223,6 +223,130 @@ Q_SIGNALS:
void scheduledUpdateCompleted();
};
+class Q_QUICK_PRIVATE_EXPORT QSGGuiThreadShaderEffectManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum Status {
+ Compiled,
+ Uncompiled,
+ Error
+ };
+
+ virtual bool hasSeparateSamplerAndTextureObjects() const = 0;
+
+ virtual QString log() const = 0;
+ virtual Status status() const = 0;
+
+ struct ShaderInfo {
+ enum Type {
+ TypeVertex,
+ TypeFragment,
+ TypeOther
+ };
+ enum VariableType {
+ Constant, // cbuffer members or uniforms
+ Sampler,
+ Texture // for APIs with separate texture and sampler objects
+ };
+ struct InputParameter {
+ InputParameter() : semanticIndex(0) { }
+ // Semantics use the D3D keys (POSITION, TEXCOORD).
+ // Attribute name based APIs can map based on pre-defined names.
+ QByteArray semanticName;
+ int semanticIndex;
+ };
+ struct Variable {
+ Variable() : type(Constant), offset(0), size(0), bindPoint(0) { }
+ VariableType type;
+ QByteArray name;
+ uint offset; // for cbuffer members
+ uint size; // for cbuffer members
+ int bindPoint; // for textures and samplers; for register-based APIs
+ };
+
+ QByteArray blob; // source or bytecode
+ Type type;
+ QVector<InputParameter> inputParameters;
+ QVector<Variable> variables;
+ uint constantDataSize;
+ };
+
+ virtual bool reflect(const QByteArray &src, ShaderInfo *result) = 0;
+
+Q_SIGNALS:
+ void textureChanged();
+ void logAndStatusChanged();
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug debug, const QSGGuiThreadShaderEffectManager::ShaderInfo::InputParameter &p);
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug debug, const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &v);
+#endif
+
+class Q_QUICK_PRIVATE_EXPORT QSGShaderEffectNode : public QSGVisitableNode
+{
+public:
+ enum DirtyShaderFlag {
+ DirtyShaders = 0x01,
+ DirtyShaderConstant = 0x02,
+ DirtyShaderTexture = 0x04,
+ DirtyShaderGeometry = 0x08,
+ DirtyShaderMesh = 0x10,
+
+ DirtyShaderAll = 0xFF
+ };
+ Q_DECLARE_FLAGS(DirtyShaderFlags, DirtyShaderFlag)
+
+ enum CullMode { // must match ShaderEffect
+ NoCulling,
+ BackFaceCulling,
+ FrontFaceCulling
+ };
+
+ struct VariableData {
+ enum SpecialType { None, Unused, Source, SubRect, Opacity, Matrix };
+
+ QVariant value;
+ SpecialType specialType;
+ };
+
+ struct ShaderData {
+ ShaderData() : hasShaderCode(false) { }
+ bool hasShaderCode;
+ QSGGuiThreadShaderEffectManager::ShaderInfo shaderInfo;
+ QVector<VariableData> varData;
+ };
+
+ struct SyncData {
+ DirtyShaderFlags dirty;
+ CullMode cullMode;
+ bool blending;
+ struct ShaderSyncData {
+ const ShaderData *shader;
+ const QSet<int> *dirtyConstants;
+ const QSet<int> *dirtyTextures;
+ };
+ ShaderSyncData vertex;
+ ShaderSyncData fragment;
+ };
+
+ // Each ShaderEffect item has one node (render thread) and one manager (gui thread).
+ QSGShaderEffectNode(QSGGuiThreadShaderEffectManager *) { }
+
+ virtual QRectF updateNormalizedTextureSubRect(bool supportsAtlasTextures) = 0;
+ virtual void syncMaterial(SyncData *syncData) = 0;
+
+ void accept(QSGNodeVisitorEx *visitor) override { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); }
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGShaderEffectNode::DirtyShaderFlags)
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug debug, const QSGShaderEffectNode::VariableData &vd);
+#endif
+
class Q_QUICK_PRIVATE_EXPORT QSGGlyphNode : public QSGVisitableNode
{
public:
@@ -295,7 +419,7 @@ public:
};
struct Texture {
- GLuint textureId;
+ uint textureId;
QSize size;
Texture() : textureId(0), size(QSize()) { }
@@ -359,10 +483,10 @@ protected:
void markGlyphsToRender(const QVector<glyph_t> &glyphs);
inline void removeGlyph(glyph_t glyph);
- void updateTexture(GLuint oldTex, GLuint newTex, const QSize &newTexSize);
+ void updateTexture(uint oldTex, uint newTex, const QSize &newTexSize);
inline bool containsGlyph(glyph_t glyph);
- GLuint textureIdForGlyph(glyph_t glyph) const;
+ uint textureIdForGlyph(glyph_t glyph) const;
GlyphData &glyphData(glyph_t glyph);
diff --git a/src/quick/scenegraph/qsgbasicglyphnode.cpp b/src/quick/scenegraph/qsgbasicglyphnode.cpp
new file mode 100644
index 0000000000..38f650a82c
--- /dev/null
+++ b/src/quick/scenegraph/qsgbasicglyphnode.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgbasicglyphnode_p.h"
+#include <qsgmaterial.h> // just so that we can safely do delete m_material in the dtor
+
+QT_BEGIN_NAMESPACE
+
+QSGBasicGlyphNode::QSGBasicGlyphNode()
+ : m_style(QQuickText::Normal)
+ , m_material(0)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
+{
+ m_geometry.setDrawingMode(QSGGeometry::DrawTriangles);
+ setGeometry(&m_geometry);
+}
+
+QSGBasicGlyphNode::~QSGBasicGlyphNode()
+{
+ delete m_material;
+}
+
+void QSGBasicGlyphNode::setColor(const QColor &color)
+{
+ m_color = color;
+ if (m_material != 0) {
+ setMaterialColor(color);
+ markDirty(DirtyMaterial);
+ }
+}
+
+void QSGBasicGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
+{
+ if (m_material != 0)
+ delete m_material;
+
+ m_position = position;
+ m_glyphs = glyphs;
+
+#ifdef QSG_RUNTIME_DESCRIPTION
+ qsgnode_set_description(this, QLatin1String("glyphs"));
+#endif
+}
+
+void QSGBasicGlyphNode::setStyle(QQuickText::TextStyle style)
+{
+ if (m_style == style)
+ return;
+ m_style = style;
+}
+
+void QSGBasicGlyphNode::setStyleColor(const QColor &color)
+{
+ if (m_styleColor == color)
+ return;
+ m_styleColor = color;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgbasicglyphnode_p.h b/src/quick/scenegraph/qsgbasicglyphnode_p.h
new file mode 100644
index 0000000000..1d09367ea5
--- /dev/null
+++ b/src/quick/scenegraph/qsgbasicglyphnode_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGBASICGLYPHNODE_P_H
+#define QSGBASICGLYPHNODE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgadaptationlayer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGMaterial;
+
+class Q_QUICK_PRIVATE_EXPORT QSGBasicGlyphNode: public QSGGlyphNode
+{
+public:
+ QSGBasicGlyphNode();
+ virtual ~QSGBasicGlyphNode();
+
+ virtual QPointF baseLine() const { return m_baseLine; }
+ virtual void setGlyphs(const QPointF &position, const QGlyphRun &glyphs);
+ virtual void setColor(const QColor &color);
+
+ virtual void setPreferredAntialiasingMode(AntialiasingMode) { }
+ virtual void setStyle(QQuickText::TextStyle);
+ virtual void setStyleColor(const QColor &);
+
+ virtual void setMaterialColor(const QColor &color) = 0;
+ virtual void update() = 0;
+
+protected:
+ QGlyphRun m_glyphs;
+ QPointF m_position;
+ QColor m_color;
+ QQuickText::TextStyle m_style;
+ QColor m_styleColor;
+
+ QPointF m_baseLine;
+ QSGMaterial *m_material;
+
+ QSGGeometry m_geometry;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/scenegraph/qsgbasicimagenode.cpp b/src/quick/scenegraph/qsgbasicimagenode.cpp
new file mode 100644
index 0000000000..24077cc947
--- /dev/null
+++ b/src/quick/scenegraph/qsgbasicimagenode.cpp
@@ -0,0 +1,559 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgbasicimagenode_p.h"
+
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace
+{
+ struct SmoothVertex
+ {
+ float x, y, u, v;
+ float dx, dy, du, dv;
+ };
+
+ const QSGGeometry::AttributeSet &smoothAttributeSet()
+ {
+ static QSGGeometry::Attribute data[] = {
+ QSGGeometry::Attribute::createWithSemantic(0, 2, QSGGeometry::TypeFloat, QSGGeometry::Attribute::POSITION),
+ QSGGeometry::Attribute::createWithSemantic(1, 2, QSGGeometry::TypeFloat, QSGGeometry::Attribute::TEXCOORD),
+ QSGGeometry::Attribute::createWithSemantic(2, 2, QSGGeometry::TypeFloat, QSGGeometry::Attribute::TEXCOORD1),
+ QSGGeometry::Attribute::createWithSemantic(3, 2, QSGGeometry::TypeFloat, QSGGeometry::Attribute::TEXCOORD2)
+ };
+ static QSGGeometry::AttributeSet attrs = { 4, sizeof(SmoothVertex), data };
+ return attrs;
+ }
+}
+
+QSGBasicImageNode::QSGBasicImageNode()
+ : m_innerSourceRect(0, 0, 1, 1)
+ , m_subSourceRect(0, 0, 1, 1)
+ , m_antialiasing(false)
+ , m_mirror(false)
+ , m_dirtyGeometry(false)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+ , m_dynamicTexture(nullptr)
+{
+ setGeometry(&m_geometry);
+
+#ifdef QSG_RUNTIME_DESCRIPTION
+ qsgnode_set_description(this, QLatin1String("image"));
+#endif
+}
+
+void QSGBasicImageNode::setTargetRect(const QRectF &rect)
+{
+ if (rect == m_targetRect)
+ return;
+ m_targetRect = rect;
+ m_dirtyGeometry = true;
+}
+
+void QSGBasicImageNode::setInnerTargetRect(const QRectF &rect)
+{
+ if (rect == m_innerTargetRect)
+ return;
+ m_innerTargetRect = rect;
+ m_dirtyGeometry = true;
+}
+
+void QSGBasicImageNode::setInnerSourceRect(const QRectF &rect)
+{
+ if (rect == m_innerSourceRect)
+ return;
+ m_innerSourceRect = rect;
+ m_dirtyGeometry = true;
+}
+
+void QSGBasicImageNode::setSubSourceRect(const QRectF &rect)
+{
+ if (rect == m_subSourceRect)
+ return;
+ m_subSourceRect = rect;
+ m_dirtyGeometry = true;
+}
+
+void QSGBasicImageNode::setTexture(QSGTexture *texture)
+{
+ Q_ASSERT(texture);
+
+ setMaterialTexture(texture);
+ updateMaterialBlending();
+
+ markDirty(DirtyMaterial);
+
+ // Because the texture can be a different part of the atlas, we need to update it...
+ m_dirtyGeometry = true;
+}
+
+void QSGBasicImageNode::setAntialiasing(bool antialiasing)
+{
+ if (antialiasing == m_antialiasing)
+ return;
+ m_antialiasing = antialiasing;
+ if (m_antialiasing) {
+ setGeometry(new QSGGeometry(smoothAttributeSet(), 0));
+ setFlag(OwnsGeometry, true);
+ } else {
+ setGeometry(&m_geometry);
+ setFlag(OwnsGeometry, false);
+ }
+ updateMaterialAntialiasing();
+ m_dirtyGeometry = true;
+}
+
+void QSGBasicImageNode::setMirror(bool mirror)
+{
+ if (mirror == m_mirror)
+ return;
+ m_mirror = mirror;
+ m_dirtyGeometry = true;
+}
+
+
+void QSGBasicImageNode::update()
+{
+ if (m_dirtyGeometry)
+ updateGeometry();
+}
+
+void QSGBasicImageNode::preprocess()
+{
+ bool doDirty = false;
+ QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(materialTexture());
+ if (t) {
+ doDirty = t->updateTexture();
+ if (doDirty) {
+ // The geometry may need updating. This is expensive however, so do
+ // it only when something relevant has changed.
+ if (t != m_dynamicTexture
+ || t->textureSize() != m_dynamicTextureSize
+ || t->normalizedTextureSubRect() != m_dynamicTextureSubRect) {
+ updateGeometry();
+ m_dynamicTextureSize = t->textureSize();
+ m_dynamicTextureSubRect = t->normalizedTextureSubRect();
+ }
+ }
+ }
+ m_dynamicTexture = t;
+
+ if (updateMaterialBlending())
+ doDirty = true;
+
+ if (doDirty)
+ markDirty(DirtyMaterial);
+}
+
+namespace {
+ struct X { float x, tx; };
+ struct Y { float y, ty; };
+}
+
+static inline void appendQuad(quint16 **indices, quint16 topLeft, quint16 topRight,
+ quint16 bottomLeft, quint16 bottomRight)
+{
+ *(*indices)++ = topLeft;
+ *(*indices)++ = bottomLeft;
+ *(*indices)++ = bottomRight;
+ *(*indices)++ = bottomRight;
+ *(*indices)++ = topRight;
+ *(*indices)++ = topLeft;
+}
+
+QSGGeometry *QSGBasicImageNode::updateGeometry(const QRectF &targetRect,
+ const QRectF &innerTargetRect,
+ const QRectF &sourceRect,
+ const QRectF &innerSourceRect,
+ const QRectF &subSourceRect,
+ QSGGeometry *geometry,
+ bool mirror,
+ bool antialiasing)
+{
+ int floorLeft = qFloor(subSourceRect.left());
+ int ceilRight = qCeil(subSourceRect.right());
+ int floorTop = qFloor(subSourceRect.top());
+ int ceilBottom = qCeil(subSourceRect.bottom());
+ int hTiles = ceilRight - floorLeft;
+ int vTiles = ceilBottom - floorTop;
+
+ int hCells = hTiles;
+ int vCells = vTiles;
+ if (innerTargetRect.width() == 0)
+ hCells = 0;
+ if (innerTargetRect.left() != targetRect.left())
+ ++hCells;
+ if (innerTargetRect.right() != targetRect.right())
+ ++hCells;
+ if (innerTargetRect.height() == 0)
+ vCells = 0;
+ if (innerTargetRect.top() != targetRect.top())
+ ++vCells;
+ if (innerTargetRect.bottom() != targetRect.bottom())
+ ++vCells;
+ QVarLengthArray<X, 32> xData(2 * hCells);
+ QVarLengthArray<Y, 32> yData(2 * vCells);
+ X *xs = xData.data();
+ Y *ys = yData.data();
+
+ if (innerTargetRect.left() != targetRect.left()) {
+ xs[0].x = targetRect.left();
+ xs[0].tx = sourceRect.left();
+ xs[1].x = innerTargetRect.left();
+ xs[1].tx = innerSourceRect.left();
+ xs += 2;
+ }
+ if (innerTargetRect.width() != 0) {
+ xs[0].x = innerTargetRect.left();
+ xs[0].tx = innerSourceRect.x() + (subSourceRect.left() - floorLeft) * innerSourceRect.width();
+ ++xs;
+ float b = innerTargetRect.width() / subSourceRect.width();
+ float a = innerTargetRect.x() - subSourceRect.x() * b;
+ for (int i = floorLeft + 1; i <= ceilRight - 1; ++i) {
+ xs[0].x = xs[1].x = a + b * i;
+ xs[0].tx = innerSourceRect.right();
+ xs[1].tx = innerSourceRect.left();
+ xs += 2;
+ }
+ xs[0].x = innerTargetRect.right();
+ xs[0].tx = innerSourceRect.x() + (subSourceRect.right() - ceilRight + 1) * innerSourceRect.width();
+ ++xs;
+ }
+ if (innerTargetRect.right() != targetRect.right()) {
+ xs[0].x = innerTargetRect.right();
+ xs[0].tx = innerSourceRect.right();
+ xs[1].x = targetRect.right();
+ xs[1].tx = sourceRect.right();
+ xs += 2;
+ }
+ Q_ASSERT(xs == xData.data() + xData.size());
+ if (mirror) {
+ float leftPlusRight = targetRect.left() + targetRect.right();
+ int count = xData.size();
+ xs = xData.data();
+ for (int i = 0; i < count >> 1; ++i)
+ qSwap(xs[i], xs[count - 1 - i]);
+ for (int i = 0; i < count; ++i)
+ xs[i].x = leftPlusRight - xs[i].x;
+ }
+
+ if (innerTargetRect.top() != targetRect.top()) {
+ ys[0].y = targetRect.top();
+ ys[0].ty = sourceRect.top();
+ ys[1].y = innerTargetRect.top();
+ ys[1].ty = innerSourceRect.top();
+ ys += 2;
+ }
+ if (innerTargetRect.height() != 0) {
+ ys[0].y = innerTargetRect.top();
+ ys[0].ty = innerSourceRect.y() + (subSourceRect.top() - floorTop) * innerSourceRect.height();
+ ++ys;
+ float b = innerTargetRect.height() / subSourceRect.height();
+ float a = innerTargetRect.y() - subSourceRect.y() * b;
+ for (int i = floorTop + 1; i <= ceilBottom - 1; ++i) {
+ ys[0].y = ys[1].y = a + b * i;
+ ys[0].ty = innerSourceRect.bottom();
+ ys[1].ty = innerSourceRect.top();
+ ys += 2;
+ }
+ ys[0].y = innerTargetRect.bottom();
+ ys[0].ty = innerSourceRect.y() + (subSourceRect.bottom() - ceilBottom + 1) * innerSourceRect.height();
+ ++ys;
+ }
+ if (innerTargetRect.bottom() != targetRect.bottom()) {
+ ys[0].y = innerTargetRect.bottom();
+ ys[0].ty = innerSourceRect.bottom();
+ ys[1].y = targetRect.bottom();
+ ys[1].ty = sourceRect.bottom();
+ ys += 2;
+ }
+ Q_ASSERT(ys == yData.data() + yData.size());
+
+ if (antialiasing) {
+ QSGGeometry *g = geometry;
+ Q_ASSERT(g);
+
+ g->allocate(hCells * vCells * 4 + (hCells + vCells - 1) * 4,
+ hCells * vCells * 6 + (hCells + vCells) * 12);
+ g->setDrawingMode(QSGGeometry::DrawTriangles);
+ SmoothVertex *vertices = reinterpret_cast<SmoothVertex *>(g->vertexData());
+ memset(vertices, 0, g->vertexCount() * g->sizeOfVertex());
+ quint16 *indices = g->indexDataAsUShort();
+
+ // The deltas are how much the fuzziness can reach into the image.
+ // Only the border vertices are moved by the vertex shader, so the fuzziness
+ // can't reach further into the image than the closest interior vertices.
+ float leftDx = xData.at(1).x - xData.at(0).x;
+ float rightDx = xData.at(xData.size() - 1).x - xData.at(xData.size() - 2).x;
+ float topDy = yData.at(1).y - yData.at(0).y;
+ float bottomDy = yData.at(yData.size() - 1).y - yData.at(yData.size() - 2).y;
+
+ float leftDu = xData.at(1).tx - xData.at(0).tx;
+ float rightDu = xData.at(xData.size() - 1).tx - xData.at(xData.size() - 2).tx;
+ float topDv = yData.at(1).ty - yData.at(0).ty;
+ float bottomDv = yData.at(yData.size() - 1).ty - yData.at(yData.size() - 2).ty;
+
+ if (hCells == 1) {
+ leftDx = rightDx *= 0.5f;
+ leftDu = rightDu *= 0.5f;
+ }
+ if (vCells == 1) {
+ topDy = bottomDy *= 0.5f;
+ topDv = bottomDv *= 0.5f;
+ }
+
+ // This delta is how much the fuzziness can reach out from the image.
+ float delta = float(qAbs(targetRect.width()) < qAbs(targetRect.height())
+ ? targetRect.width() : targetRect.height()) * 0.5f;
+
+ quint16 index = 0;
+ ys = yData.data();
+ for (int j = 0; j < vCells; ++j, ys += 2) {
+ xs = xData.data();
+ bool isTop = j == 0;
+ bool isBottom = j == vCells - 1;
+ for (int i = 0; i < hCells; ++i, xs += 2) {
+ bool isLeft = i == 0;
+ bool isRight = i == hCells - 1;
+
+ SmoothVertex *v = vertices + index;
+
+ quint16 topLeft = index;
+ for (int k = (isTop || isLeft ? 2 : 1); k--; ++v, ++index) {
+ v->x = xs[0].x;
+ v->u = xs[0].tx;
+ v->y = ys[0].y;
+ v->v = ys[0].ty;
+ }
+
+ quint16 topRight = index;
+ for (int k = (isTop || isRight ? 2 : 1); k--; ++v, ++index) {
+ v->x = xs[1].x;
+ v->u = xs[1].tx;
+ v->y = ys[0].y;
+ v->v = ys[0].ty;
+ }
+
+ quint16 bottomLeft = index;
+ for (int k = (isBottom || isLeft ? 2 : 1); k--; ++v, ++index) {
+ v->x = xs[0].x;
+ v->u = xs[0].tx;
+ v->y = ys[1].y;
+ v->v = ys[1].ty;
+ }
+
+ quint16 bottomRight = index;
+ for (int k = (isBottom || isRight ? 2 : 1); k--; ++v, ++index) {
+ v->x = xs[1].x;
+ v->u = xs[1].tx;
+ v->y = ys[1].y;
+ v->v = ys[1].ty;
+ }
+
+ appendQuad(&indices, topLeft, topRight, bottomLeft, bottomRight);
+
+ if (isTop) {
+ vertices[topLeft].dy = vertices[topRight].dy = topDy;
+ vertices[topLeft].dv = vertices[topRight].dv = topDv;
+ vertices[topLeft + 1].dy = vertices[topRight + 1].dy = -delta;
+ appendQuad(&indices, topLeft + 1, topRight + 1, topLeft, topRight);
+ }
+
+ if (isBottom) {
+ vertices[bottomLeft].dy = vertices[bottomRight].dy = -bottomDy;
+ vertices[bottomLeft].dv = vertices[bottomRight].dv = -bottomDv;
+ vertices[bottomLeft + 1].dy = vertices[bottomRight + 1].dy = delta;
+ appendQuad(&indices, bottomLeft, bottomRight, bottomLeft + 1, bottomRight + 1);
+ }
+
+ if (isLeft) {
+ vertices[topLeft].dx = vertices[bottomLeft].dx = leftDx;
+ vertices[topLeft].du = vertices[bottomLeft].du = leftDu;
+ vertices[topLeft + 1].dx = vertices[bottomLeft + 1].dx = -delta;
+ appendQuad(&indices, topLeft + 1, topLeft, bottomLeft + 1, bottomLeft);
+ }
+
+ if (isRight) {
+ vertices[topRight].dx = vertices[bottomRight].dx = -rightDx;
+ vertices[topRight].du = vertices[bottomRight].du = -rightDu;
+ vertices[topRight + 1].dx = vertices[bottomRight + 1].dx = delta;
+ appendQuad(&indices, topRight, topRight + 1, bottomRight, bottomRight + 1);
+ }
+ }
+ }
+
+ Q_ASSERT(index == g->vertexCount());
+ Q_ASSERT(indices - g->indexCount() == g->indexData());
+ } else {
+ if (!geometry) {
+ geometry = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(),
+ hCells * vCells * 4, hCells * vCells * 6,
+ QSGGeometry::TypeUnsignedShort);
+ } else {
+ geometry->allocate(hCells * vCells * 4, hCells * vCells * 6);
+ }
+ geometry->setDrawingMode(QSGGeometry::DrawTriangles);
+ QSGGeometry::TexturedPoint2D *vertices = geometry->vertexDataAsTexturedPoint2D();
+ ys = yData.data();
+ for (int j = 0; j < vCells; ++j, ys += 2) {
+ xs = xData.data();
+ for (int i = 0; i < hCells; ++i, xs += 2) {
+ vertices[0].x = vertices[2].x = xs[0].x;
+ vertices[0].tx = vertices[2].tx = xs[0].tx;
+ vertices[1].x = vertices[3].x = xs[1].x;
+ vertices[1].tx = vertices[3].tx = xs[1].tx;
+
+ vertices[0].y = vertices[1].y = ys[0].y;
+ vertices[0].ty = vertices[1].ty = ys[0].ty;
+ vertices[2].y = vertices[3].y = ys[1].y;
+ vertices[2].ty = vertices[3].ty = ys[1].ty;
+
+ vertices += 4;
+ }
+ }
+
+ quint16 *indices = geometry->indexDataAsUShort();
+ for (int i = 0; i < 4 * vCells * hCells; i += 4)
+ appendQuad(&indices, i, i + 1, i + 2, i + 3);
+ }
+ return geometry;
+}
+
+void QSGBasicImageNode::updateGeometry()
+{
+ Q_ASSERT(!m_targetRect.isEmpty());
+ const QSGTexture *t = materialTexture();
+ if (!t) {
+ QSGGeometry *g = geometry();
+ g->allocate(4);
+ g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
+ memset(g->vertexData(), 0, g->sizeOfVertex() * 4);
+ } else {
+ QRectF sourceRect = t->normalizedTextureSubRect();
+
+ QRectF innerSourceRect(sourceRect.x() + m_innerSourceRect.x() * sourceRect.width(),
+ sourceRect.y() + m_innerSourceRect.y() * sourceRect.height(),
+ m_innerSourceRect.width() * sourceRect.width(),
+ m_innerSourceRect.height() * sourceRect.height());
+
+ bool hasMargins = m_targetRect != m_innerTargetRect;
+
+ int floorLeft = qFloor(m_subSourceRect.left());
+ int ceilRight = qCeil(m_subSourceRect.right());
+ int floorTop = qFloor(m_subSourceRect.top());
+ int ceilBottom = qCeil(m_subSourceRect.bottom());
+ int hTiles = ceilRight - floorLeft;
+ int vTiles = ceilBottom - floorTop;
+
+ bool hasTiles = hTiles != 1 || vTiles != 1;
+ bool fullTexture = innerSourceRect == QRectF(0, 0, 1, 1);
+
+ // An image can be rendered as a single quad if:
+ // - There are no margins, and either:
+ // - the image isn't repeated
+ // - the source rectangle fills the entire texture so that texture wrapping can be used,
+ // and NPOT is supported
+ if (!hasMargins && (!hasTiles || (fullTexture && supportsWrap(t->textureSize())))) {
+ QRectF sr;
+ if (!fullTexture) {
+ sr = QRectF(innerSourceRect.x() + (m_subSourceRect.left() - floorLeft) * innerSourceRect.width(),
+ innerSourceRect.y() + (m_subSourceRect.top() - floorTop) * innerSourceRect.height(),
+ m_subSourceRect.width() * innerSourceRect.width(),
+ m_subSourceRect.height() * innerSourceRect.height());
+ } else {
+ sr = QRectF(m_subSourceRect.left() - floorLeft, m_subSourceRect.top() - floorTop,
+ m_subSourceRect.width(), m_subSourceRect.height());
+ }
+ if (m_mirror) {
+ qreal oldLeft = sr.left();
+ sr.setLeft(sr.right());
+ sr.setRight(oldLeft);
+ }
+
+ if (m_antialiasing) {
+ QSGGeometry *g = geometry();
+ Q_ASSERT(g != &m_geometry);
+ g->allocate(8, 14);
+ g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
+ SmoothVertex *vertices = reinterpret_cast<SmoothVertex *>(g->vertexData());
+ float delta = float(qAbs(m_targetRect.width()) < qAbs(m_targetRect.height())
+ ? m_targetRect.width() : m_targetRect.height()) * 0.5f;
+ float sx = float(sr.width() / m_targetRect.width());
+ float sy = float(sr.height() / m_targetRect.height());
+ for (int d = -1; d <= 1; d += 2) {
+ for (int j = 0; j < 2; ++j) {
+ for (int i = 0; i < 2; ++i, ++vertices) {
+ vertices->x = m_targetRect.x() + i * m_targetRect.width();
+ vertices->y = m_targetRect.y() + j * m_targetRect.height();
+ vertices->u = sr.x() + i * sr.width();
+ vertices->v = sr.y() + j * sr.height();
+ vertices->dx = (i == 0 ? delta : -delta) * d;
+ vertices->dy = (j == 0 ? delta : -delta) * d;
+ vertices->du = (d < 0 ? 0 : vertices->dx * sx);
+ vertices->dv = (d < 0 ? 0 : vertices->dy * sy);
+ }
+ }
+ }
+ Q_ASSERT(vertices - g->vertexCount() == g->vertexData());
+ static const quint16 indices[] = {
+ 0, 4, 1, 5, 3, 7, 2, 6, 0, 4,
+ 4, 6, 5, 7
+ };
+ Q_ASSERT(g->sizeOfIndex() * g->indexCount() == sizeof(indices));
+ memcpy(g->indexDataAsUShort(), indices, sizeof(indices));
+ } else {
+ m_geometry.allocate(4);
+ m_geometry.setDrawingMode(QSGGeometry::DrawTriangleStrip);
+ QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_targetRect, sr);
+ }
+ } else {
+ QSGGeometry *g = m_antialiasing ? geometry() : &m_geometry;
+ updateGeometry(m_targetRect, m_innerTargetRect,
+ sourceRect, innerSourceRect, m_subSourceRect,
+ g, m_mirror, m_antialiasing);
+ }
+ }
+ markDirty(DirtyGeometry);
+ m_dirtyGeometry = false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgbasicimagenode_p.h b/src/quick/scenegraph/qsgbasicimagenode_p.h
new file mode 100644
index 0000000000..4a96e1a9f6
--- /dev/null
+++ b/src/quick/scenegraph/qsgbasicimagenode_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGBASICIMAGENODE_P_H
+#define QSGBASICIMAGENODE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgadaptationlayer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_PRIVATE_EXPORT QSGBasicImageNode : public QSGImageNode
+{
+public:
+ QSGBasicImageNode();
+
+ void setTargetRect(const QRectF &rect) override;
+ void setInnerTargetRect(const QRectF &rect) override;
+ void setInnerSourceRect(const QRectF &rect) override;
+ void setSubSourceRect(const QRectF &rect) override;
+ void setTexture(QSGTexture *texture) override;
+ void setAntialiasing(bool antialiasing) override;
+ void setMirror(bool mirror) override;
+ void update() override;
+ void preprocess() override;
+
+ static QSGGeometry *updateGeometry(const QRectF &targetRect,
+ const QRectF &innerTargetRect,
+ const QRectF &sourceRect,
+ const QRectF &innerSourceRect,
+ const QRectF &subSourceRect,
+ QSGGeometry *geometry,
+ bool mirror = false,
+ bool antialiasing = false);
+
+protected:
+ virtual void updateMaterialAntialiasing() = 0;
+ virtual void setMaterialTexture(QSGTexture *texture) = 0;
+ virtual QSGTexture *materialTexture() const = 0;
+ virtual bool updateMaterialBlending() = 0;
+ virtual bool supportsWrap(const QSize &size) const = 0;
+
+ void updateGeometry();
+
+ QRectF m_targetRect;
+ QRectF m_innerTargetRect;
+ QRectF m_innerSourceRect;
+ QRectF m_subSourceRect;
+
+ uint m_antialiasing : 1;
+ uint m_mirror : 1;
+ uint m_dirtyGeometry : 1;
+
+ QSGGeometry m_geometry;
+
+ QSGDynamicTexture *m_dynamicTexture;
+ QSize m_dynamicTextureSize;
+ QRectF m_dynamicTextureSubRect;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/scenegraph/qsgbasicrectanglenode.cpp b/src/quick/scenegraph/qsgbasicrectanglenode.cpp
new file mode 100644
index 0000000000..14d2dc9677
--- /dev/null
+++ b/src/quick/scenegraph/qsgbasicrectanglenode.cpp
@@ -0,0 +1,687 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgbasicrectanglenode_p.h"
+
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace
+{
+ struct Color4ub
+ {
+ unsigned char r, g, b, a;
+ };
+
+ Color4ub operator *(Color4ub c, float t) { c.a *= t; c.r *= t; c.g *= t; c.b *= t; return c; }
+ Color4ub operator +(Color4ub a, Color4ub b) { a.a += b.a; a.r += b.r; a.g += b.g; a.b += b.b; return a; }
+
+ inline Color4ub colorToColor4ub(const QColor &c)
+ {
+ Color4ub color = { uchar(qRound(c.redF() * c.alphaF() * 255)),
+ uchar(qRound(c.greenF() * c.alphaF() * 255)),
+ uchar(qRound(c.blueF() * c.alphaF() * 255)),
+ uchar(qRound(c.alphaF() * 255))
+ };
+ return color;
+ }
+
+ // Same layout as QSGGeometry::ColoredPoint2D, but uses Color4ub for convenience.
+ struct Vertex
+ {
+ float x, y;
+ Color4ub color;
+ void set(float nx, float ny, Color4ub ncolor)
+ {
+ x = nx; y = ny; color = ncolor;
+ }
+ };
+
+ struct SmoothVertex : public Vertex
+ {
+ float dx, dy;
+ void set(float nx, float ny, Color4ub ncolor, float ndx, float ndy)
+ {
+ Vertex::set(nx, ny, ncolor);
+ dx = ndx; dy = ndy;
+ }
+ };
+
+ const QSGGeometry::AttributeSet &smoothAttributeSet()
+ {
+ static QSGGeometry::Attribute data[] = {
+ QSGGeometry::Attribute::createWithSemantic(0, 2, QSGGeometry::TypeFloat, QSGGeometry::Attribute::POSITION),
+ QSGGeometry::Attribute::createWithSemantic(1, 4, QSGGeometry::TypeUnsignedByte, QSGGeometry::Attribute::COLOR),
+ QSGGeometry::Attribute::createWithSemantic(2, 2, QSGGeometry::TypeFloat, QSGGeometry::Attribute::TEXCOORD)
+ };
+ static QSGGeometry::AttributeSet attrs = { 3, sizeof(SmoothVertex), data };
+ return attrs;
+ }
+}
+
+QSGBasicRectangleNode::QSGBasicRectangleNode()
+ : m_radius(0)
+ , m_pen_width(0)
+ , m_aligned(true)
+ , m_antialiasing(false)
+ , m_gradient_is_opaque(true)
+ , m_dirty_geometry(false)
+ , m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0)
+{
+ setGeometry(&m_geometry);
+
+#ifdef QSG_RUNTIME_DESCRIPTION
+ qsgnode_set_description(this, QLatin1String("rectangle"));
+#endif
+}
+
+void QSGBasicRectangleNode::setRect(const QRectF &rect)
+{
+ if (rect == m_rect)
+ return;
+ m_rect = rect;
+ m_dirty_geometry = true;
+}
+
+void QSGBasicRectangleNode::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+ m_color = color;
+ if (m_gradient_stops.isEmpty())
+ m_dirty_geometry = true;
+}
+
+void QSGBasicRectangleNode::setPenColor(const QColor &color)
+{
+ if (color == m_border_color)
+ return;
+ m_border_color = color;
+ if (m_pen_width > 0)
+ m_dirty_geometry = true;
+}
+
+void QSGBasicRectangleNode::setPenWidth(qreal width)
+{
+ if (width == m_pen_width)
+ return;
+ m_pen_width = width;
+ m_dirty_geometry = true;
+}
+
+
+void QSGBasicRectangleNode::setGradientStops(const QGradientStops &stops)
+{
+ if (stops.constData() == m_gradient_stops.constData())
+ return;
+
+ m_gradient_stops = stops;
+
+ m_gradient_is_opaque = true;
+ for (int i = 0; i < stops.size(); ++i)
+ m_gradient_is_opaque &= stops.at(i).second.alpha() == 0xff;
+ m_dirty_geometry = true;
+}
+
+void QSGBasicRectangleNode::setRadius(qreal radius)
+{
+ if (radius == m_radius)
+ return;
+ m_radius = radius;
+ m_dirty_geometry = true;
+}
+
+void QSGBasicRectangleNode::setAntialiasing(bool antialiasing)
+{
+ if (!supportsAntialiasing())
+ return;
+
+ if (antialiasing == m_antialiasing)
+ return;
+ m_antialiasing = antialiasing;
+ if (m_antialiasing) {
+ setGeometry(new QSGGeometry(smoothAttributeSet(), 0));
+ setFlag(OwnsGeometry, true);
+ } else {
+ setGeometry(&m_geometry);
+ setFlag(OwnsGeometry, false);
+ }
+ updateMaterialAntialiasing();
+ m_dirty_geometry = true;
+}
+
+void QSGBasicRectangleNode::setAligned(bool aligned)
+{
+ if (aligned == m_aligned)
+ return;
+ m_aligned = aligned;
+ m_dirty_geometry = true;
+}
+
+void QSGBasicRectangleNode::update()
+{
+ if (m_dirty_geometry) {
+ updateGeometry();
+ m_dirty_geometry = false;
+
+ QSGNode::DirtyState state = QSGNode::DirtyGeometry;
+ updateMaterialBlending(&state);
+ markDirty(state);
+ }
+}
+
+void QSGBasicRectangleNode::updateGeometry()
+{
+ float width = float(m_rect.width());
+ float height = float(m_rect.height());
+ float penWidth = qMin(qMin(width, height) * 0.5f, float(m_pen_width));
+
+ if (m_aligned)
+ penWidth = qRound(penWidth);
+
+ QSGGeometry *g = geometry();
+ g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
+ int vertexStride = g->sizeOfVertex();
+
+ union {
+ Vertex *vertices;
+ SmoothVertex *smoothVertices;
+ };
+
+ Color4ub fillColor = colorToColor4ub(m_color);
+ Color4ub borderColor = colorToColor4ub(m_border_color);
+ Color4ub transparent = { 0, 0, 0, 0 };
+ const QGradientStops &stops = m_gradient_stops;
+
+ int nextGradientStop = 0;
+ float gradientPos = penWidth / height;
+ while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos)
+ ++nextGradientStop;
+ int lastGradientStop = stops.size() - 1;
+ float lastGradientPos = 1.0f - penWidth / height;
+ while (lastGradientStop >= nextGradientStop && stops.at(lastGradientStop).first >= lastGradientPos)
+ --lastGradientStop;
+ int gradientIntersections = (lastGradientStop - nextGradientStop + 1);
+
+ if (m_radius > 0) {
+ // Rounded corners.
+
+ // Radius should never exceeds half of the width or half of the height
+ float radius = qMin(qMin(width, height) * 0.5f, float(m_radius));
+ QRectF innerRect = m_rect;
+ innerRect.adjust(radius, radius, -radius, -radius);
+
+ float innerRadius = radius - penWidth * 1.0f;
+ float outerRadius = radius;
+ float delta = qMin(width, height) * 0.5f;
+
+ // Number of segments per corner, approximately one per 3 pixels.
+ int segments = qBound(3, qCeil(outerRadius * (M_PI / 6)), 18);
+
+ /*
+
+ --+--__
+ --+--__--__
+ | --__--__
+ | seg --__--+
+ --+-__ ment _+ \
+ --+-__--__ - \ \
+ --__--+ se \ \
+ + \ g \ \
+ \ \ m \ \
+ -----------+--+ e \ \ <- gradient line
+ \ \ nt\ \
+ fill +--+----+--+
+ | | | |
+ border
+ inner AA outer AA (AA = antialiasing)
+
+ */
+
+ int innerVertexCount = (segments + 1) * 4 + gradientIntersections * 2;
+ int outerVertexCount = (segments + 1) * 4;
+ int vertexCount = innerVertexCount;
+ if (m_antialiasing || penWidth)
+ vertexCount += innerVertexCount;
+ if (penWidth)
+ vertexCount += outerVertexCount;
+ if (m_antialiasing && penWidth)
+ vertexCount += outerVertexCount;
+
+ int fillIndexCount = innerVertexCount;
+ int innerAAIndexCount = innerVertexCount * 2 + 2;
+ int borderIndexCount = innerVertexCount * 2 + 2;
+ int outerAAIndexCount = outerVertexCount * 2 + 2;
+ int indexCount = 0;
+ int fillHead = 0;
+ int innerAAHead = 0;
+ int innerAATail = 0;
+ int borderHead = 0;
+ int borderTail = 0;
+ int outerAAHead = 0;
+ int outerAATail = 0;
+ bool hasFill = m_color.alpha() > 0 || !stops.isEmpty();
+ if (hasFill)
+ indexCount += fillIndexCount;
+ if (m_antialiasing) {
+ innerAATail = innerAAHead = indexCount + (innerAAIndexCount >> 1) + 1;
+ indexCount += innerAAIndexCount;
+ }
+ if (penWidth) {
+ borderTail = borderHead = indexCount + (borderIndexCount >> 1) + 1;
+ indexCount += borderIndexCount;
+ }
+ if (m_antialiasing && penWidth) {
+ outerAATail = outerAAHead = indexCount + (outerAAIndexCount >> 1) + 1;
+ indexCount += outerAAIndexCount;
+ }
+
+ g->allocate(vertexCount, indexCount);
+ vertices = reinterpret_cast<Vertex *>(g->vertexData());
+ memset(vertices, 0, vertexCount * vertexStride);
+ quint16 *indices = g->indexDataAsUShort();
+ quint16 index = 0;
+
+ float py = 0; // previous inner y-coordinate.
+ float plx = 0; // previous inner left x-coordinate.
+ float prx = 0; // previous inner right x-coordinate.
+
+ float angle = 0.5f * float(M_PI) / segments;
+ float cosStep = qFastCos(angle);
+ float sinStep = qFastSin(angle);
+
+ for (int part = 0; part < 2; ++part) {
+ float c = 1 - part;
+ float s = part;
+ for (int i = 0; i <= segments; ++i) {
+ float y, lx, rx;
+ if (innerRadius > 0) {
+ y = (part ? innerRect.bottom() : innerRect.top()) - innerRadius * c; // current inner y-coordinate.
+ lx = innerRect.left() - innerRadius * s; // current inner left x-coordinate.
+ rx = innerRect.right() + innerRadius * s; // current inner right x-coordinate.
+ gradientPos = ((part ? innerRect.height() : 0) + radius - innerRadius * c) / height;
+ } else {
+ y = (part ? innerRect.bottom() + innerRadius : innerRect.top() - innerRadius); // current inner y-coordinate.
+ lx = innerRect.left() - innerRadius; // current inner left x-coordinate.
+ rx = innerRect.right() + innerRadius; // current inner right x-coordinate.
+ gradientPos = ((part ? innerRect.height() + innerRadius : -innerRadius) + radius) / height;
+ }
+ float Y = (part ? innerRect.bottom() : innerRect.top()) - outerRadius * c; // current outer y-coordinate.
+ float lX = innerRect.left() - outerRadius * s; // current outer left x-coordinate.
+ float rX = innerRect.right() + outerRadius * s; // current outer right x-coordinate.
+
+ while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
+ // Insert vertices at gradient stops.
+ float gy = (innerRect.top() - radius) + stops.at(nextGradientStop).first * height;
+ float t = (gy - py) / (y - py);
+ float glx = plx * (1 - t) + t * lx;
+ float grx = prx * (1 - t) + t * rx;
+
+ fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
+
+ if (hasFill) {
+ indices[fillHead++] = index;
+ indices[fillHead++] = index + 1;
+ }
+
+ if (penWidth) {
+ --borderHead;
+ indices[borderHead] = indices[borderHead + 2];
+ indices[--borderHead] = index + 2;
+ indices[borderTail++] = index + 3;
+ indices[borderTail] = indices[borderTail - 2];
+ ++borderTail;
+ }
+
+ if (m_antialiasing) {
+ indices[--innerAAHead] = index + 2;
+ indices[--innerAAHead] = index;
+ indices[innerAATail++] = index + 1;
+ indices[innerAATail++] = index + 3;
+
+ bool lower = stops.at(nextGradientStop).first > 0.5f;
+ float dy = lower ? qMin(0.0f, height - gy - delta) : qMax(0.0f, delta - gy);
+ smoothVertices[index++].set(grx, gy, fillColor, width - grx - delta, dy);
+ smoothVertices[index++].set(glx, gy, fillColor, delta - glx, dy);
+ if (penWidth) {
+ smoothVertices[index++].set(grx, gy, borderColor, 0.49f * penWidth * s, -0.49f * penWidth * c);
+ smoothVertices[index++].set(glx, gy, borderColor, -0.49f * penWidth * s, -0.49f * penWidth * c);
+ } else {
+ dy = lower ? delta : -delta;
+ smoothVertices[index++].set(grx, gy, transparent, delta, dy);
+ smoothVertices[index++].set(glx, gy, transparent, -delta, dy);
+ }
+ } else {
+ vertices[index++].set(grx, gy, fillColor);
+ vertices[index++].set(glx, gy, fillColor);
+ if (penWidth) {
+ vertices[index++].set(grx, gy, borderColor);
+ vertices[index++].set(glx, gy, borderColor);
+ }
+ }
+ ++nextGradientStop;
+ }
+
+ if (!stops.isEmpty()) {
+ if (nextGradientStop == 0) {
+ fillColor = colorToColor4ub(stops.at(0).second);
+ } else if (nextGradientStop == stops.size()) {
+ fillColor = colorToColor4ub(stops.last().second);
+ } else {
+ const QGradientStop &prev = stops.at(nextGradientStop - 1);
+ const QGradientStop &next = stops.at(nextGradientStop);
+ float t = (gradientPos - prev.first) / (next.first - prev.first);
+ fillColor = colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t;
+ }
+ }
+
+ if (hasFill) {
+ indices[fillHead++] = index;
+ indices[fillHead++] = index + 1;
+ }
+
+ if (penWidth) {
+ indices[--borderHead] = index + 4;
+ indices[--borderHead] = index + 2;
+ indices[borderTail++] = index + 3;
+ indices[borderTail++] = index + 5;
+ }
+
+ if (m_antialiasing) {
+ indices[--innerAAHead] = index + 2;
+ indices[--innerAAHead] = index;
+ indices[innerAATail++] = index + 1;
+ indices[innerAATail++] = index + 3;
+
+ float dy = part ? qMin(0.0f, height - y - delta) : qMax(0.0f, delta - y);
+ smoothVertices[index++].set(rx, y, fillColor, width - rx - delta, dy);
+ smoothVertices[index++].set(lx, y, fillColor, delta - lx, dy);
+
+ dy = part ? delta : -delta;
+ if (penWidth) {
+ smoothVertices[index++].set(rx, y, borderColor, 0.49f * penWidth * s, -0.49f * penWidth * c);
+ smoothVertices[index++].set(lx, y, borderColor, -0.49f * penWidth * s, -0.49f * penWidth * c);
+ smoothVertices[index++].set(rX, Y, borderColor, -0.49f * penWidth * s, 0.49f * penWidth * c);
+ smoothVertices[index++].set(lX, Y, borderColor, 0.49f * penWidth * s, 0.49f * penWidth * c);
+ smoothVertices[index++].set(rX, Y, transparent, delta, dy);
+ smoothVertices[index++].set(lX, Y, transparent, -delta, dy);
+
+ indices[--outerAAHead] = index - 2;
+ indices[--outerAAHead] = index - 4;
+ indices[outerAATail++] = index - 3;
+ indices[outerAATail++] = index - 1;
+ } else {
+ smoothVertices[index++].set(rx, y, transparent, delta, dy);
+ smoothVertices[index++].set(lx, y, transparent, -delta, dy);
+ }
+ } else {
+ vertices[index++].set(rx, y, fillColor);
+ vertices[index++].set(lx, y, fillColor);
+ if (penWidth) {
+ vertices[index++].set(rx, y, borderColor);
+ vertices[index++].set(lx, y, borderColor);
+ vertices[index++].set(rX, Y, borderColor);
+ vertices[index++].set(lX, Y, borderColor);
+ }
+ }
+
+ py = y;
+ plx = lx;
+ prx = rx;
+
+ // Rotate
+ qreal tmp = c;
+ c = c * cosStep - s * sinStep;
+ s = s * cosStep + tmp * sinStep;
+ }
+ }
+ Q_ASSERT(index == vertexCount);
+
+ // Close the triangle strips.
+ if (m_antialiasing) {
+ indices[--innerAAHead] = indices[innerAATail - 1];
+ indices[--innerAAHead] = indices[innerAATail - 2];
+ Q_ASSERT(innerAATail <= indexCount);
+ }
+ if (penWidth) {
+ indices[--borderHead] = indices[borderTail - 1];
+ indices[--borderHead] = indices[borderTail - 2];
+ Q_ASSERT(borderTail <= indexCount);
+ }
+ if (m_antialiasing && penWidth) {
+ indices[--outerAAHead] = indices[outerAATail - 1];
+ indices[--outerAAHead] = indices[outerAATail - 2];
+ Q_ASSERT(outerAATail == indexCount);
+ }
+ } else {
+ // Straight corners.
+ QRectF innerRect = m_rect;
+ QRectF outerRect = m_rect;
+
+ if (penWidth)
+ innerRect.adjust(1.0f * penWidth, 1.0f * penWidth, -1.0f * penWidth, -1.0f * penWidth);
+
+ float delta = qMin(width, height) * 0.5f;
+ int innerVertexCount = 4 + gradientIntersections * 2;
+ int outerVertexCount = 4;
+ int vertexCount = innerVertexCount;
+ if (m_antialiasing || penWidth)
+ vertexCount += innerVertexCount;
+ if (penWidth)
+ vertexCount += outerVertexCount;
+ if (m_antialiasing && penWidth)
+ vertexCount += outerVertexCount;
+
+ int fillIndexCount = innerVertexCount;
+ int innerAAIndexCount = innerVertexCount * 2 + 2;
+ int borderIndexCount = innerVertexCount * 2 + 2;
+ int outerAAIndexCount = outerVertexCount * 2 + 2;
+ int indexCount = 0;
+ int fillHead = 0;
+ int innerAAHead = 0;
+ int innerAATail = 0;
+ int borderHead = 0;
+ int borderTail = 0;
+ int outerAAHead = 0;
+ int outerAATail = 0;
+ bool hasFill = m_color.alpha() > 0 || !stops.isEmpty();
+ if (hasFill)
+ indexCount += fillIndexCount;
+ if (m_antialiasing) {
+ innerAATail = innerAAHead = indexCount + (innerAAIndexCount >> 1) + 1;
+ indexCount += innerAAIndexCount;
+ }
+ if (penWidth) {
+ borderTail = borderHead = indexCount + (borderIndexCount >> 1) + 1;
+ indexCount += borderIndexCount;
+ }
+ if (m_antialiasing && penWidth) {
+ outerAATail = outerAAHead = indexCount + (outerAAIndexCount >> 1) + 1;
+ indexCount += outerAAIndexCount;
+ }
+
+ g->allocate(vertexCount, indexCount);
+ vertices = reinterpret_cast<Vertex *>(g->vertexData());
+ memset(vertices, 0, vertexCount * vertexStride);
+ quint16 *indices = g->indexDataAsUShort();
+ quint16 index = 0;
+
+ float lx = innerRect.left();
+ float rx = innerRect.right();
+ float lX = outerRect.left();
+ float rX = outerRect.right();
+
+ for (int part = -1; part <= 1; part += 2) {
+ float y = (part == 1 ? innerRect.bottom() : innerRect.top());
+ float Y = (part == 1 ? outerRect.bottom() : outerRect.top());
+ gradientPos = (y - innerRect.top() + penWidth) / height;
+
+ while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
+ // Insert vertices at gradient stops.
+ float gy = (innerRect.top() - penWidth) + stops.at(nextGradientStop).first * height;
+
+ fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
+
+ if (hasFill) {
+ indices[fillHead++] = index;
+ indices[fillHead++] = index + 1;
+ }
+
+ if (penWidth) {
+ --borderHead;
+ indices[borderHead] = indices[borderHead + 2];
+ indices[--borderHead] = index + 2;
+ indices[borderTail++] = index + 3;
+ indices[borderTail] = indices[borderTail - 2];
+ ++borderTail;
+ }
+
+ if (m_antialiasing) {
+ indices[--innerAAHead] = index + 2;
+ indices[--innerAAHead] = index;
+ indices[innerAATail++] = index + 1;
+ indices[innerAATail++] = index + 3;
+
+ bool lower = stops.at(nextGradientStop).first > 0.5f;
+ float dy = lower ? qMin(0.0f, height - gy - delta) : qMax(0.0f, delta - gy);
+ smoothVertices[index++].set(rx, gy, fillColor, width - rx - delta, dy);
+ smoothVertices[index++].set(lx, gy, fillColor, delta - lx, dy);
+ if (penWidth) {
+ smoothVertices[index++].set(rx, gy, borderColor, 0.49f * penWidth, (lower ? 0.49f : -0.49f) * penWidth);
+ smoothVertices[index++].set(lx, gy, borderColor, -0.49f * penWidth, (lower ? 0.49f : -0.49f) * penWidth);
+ } else {
+ smoothVertices[index++].set(rx, gy, transparent, delta, lower ? delta : -delta);
+ smoothVertices[index++].set(lx, gy, transparent, -delta, lower ? delta : -delta);
+ }
+ } else {
+ vertices[index++].set(rx, gy, fillColor);
+ vertices[index++].set(lx, gy, fillColor);
+ if (penWidth) {
+ vertices[index++].set(rx, gy, borderColor);
+ vertices[index++].set(lx, gy, borderColor);
+ }
+ }
+ ++nextGradientStop;
+ }
+
+ if (!stops.isEmpty()) {
+ if (nextGradientStop == 0) {
+ fillColor = colorToColor4ub(stops.at(0).second);
+ } else if (nextGradientStop == stops.size()) {
+ fillColor = colorToColor4ub(stops.last().second);
+ } else {
+ const QGradientStop &prev = stops.at(nextGradientStop - 1);
+ const QGradientStop &next = stops.at(nextGradientStop);
+ float t = (gradientPos - prev.first) / (next.first - prev.first);
+ fillColor = colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t;
+ }
+ }
+
+ if (hasFill) {
+ indices[fillHead++] = index;
+ indices[fillHead++] = index + 1;
+ }
+
+ if (penWidth) {
+ indices[--borderHead] = index + 4;
+ indices[--borderHead] = index + 2;
+ indices[borderTail++] = index + 3;
+ indices[borderTail++] = index + 5;
+ }
+
+ if (m_antialiasing) {
+ indices[--innerAAHead] = index + 2;
+ indices[--innerAAHead] = index;
+ indices[innerAATail++] = index + 1;
+ indices[innerAATail++] = index + 3;
+
+ float dy = part == 1 ? qMin(0.0f, height - y - delta) : qMax(0.0f, delta - y);
+ smoothVertices[index++].set(rx, y, fillColor, width - rx - delta, dy);
+ smoothVertices[index++].set(lx, y, fillColor, delta - lx, dy);
+
+ if (penWidth) {
+ smoothVertices[index++].set(rx, y, borderColor, 0.49f * penWidth, 0.49f * penWidth * part);
+ smoothVertices[index++].set(lx, y, borderColor, -0.49f * penWidth, 0.49f * penWidth * part);
+ smoothVertices[index++].set(rX, Y, borderColor, -0.49f * penWidth, -0.49f * penWidth * part);
+ smoothVertices[index++].set(lX, Y, borderColor, 0.49f * penWidth, -0.49f * penWidth * part);
+ smoothVertices[index++].set(rX, Y, transparent, delta, delta * part);
+ smoothVertices[index++].set(lX, Y, transparent, -delta, delta * part);
+
+ indices[--outerAAHead] = index - 2;
+ indices[--outerAAHead] = index - 4;
+ indices[outerAATail++] = index - 3;
+ indices[outerAATail++] = index - 1;
+ } else {
+ smoothVertices[index++].set(rx, y, transparent, delta, delta * part);
+ smoothVertices[index++].set(lx, y, transparent, -delta, delta * part);
+ }
+ } else {
+ vertices[index++].set(rx, y, fillColor);
+ vertices[index++].set(lx, y, fillColor);
+ if (penWidth) {
+ vertices[index++].set(rx, y, borderColor);
+ vertices[index++].set(lx, y, borderColor);
+ vertices[index++].set(rX, Y, borderColor);
+ vertices[index++].set(lX, Y, borderColor);
+ }
+ }
+ }
+ Q_ASSERT(index == vertexCount);
+
+ // Close the triangle strips.
+ if (m_antialiasing) {
+ indices[--innerAAHead] = indices[innerAATail - 1];
+ indices[--innerAAHead] = indices[innerAATail - 2];
+ Q_ASSERT(innerAATail <= indexCount);
+ }
+ if (penWidth) {
+ indices[--borderHead] = indices[borderTail - 1];
+ indices[--borderHead] = indices[borderTail - 2];
+ Q_ASSERT(borderTail <= indexCount);
+ }
+ if (m_antialiasing && penWidth) {
+ indices[--outerAAHead] = indices[outerAATail - 1];
+ indices[--outerAAHead] = indices[outerAATail - 2];
+ Q_ASSERT(outerAATail == indexCount);
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgbasicrectanglenode_p.h b/src/quick/scenegraph/qsgbasicrectanglenode_p.h
new file mode 100644
index 0000000000..b1d1457590
--- /dev/null
+++ b/src/quick/scenegraph/qsgbasicrectanglenode_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSGBASICRECTANGLENODE_P_H
+#define QSGBASICRECTANGLENODE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qsgadaptationlayer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_PRIVATE_EXPORT QSGBasicRectangleNode : public QSGRectangleNode
+{
+public:
+ QSGBasicRectangleNode();
+
+ void setRect(const QRectF &rect) override;
+ void setColor(const QColor &color) override;
+ void setPenColor(const QColor &color) override;
+ void setPenWidth(qreal width) override;
+ void setGradientStops(const QGradientStops &stops) override;
+ void setRadius(qreal radius) override;
+ void setAntialiasing(bool antialiasing) override;
+ void setAligned(bool aligned) override;
+ void update() override;
+
+protected:
+ virtual bool supportsAntialiasing() const { return true; }
+ virtual void updateMaterialAntialiasing() = 0;
+ virtual void updateMaterialBlending(QSGNode::DirtyState *state) = 0;
+
+ void updateGeometry();
+ void updateGradientTexture();
+
+ QRectF m_rect;
+ QGradientStops m_gradient_stops;
+ QColor m_color;
+ QColor m_border_color;
+ qreal m_radius;
+ qreal m_pen_width;
+
+ uint m_aligned : 1;
+ uint m_antialiasing : 1;
+ uint m_gradient_is_opaque : 1;
+ uint m_dirty_geometry : 1;
+
+ QSGGeometry m_geometry;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index 6572ceb2ce..40d65d99aa 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -38,27 +38,13 @@
****************************************************************************/
#include <QtQuick/private/qsgcontext_p.h>
-#include <QtQuick/private/qsgbatchrenderer_p.h>
-#include <QtQuick/private/qsgdistancefieldutil_p.h>
-#include <QtQuick/private/qsgdefaultdistancefieldglyphcache_p.h>
-#include <QtQuick/private/qsgdefaultrectanglenode_p.h>
-#include <QtQuick/private/qsgdefaultimagenode_p.h>
-#include <QtQuick/private/qsgdefaultpainternode_p.h>
-#include <QtQuick/private/qsgdefaultglyphnode_p.h>
-#include <QtQuick/private/qsgdistancefieldglyphnode_p.h>
-#include <QtQuick/private/qsgdistancefieldglyphnode_p_p.h>
-#include <QtQuick/private/qsgatlastexture_p.h>
-#include <QtQuick/private/qsgrenderloop_p.h>
-#include <QtQuick/private/qsgdefaultlayer_p.h>
-
#include <QtQuick/private/qsgtexture_p.h>
#include <QtQuick/private/qquickpixmapcache_p.h>
+#include <QtQuick/private/qsgadaptationlayer_p.h>
#include <QGuiApplication>
#include <QScreen>
-#include <QOpenGLContext>
#include <QQuickWindow>
-#include <QtGui/qopenglframebufferobject.h>
#include <private/qqmlglobal_p.h>
@@ -69,8 +55,6 @@
#include <private/qobject_p.h>
#include <qmutex.h>
-DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
-
/*
Comments about this class from Gunnar:
@@ -114,31 +98,9 @@ Q_LOGGING_CATEGORY(QSG_LOG_TIME_GLYPH, "qt.scenegraph.time.glyph")
// Timing inside the renderer base class
Q_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERER, "qt.scenegraph.time.renderer")
-class QSGContextPrivate : public QObjectPrivate
-{
-public:
- QSGContextPrivate()
- : antialiasingMethod(QSGContext::UndecidedAntialiasing)
- , distanceFieldDisabled(qmlDisableDistanceField())
- , distanceFieldAntialiasing(QSGGlyphNode::HighQualitySubPixelAntialiasing)
- , distanceFieldAntialiasingDecided(false)
- {
- }
-
- ~QSGContextPrivate()
- {
- }
-
- QMutex mutex;
- QSGContext::AntialiasingMethod antialiasingMethod;
- bool distanceFieldDisabled;
- QSGDistanceFieldGlyphNode::AntialiasingMode distanceFieldAntialiasing;
- bool distanceFieldAntialiasingDecided;
-};
-
-static bool qsg_useConsistentTiming()
+bool qsg_useConsistentTiming()
{
- static int use = -1;
+ int use = -1;
if (use < 0) {
use = !qEnvironmentVariableIsEmpty("QSG_FIXED_ANIMATION_STEP") && qgetenv("QSG_FIXED_ANIMATION_STEP") != "no"
? 1 : 0;
@@ -274,20 +236,6 @@ public:
QSGTexture *texture;
};
-namespace QSGMultisampleAntialiasing {
- class ImageNode : public QSGDefaultImageNode {
- public:
- void setAntialiasing(bool) { }
- };
-
-
- class RectangleNode : public QSGDefaultRectangleNode {
- public:
- void setAntialiasing(bool) { }
- };
-}
-
-
/*!
\class QSGContext
@@ -300,92 +248,16 @@ namespace QSGMultisampleAntialiasing {
*/
QSGContext::QSGContext(QObject *parent) :
- QObject(*(new QSGContextPrivate), parent)
+ QObject(parent)
{
- Q_D(QSGContext);
- if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QSG_DISTANCEFIELD_ANTIALIASING"))) {
- const QByteArray mode = qgetenv("QSG_DISTANCEFIELD_ANTIALIASING");
- d->distanceFieldAntialiasingDecided = true;
- if (mode == "subpixel")
- d->distanceFieldAntialiasing = QSGGlyphNode::HighQualitySubPixelAntialiasing;
- else if (mode == "subpixel-lowq")
- d->distanceFieldAntialiasing = QSGGlyphNode::LowQualitySubPixelAntialiasing;
- else if (mode == "gray")
- d->distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing;
- }
-
- // Adds compatibility with Qt 5.3 and earlier's QSG_RENDER_TIMING
- if (qEnvironmentVariableIsSet("QSG_RENDER_TIMING")) {
- const_cast<QLoggingCategory &>(QSG_LOG_TIME_GLYPH()).setEnabled(QtDebugMsg, true);
- const_cast<QLoggingCategory &>(QSG_LOG_TIME_TEXTURE()).setEnabled(QtDebugMsg, true);
- const_cast<QLoggingCategory &>(QSG_LOG_TIME_RENDERER()).setEnabled(QtDebugMsg, true);
- const_cast<QLoggingCategory &>(QSG_LOG_TIME_RENDERLOOP()).setEnabled(QtDebugMsg, true);
- const_cast<QLoggingCategory &>(QSG_LOG_TIME_COMPILATION()).setEnabled(QtDebugMsg, true);
- }
}
-
QSGContext::~QSGContext()
{
}
-QSGRenderContext *QSGContext::createRenderContext()
+void QSGContext::renderContextInitialized(QSGRenderContext *)
{
- return new QSGRenderContext(this);
-}
-
-void QSGContext::renderContextInitialized(QSGRenderContext *renderContext)
-{
- Q_D(QSGContext);
-
- d->mutex.lock();
- if (d->antialiasingMethod == UndecidedAntialiasing) {
- if (Q_UNLIKELY(qEnvironmentVariableIsSet("QSG_ANTIALIASING_METHOD"))) {
- const QByteArray aaType = qgetenv("QSG_ANTIALIASING_METHOD");
- if (aaType == "msaa")
- d->antialiasingMethod = MsaaAntialiasing;
- else if (aaType == "vertex")
- d->antialiasingMethod = VertexAntialiasing;
- }
- if (d->antialiasingMethod == UndecidedAntialiasing) {
- if (renderContext->openglContext()->format().samples() > 0)
- d->antialiasingMethod = MsaaAntialiasing;
- else
- d->antialiasingMethod = VertexAntialiasing;
- }
- }
-
- // With OpenGL ES, except for Angle on Windows, use GrayAntialiasing, unless
- // some value had been requested explicitly. This could not be decided
- // before without a context. Now the context is ready.
- if (!d->distanceFieldAntialiasingDecided) {
- d->distanceFieldAntialiasingDecided = true;
-#ifndef Q_OS_WIN32
- if (renderContext->openglContext()->isOpenGLES())
- d->distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing;
-#endif
- }
-
- static bool dumped = false;
- if (!dumped && QSG_LOG_INFO().isDebugEnabled()) {
- dumped = true;
- QSurfaceFormat format = renderContext->openglContext()->format();
- QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
- qCDebug(QSG_LOG_INFO) << "R/G/B/A Buffers: " << format.redBufferSize() << format.greenBufferSize() << format.blueBufferSize() << format.alphaBufferSize();
- qCDebug(QSG_LOG_INFO) << "Depth Buffer: " << format.depthBufferSize();
- qCDebug(QSG_LOG_INFO) << "Stencil Buffer: " << format.stencilBufferSize();
- qCDebug(QSG_LOG_INFO) << "Samples: " << format.samples();
- qCDebug(QSG_LOG_INFO) << "GL_VENDOR: " << (const char *) funcs->glGetString(GL_VENDOR);
- qCDebug(QSG_LOG_INFO) << "GL_RENDERER: " << (const char *) funcs->glGetString(GL_RENDERER);
- qCDebug(QSG_LOG_INFO) << "GL_VERSION: " << (const char *) funcs->glGetString(GL_VERSION);
- QSet<QByteArray> exts = renderContext->openglContext()->extensions();
- QByteArray all; foreach (const QByteArray &e, exts) all += ' ' + e;
- qCDebug(QSG_LOG_INFO) << "GL_EXTENSIONS: " << all.constData();
- qCDebug(QSG_LOG_INFO) << "Max Texture Size: " << renderContext->maxTextureSize();
- qCDebug(QSG_LOG_INFO) << "Debug context: " << format.testOption(QSurfaceFormat::DebugContext);
- }
-
- d->mutex.unlock();
}
void QSGContext::renderContextInvalidated(QSGRenderContext *)
@@ -406,88 +278,33 @@ QSGRectangleNode *QSGContext::createRectangleNode(const QRectF &rect, const QCol
}
/*!
- Factory function for scene graph backends of the Rectangle element.
- */
-QSGRectangleNode *QSGContext::createRectangleNode()
-{
- Q_D(QSGContext);
- return d->antialiasingMethod == MsaaAntialiasing
- ? new QSGMultisampleAntialiasing::RectangleNode
- : new QSGDefaultRectangleNode;
-}
-
-/*!
- Factory function for scene graph backends of the Image element.
- */
-QSGImageNode *QSGContext::createImageNode()
-{
- Q_D(QSGContext);
- return d->antialiasingMethod == MsaaAntialiasing
- ? new QSGMultisampleAntialiasing::ImageNode
- : new QSGDefaultImageNode;
-}
-
-/*!
- Factory function for scene graph backends of Painter elements
- */
-QSGPainterNode *QSGContext::createPainterNode(QQuickPaintedItem *item)
-{
- return new QSGDefaultPainterNode(item);
-}
-
-/*!
- Factory function for scene graph backends of the Text elements;
+ Creates a new shader effect helper instance. This function is called on the
+ gui thread, unlike the others. This is necessary in order to provide
+ adaptable, backend-specific shader effect functionality to the gui thread too.
*/
-QSGGlyphNode *QSGContext::createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode)
+QSGGuiThreadShaderEffectManager *QSGContext::createGuiThreadShaderEffectManager()
{
- Q_D(QSGContext);
-
- if (d->distanceFieldDisabled || preferNativeGlyphNode) {
- return new QSGDefaultGlyphNode;
- } else {
- QSGDistanceFieldGlyphNode *node = new QSGDistanceFieldGlyphNode(rc);
- node->setPreferredAntialiasingMode(d->distanceFieldAntialiasing);
- return node;
- }
+ return nullptr;
}
/*!
- * Factory function for scene graph backends of the QStyle stylable elements. Returns a
- * null pointer if the backend doesn't provide its own node type.
+ Creates a new shader effect node. The default of returning nullptr is
+ valid as long as the backend does not claim SupportsShaderEffectNode or
+ ignoring ShaderEffect elements is acceptable.
*/
-QSGNinePatchNode *QSGContext::createNinePatchNode()
+QSGShaderEffectNode *QSGContext::createShaderEffectNode(QSGRenderContext *, QSGGuiThreadShaderEffectManager *)
{
- return 0;
+ return nullptr;
}
/*!
- Factory function for scene graph backends of layers.
+ Creates a new animation driver.
*/
-QSGLayer *QSGContext::createLayer(QSGRenderContext *renderContext)
-{
- return new QSGDefaultLayer(renderContext);
-}
-
-QSurfaceFormat QSGContext::defaultSurfaceFormat() const
+QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent)
{
- QSurfaceFormat format = QSurfaceFormat::defaultFormat();
- static bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER");
- static bool useStencil = qEnvironmentVariableIsEmpty("QSG_NO_STENCIL_BUFFER");
- static bool enableDebug = qEnvironmentVariableIsSet("QSG_OPENGL_DEBUG");
- format.setDepthBufferSize(useDepth ? 24 : 0);
- format.setStencilBufferSize(useStencil ? 8 : 0);
- if (enableDebug)
- format.setOption(QSurfaceFormat::DebugContext);
- if (QQuickWindow::hasDefaultAlphaBuffer())
- format.setAlphaBufferSize(8);
- format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
- return format;
+ return new QSGAnimationDriver(parent);
}
-/*!
- Returns the minimum supported framebuffer object size.
- */
-
QSize QSGContext::minimumFBOSize() const
{
#ifdef Q_OS_MAC
@@ -497,46 +314,22 @@ QSize QSGContext::minimumFBOSize() const
return QSize(1, 1);
}
-
-
/*!
- Sets whether or not the scene graph should use the distance field technique to render text
- */
-void QSGContext::setDistanceFieldEnabled(bool enabled)
-{
- d_func()->distanceFieldDisabled = !enabled;
-}
+ Returns a pointer to the (presumably) global renderer interface.
-
-/*!
- Returns true if the scene graph uses the distance field technique to render text
+ \note This function may be called on the gui thread in order to get access
+ to QSGRendererInterface::graphicsApi().
*/
-bool QSGContext::isDistanceFieldEnabled() const
+QSGRendererInterface *QSGContext::rendererInterface(QSGRenderContext *renderContext)
{
- return !d_func()->distanceFieldDisabled;
-}
-
-
-
-/*!
- Creates a new animation driver.
- */
-
-QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent)
-{
- return new QSGAnimationDriver(parent);
+ Q_UNUSED(renderContext);
+ qWarning("QSGRendererInterface not implemented");
+ return nullptr;
}
QSGRenderContext::QSGRenderContext(QSGContext *context)
- : m_gl(0)
- , m_sg(context)
- , m_atlasManager(0)
- , m_depthStencilManager(0)
+ : m_sg(context)
, m_distanceFieldCacheManager(0)
- , m_maxTextureSize(0)
- , m_brokenIBOs(false)
- , m_serializedRender(false)
- , m_attachToGLContext(true)
{
}
@@ -545,55 +338,31 @@ QSGRenderContext::~QSGRenderContext()
invalidate();
}
-void QSGRenderContext::endSync()
+void QSGRenderContext::initialize(void *context)
{
- qDeleteAll(m_texturesToDelete);
- m_texturesToDelete.clear();
+ Q_UNUSED(context);
}
-static QBasicMutex qsg_framerender_mutex;
-
-void QSGRenderContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId)
+void QSGRenderContext::invalidate()
{
- if (m_serializedRender)
- qsg_framerender_mutex.lock();
-
- renderer->renderScene(fboId);
-
- if (m_serializedRender)
- qsg_framerender_mutex.unlock();
+ m_sg->renderContextInvalidated(this);
+ emit invalidated();
+}
+void QSGRenderContext::endSync()
+{
+ qDeleteAll(m_texturesToDelete);
+ m_texturesToDelete.clear();
}
/*!
Factory function for scene graph backends of the distance-field glyph cache.
*/
-QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRawFont &font)
-{
- if (!m_distanceFieldCacheManager)
- m_distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager;
-
- QSGDistanceFieldGlyphCache *cache = m_distanceFieldCacheManager->cache(font);
- if (!cache) {
- cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font);
- m_distanceFieldCacheManager->insertCache(font, cache);
- }
-
- return cache;
-}
-
-void QSGRenderContext::setAttachToGLContext(bool attach)
+QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRawFont &)
{
- Q_ASSERT(!isValid());
- m_attachToGLContext = attach;
+ return nullptr;
}
-#define QSG_RENDERCONTEXT_PROPERTY "_q_sgrendercontext"
-
-QSGRenderContext *QSGRenderContext::from(QOpenGLContext *context)
-{
- return qobject_cast<QSGRenderContext *>(context->property(QSG_RENDERCONTEXT_PROPERTY).value<QObject *>());
-}
void QSGRenderContext::registerFontengineForCleanup(QFontEngine *engine)
{
@@ -602,178 +371,18 @@ void QSGRenderContext::registerFontengineForCleanup(QFontEngine *engine)
}
/*!
- Initializes the scene graph render context with the GL context \a context. This also
- emits the ready() signal so that the QML graph can start building scene graph nodes.
- */
-void QSGRenderContext::initialize(QOpenGLContext *context)
-{
- QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
- funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
-
- // Sanity check the surface format, in case it was overridden by the application
- QSurfaceFormat requested = m_sg->defaultSurfaceFormat();
- QSurfaceFormat actual = context->format();
- if (requested.depthBufferSize() > 0 && actual.depthBufferSize() <= 0)
- qWarning("QSGContext::initialize: depth buffer support missing, expect rendering errors");
- if (requested.stencilBufferSize() > 0 && actual.stencilBufferSize() <= 0)
- qWarning("QSGContext::initialize: stencil buffer support missing, expect rendering errors");
-
- if (!m_atlasManager)
- m_atlasManager = new QSGAtlasTexture::Manager();
-
- Q_ASSERT_X(!m_gl, "QSGRenderContext::initialize", "already initialized!");
- m_gl = context;
- 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
- const char *vendor = (const char *) funcs->glGetString(GL_VENDOR);
- if (strstr(vendor, "nouveau"))
- m_brokenIBOs = true;
- const char *renderer = (const char *) funcs->glGetString(GL_RENDERER);
- if (strstr(renderer, "llvmpipe"))
- m_serializedRender = true;
- if (strstr(vendor, "Hisilicon Technologies") && strstr(renderer, "Immersion.16"))
- m_brokenIBOs = true;
-#endif
-
- emit initialized();
-}
-
-void QSGRenderContext::invalidate()
-{
- if (!m_gl)
- return;
-
- qDeleteAll(m_texturesToDelete);
- m_texturesToDelete.clear();
-
- qDeleteAll(m_textures);
- m_textures.clear();
-
- /* The cleanup of the atlas textures is a bit intriguing.
- As part of the cleanup in the threaded render loop, we
- do:
- 1. call this function
- 2. call QCoreApp::sendPostedEvents() to immediately process
- any pending deferred deletes.
- 3. delete the GL context.
-
- As textures need the atlas manager while cleaning up, the
- manager needs to be cleaned up after the textures, so
- we post a deleteLater here at the very bottom so it gets
- deferred deleted last.
-
- Another alternative would be to use a QPointer in
- QSGAtlasTexture::Texture, but this seemed simpler.
- */
- m_atlasManager->invalidate();
- m_atlasManager->deleteLater();
- m_atlasManager = 0;
-
- // The following piece of code will read/write to the font engine's caches,
- // potentially from different threads. However, this is safe because this
- // code is only called from QQuickWindow's shutdown which is called
- // only when the GUI is blocked, and multiple threads will call it in
- // sequence. (see qsgdefaultglyphnode_p.cpp's init())
- for (QSet<QFontEngine *>::const_iterator it = m_fontEnginesToClean.constBegin(),
- end = m_fontEnginesToClean.constEnd(); it != end; ++it) {
- (*it)->clearGlyphCache(m_gl);
- if (!(*it)->ref.deref())
- delete *it;
- }
- m_fontEnginesToClean.clear();
-
- delete m_depthStencilManager;
- m_depthStencilManager = 0;
-
- delete m_distanceFieldCacheManager;
- m_distanceFieldCacheManager = 0;
-
- if (m_gl->property(QSG_RENDERCONTEXT_PROPERTY) == QVariant::fromValue(this))
- m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant());
- m_gl = 0;
-
- m_sg->renderContextInvalidated(this);
- emit invalidated();
-}
-
-/*!
- Returns a shared pointer to a depth stencil buffer that can be used with \a fbo.
- */
-QSharedPointer<QSGDepthStencilBuffer> QSGRenderContext::depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo)
-{
- if (!m_gl)
- return QSharedPointer<QSGDepthStencilBuffer>();
- QSGDepthStencilBufferManager *manager = depthStencilBufferManager();
- QSGDepthStencilBuffer::Format format;
- format.size = fbo->size();
- format.samples = fbo->format().samples();
- format.attachments = QSGDepthStencilBuffer::DepthAttachment | QSGDepthStencilBuffer::StencilAttachment;
- QSharedPointer<QSGDepthStencilBuffer> buffer = manager->bufferForFormat(format);
- if (buffer.isNull()) {
- buffer = QSharedPointer<QSGDepthStencilBuffer>(new QSGDefaultDepthStencilBuffer(m_gl, format));
- manager->insertBuffer(buffer);
- }
- return buffer;
-}
-
-/*!
- Returns a pointer to the context's depth/stencil buffer manager. This is useful for custom
- implementations of \l depthStencilBufferForFbo().
- */
-QSGDepthStencilBufferManager *QSGRenderContext::depthStencilBufferManager()
-{
- if (!m_gl)
- return 0;
- if (!m_depthStencilManager)
- m_depthStencilManager = new QSGDepthStencilBufferManager(m_gl);
- return m_depthStencilManager;
-}
-
-
-/*!
Factory function for texture objects.
If \a image is a valid image, the QSGTexture::setImage function
will be called with \a image as argument.
*/
-QSGTexture *QSGRenderContext::createTexture(const QImage &image, uint flags) const
-{
- bool atlas = flags & CreateTexture_Atlas;
- bool mipmap = flags & CreateTexture_Mipmap;
- bool alpha = flags & CreateTexture_Alpha;
-
- // The atlas implementation is only supported from the render thread and
- // does not support mipmaps.
- if (!mipmap && atlas && openglContext() && QThread::currentThread() == openglContext()->thread()) {
- QSGTexture *t = m_atlasManager->create(image, alpha);
- if (t)
- return t;
- }
-
- QSGPlainTexture *texture = new QSGPlainTexture();
- texture->setImage(image);
- if (texture->hasAlphaChannel() && !alpha)
- texture->setHasAlphaChannel(false);
-
- return texture;
-}
-
/*!
Factory function for the scene graph renderers.
The renderers are used for the toplevel renderer and once for every
QQuickShaderEffectSource used in the QML scene.
*/
-QSGRenderer *QSGRenderContext::createRenderer()
-{
- return new QSGBatchRenderer::Renderer(this);
-}
QSGTexture *QSGRenderContext::textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window)
{
@@ -803,41 +412,6 @@ void QSGRenderContext::textureFactoryDestroyed(QObject *o)
m_mutex.unlock();
}
-/*!
- Compile \a shader, optionally using \a vertexCode and \a fragmentCode as
- replacement for the source code supplied by \a shader.
-
- If \a vertexCode or \a fragmentCode is supplied, the caller is responsible
- for setting up attribute bindings.
-
- \a material is supplied in case the implementation needs to take the
- material flags into account.
- */
-
-void QSGRenderContext::compile(QSGMaterialShader *shader, QSGMaterial *material, const char *vertexCode, const char *fragmentCode)
-{
- Q_UNUSED(material);
- if (vertexCode || fragmentCode) {
- Q_ASSERT_X((material->flags() & QSGMaterial::CustomCompileStep) == 0,
- "QSGRenderContext::compile()",
- "materials with custom compile step cannot have custom vertex/fragment code");
- QOpenGLShaderProgram *p = shader->program();
- p->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexCode ? vertexCode : shader->vertexShader());
- p->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentCode ? fragmentCode : shader->fragmentShader());
- p->link();
- if (!p->isLinked())
- qWarning() << "shader compilation failed:" << endl << p->log();
- } else {
- shader->compile();
- }
-}
-
-void QSGRenderContext::initialize(QSGMaterialShader *shader)
-{
- shader->program()->bind();
- shader->initialize();
-}
-
#include "qsgcontext.moc"
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index 38d0cdaccc..2fef0ff1e8 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -53,6 +53,7 @@
#include <QtCore/QObject>
#include <QtCore/qabstractanimation.h>
+#include <QtCore/QMutex>
#include <QtGui/QImage>
#include <QtGui/QSurfaceFormat>
@@ -61,14 +62,9 @@
#include <private/qrawfont_p.h>
#include <QtQuick/qsgnode.h>
-#include <QtQuick/private/qsgdepthstencilbuffer_p.h>
QT_BEGIN_NAMESPACE
-namespace QSGAtlasTexture {
- class Manager;
-}
-
class QSGContextPrivate;
class QSGRectangleNode;
class QSGImageNode;
@@ -80,17 +76,15 @@ class QSGDistanceFieldGlyphCache;
class QQuickWindow;
class QSGTexture;
class QSGMaterial;
-class QSGMaterialShader;
class QSGRenderLoop;
class QSGLayer;
-
-class QOpenGLContext;
-class QOpenGLFramebufferObject;
-
class QQuickTextureFactory;
class QSGDistanceFieldGlyphCacheManager;
class QSGContext;
class QQuickPaintedItem;
+class QSGRendererInterface;
+class QSGShaderEffectNode;
+class QSGGuiThreadShaderEffectManager;
Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERLOOP)
Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_COMPILATION)
@@ -112,39 +106,24 @@ public:
};
QSGRenderContext(QSGContext *context);
- ~QSGRenderContext();
+ virtual ~QSGRenderContext();
- QOpenGLContext *openglContext() const { return m_gl; }
QSGContext *sceneGraphContext() const { return m_sg; }
- virtual bool isValid() const { return m_gl; }
+ virtual bool isValid() const { return true; }
- virtual void initialize(QOpenGLContext *context);
+ virtual void initialize(void *context);
virtual void invalidate();
-
- virtual void renderNextFrame(QSGRenderer *renderer, GLuint fboId);
+ virtual void renderNextFrame(QSGRenderer *renderer, uint fboId) = 0;
virtual void endSync();
- virtual QSharedPointer<QSGDepthStencilBuffer> depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo);
- QSGDepthStencilBufferManager *depthStencilBufferManager();
-
virtual QSGDistanceFieldGlyphCache *distanceFieldGlyphCache(const QRawFont &font);
QSGTexture *textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window);
- virtual QSGTexture *createTexture(const QImage &image, uint flags = CreateTexture_Alpha) const;
-
- virtual QSGRenderer *createRenderer();
+ virtual QSGTexture *createTexture(const QImage &image, uint flags = CreateTexture_Alpha) const = 0;
+ virtual QSGRenderer *createRenderer() = 0;
- 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);
-
- bool hasBrokenIndexBufferObjects() const { return m_brokenIBOs; }
- int maxTextureSize() const { return m_maxTextureSize; }
-
Q_SIGNALS:
void initialized();
void invalidated();
@@ -153,29 +132,20 @@ public Q_SLOTS:
void textureFactoryDestroyed(QObject *o);
protected:
- QOpenGLContext *m_gl;
QSGContext *m_sg;
QMutex m_mutex;
QHash<QQuickTextureFactory *, QSGTexture *> m_textures;
QSet<QSGTexture *> m_texturesToDelete;
- QSGAtlasTexture::Manager *m_atlasManager;
-
- QSGDepthStencilBufferManager *m_depthStencilManager;
QSGDistanceFieldGlyphCacheManager *m_distanceFieldCacheManager;
QSet<QFontEngine *> m_fontEnginesToClean;
- int m_maxTextureSize;
- bool m_brokenIBOs;
- bool m_serializedRender;
- bool m_attachToGLContext;
};
class Q_QUICK_PRIVATE_EXPORT QSGContext : public QObject
{
Q_OBJECT
- Q_DECLARE_PRIVATE(QSGContext)
public:
enum AntialiasingMethod {
@@ -185,30 +155,34 @@ public:
};
explicit QSGContext(QObject *parent = 0);
- ~QSGContext();
+ virtual ~QSGContext();
virtual void renderContextInitialized(QSGRenderContext *renderContext);
virtual void renderContextInvalidated(QSGRenderContext *renderContext);
- virtual QSGRenderContext *createRenderContext();
+ virtual QSGRenderContext *createRenderContext() = 0;
QSGRectangleNode *createRectangleNode(const QRectF &rect, const QColor &c);
- virtual QSGRectangleNode *createRectangleNode();
- virtual QSGImageNode *createImageNode();
- virtual QSGPainterNode *createPainterNode(QQuickPaintedItem *item);
- virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode);
- virtual QSGNinePatchNode *createNinePatchNode();
- virtual QSGLayer *createLayer(QSGRenderContext *renderContext);
+ virtual QSGRectangleNode *createRectangleNode() = 0;
+ virtual QSGImageNode *createImageNode() = 0;
+ virtual QSGPainterNode *createPainterNode(QQuickPaintedItem *item) = 0;
+ virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) = 0;
+ virtual QSGNinePatchNode *createNinePatchNode() = 0;
+ virtual QSGLayer *createLayer(QSGRenderContext *renderContext) = 0;
+ virtual QSGGuiThreadShaderEffectManager *createGuiThreadShaderEffectManager();
+ virtual QSGShaderEffectNode *createShaderEffectNode(QSGRenderContext *renderContext,
+ QSGGuiThreadShaderEffectManager *mgr);
virtual QAnimationDriver *createAnimationDriver(QObject *parent);
virtual QSize minimumFBOSize() const;
- virtual QSurfaceFormat defaultSurfaceFormat() const;
+ virtual QSurfaceFormat defaultSurfaceFormat() const = 0;
- void setDistanceFieldEnabled(bool enabled);
- bool isDistanceFieldEnabled() const;
+ virtual QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext);
static QSGContext *createDefaultContext();
static QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image);
static QSGRenderLoop *createWindowManager();
+
+ static void setBackend(const QString &backend);
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgcontextplugin.cpp b/src/quick/scenegraph/qsgcontextplugin.cpp
index f5c2b6880b..7569cd2495 100644
--- a/src/quick/scenegraph/qsgcontextplugin.cpp
+++ b/src/quick/scenegraph/qsgcontextplugin.cpp
@@ -43,8 +43,16 @@
#include <QtCore/private/qfactoryloader_p.h>
#include <QtCore/qlibraryinfo.h>
+// Built-in adaptations
+#include <QtQuick/private/qsgsoftwareadaptation_p.h>
+#ifndef QT_NO_OPENGL
+#include <QtQuick/private/qsgdefaultcontext_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_INFO)
+
QSGContextPlugin::QSGContextPlugin(QObject *parent)
: QObject(parent)
{
@@ -59,61 +67,113 @@ Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
(QSGContextFactoryInterface_iid, QLatin1String("/scenegraph")))
#endif
-struct QSGAdaptionPluginData
+struct QSGAdaptationBackendData
{
- QSGAdaptionPluginData()
- : tried(false)
- , factory(0)
- {
- }
-
- ~QSGAdaptionPluginData()
- {
- }
+ QSGAdaptationBackendData();
bool tried;
QSGContextFactoryInterface *factory;
- QString deviceName;
+ QString name;
+ QSGContextFactoryInterface::Flags flags;
+
+ QVector<QSGContextFactoryInterface *> builtIns;
+
+ QString quickWindowBackendRequest;
};
-Q_GLOBAL_STATIC(QSGAdaptionPluginData, qsg_adaptation_data)
+QSGAdaptationBackendData::QSGAdaptationBackendData()
+ : tried(false)
+ , factory(nullptr)
+ , flags(0)
+{
+ // Fill in the table with the built-in adaptations.
+ builtIns.append(new QSGSoftwareAdaptation);
+}
+
+Q_GLOBAL_STATIC(QSGAdaptationBackendData, qsg_adaptation_data)
+
+// This only works when the backend is loaded (contextFactory() was called),
+// otherwise the return value is 0.
+//
+// Note that the default (OpenGL) implementation always results in 0, custom flags
+// can only be returned from the other (either compiled-in or plugin-based) backends.
+QSGContextFactoryInterface::Flags qsg_backend_flags()
+{
+ return qsg_adaptation_data()->flags;
+}
-QSGAdaptionPluginData *contextFactory()
+QSGAdaptationBackendData *contextFactory()
{
- QSGAdaptionPluginData *plugin = qsg_adaptation_data();
- if (!plugin->tried) {
+ QSGAdaptationBackendData *backendData = qsg_adaptation_data();
+
+ if (!backendData->tried) {
+ backendData->tried = true;
- plugin->tried = true;
const QStringList args = QGuiApplication::arguments();
- QString device;
+ QString requestedBackend = backendData->quickWindowBackendRequest; // empty or set via QQuickWindow::setBackend()
+
for (int index = 0; index < args.count(); ++index) {
if (args.at(index).startsWith(QLatin1String("--device="))) {
- device = args.at(index).mid(9);
+ requestedBackend = args.at(index).mid(9);
break;
}
}
- if (device.isEmpty())
- device = QString::fromLocal8Bit(qgetenv("QMLSCENE_DEVICE"));
-#ifndef QT_NO_LIBRARY
- if (!device.isEmpty()) {
- const int index = loader()->indexOf(device);
- if (index != -1)
- plugin->factory = qobject_cast<QSGContextFactoryInterface*>(loader()->instance(index));
- plugin->deviceName = device;
+ if (requestedBackend.isEmpty() && qEnvironmentVariableIsSet("QMLSCENE_DEVICE"))
+ requestedBackend = QString::fromLocal8Bit(qgetenv("QMLSCENE_DEVICE"));
+
+ // A modern alternative. Scenegraph adaptations can represent backends
+ // for different graphics APIs as well, instead of being specific to
+ // some device or platform.
+ if (requestedBackend.isEmpty() && qEnvironmentVariableIsSet("QT_QUICK_BACKEND"))
+ requestedBackend = QString::fromLocal8Bit(qgetenv("QT_QUICK_BACKEND"));
+
+#ifdef QT_NO_OPENGL
+ // If this is a build without OpenGL, and no backend has been set
+ // default to the software renderer
+ if (requestedBackend.isEmpty())
+ requestedBackend = QString::fromLocal8Bit("software");
+#endif
+
+ if (!requestedBackend.isEmpty()) {
#ifndef QT_NO_DEBUG
- if (!plugin->factory) {
- qWarning("Could not create scene graph context for device '%s'"
- " - check that plugins are installed correctly in %s",
- qPrintable(device),
- qPrintable(QLibraryInfo::location(QLibraryInfo::PluginsPath)));
- }
+ qCDebug(QSG_LOG_INFO) << "Loading backend" << requestedBackend;
#endif
- }
+ // First look for a built-in adaptation.
+ for (QSGContextFactoryInterface *builtInBackend : qAsConst(backendData->builtIns)) {
+ if (builtInBackend->keys().contains(requestedBackend)) {
+ backendData->factory = builtInBackend;
+ backendData->name = requestedBackend;
+ backendData->flags = backendData->factory->flags(requestedBackend);
+ break;
+ }
+ }
+
+ // Then try the plugins.
+ if (!backendData->factory) {
+#ifndef QT_NO_LIBRARY
+ const int index = loader()->indexOf(requestedBackend);
+ if (index != -1)
+ backendData->factory = qobject_cast<QSGContextFactoryInterface*>(loader()->instance(index));
+ if (backendData->factory) {
+ backendData->name = requestedBackend;
+ backendData->flags = backendData->factory->flags(requestedBackend);
+ }
+#ifndef QT_NO_DEBUG
+ if (!backendData->factory) {
+ qWarning("Could not create scene graph context for backend '%s'"
+ " - check that plugins are installed correctly in %s",
+ qPrintable(requestedBackend),
+ qPrintable(QLibraryInfo::location(QLibraryInfo::PluginsPath)));
+ }
+#endif
+ }
#endif // QT_NO_LIBRARY
+ }
}
- return plugin;
+
+ return backendData;
}
@@ -126,10 +186,14 @@ QSGAdaptionPluginData *contextFactory()
*/
QSGContext *QSGContext::createDefaultContext()
{
- QSGAdaptionPluginData *plugin = contextFactory();
- if (plugin->factory)
- return plugin->factory->create(plugin->deviceName);
- return new QSGContext();
+ QSGAdaptationBackendData *backendData = contextFactory();
+ if (backendData->factory)
+ return backendData->factory->create(backendData->name);
+#ifndef QT_NO_OPENGL
+ return new QSGDefaultContext();
+#else
+ return nullptr;
+#endif
}
@@ -143,9 +207,9 @@ QSGContext *QSGContext::createDefaultContext()
QQuickTextureFactory *QSGContext::createTextureFactoryFromImage(const QImage &image)
{
- QSGAdaptionPluginData *plugin = contextFactory();
- if (plugin->factory)
- return plugin->factory->createTextureFactoryFromImage(image);
+ QSGAdaptationBackendData *backendData = contextFactory();
+ if (backendData->factory)
+ return backendData->factory->createTextureFactoryFromImage(image);
return 0;
}
@@ -157,14 +221,19 @@ QQuickTextureFactory *QSGContext::createTextureFactoryFromImage(const QImage &im
QSGRenderLoop *QSGContext::createWindowManager()
{
- QSGAdaptionPluginData *plugin = contextFactory();
- if (plugin->factory)
- return plugin->factory->createWindowManager();
+ QSGAdaptationBackendData *backendData = contextFactory();
+ if (backendData->factory)
+ return backendData->factory->createWindowManager();
return 0;
}
+void QSGContext::setBackend(const QString &backend)
+{
+ QSGAdaptationBackendData *backendData = qsg_adaptation_data();
+ if (backendData->tried)
+ qWarning("Scenegraph already initialized, setBackend() request ignored");
-
-
+ backendData->quickWindowBackendRequest = backend;
+}
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgcontextplugin_p.h b/src/quick/scenegraph/qsgcontextplugin_p.h
index ca326ead07..08c3d21408 100644
--- a/src/quick/scenegraph/qsgcontextplugin_p.h
+++ b/src/quick/scenegraph/qsgcontextplugin_p.h
@@ -64,12 +64,20 @@ class QSGRenderLoop;
struct Q_QUICK_PRIVATE_EXPORT QSGContextFactoryInterface : public QFactoryInterface
{
+ enum Flag {
+ SupportsShaderEffectNode = 0x01
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
virtual QSGContext *create(const QString &key) const = 0;
+ virtual Flags flags(const QString &key) const = 0;
virtual QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image) = 0;
virtual QSGRenderLoop *createWindowManager() = 0;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGContextFactoryInterface::Flags)
+
#define QSGContextFactoryInterface_iid \
"org.qt-project.Qt.QSGContextFactoryInterface"
Q_DECLARE_INTERFACE(QSGContextFactoryInterface, QSGContextFactoryInterface_iid)
@@ -83,7 +91,6 @@ public:
virtual ~QSGContextPlugin();
virtual QStringList keys() const = 0;
- virtual QSGContext *create(const QString &key) const = 0;
virtual QQuickTextureFactory *createTextureFactoryFromImage(const QImage &) { return 0; }
virtual QSGRenderLoop *createWindowManager() { return 0; }
diff --git a/src/quick/scenegraph/qsgdefaultcontext.cpp b/src/quick/scenegraph/qsgdefaultcontext.cpp
new file mode 100644
index 0000000000..f9978e816c
--- /dev/null
+++ b/src/quick/scenegraph/qsgdefaultcontext.cpp
@@ -0,0 +1,269 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultcontext_p.h"
+
+#include <QtQuick/private/qsgdistancefieldutil_p.h>
+#include <QtQuick/private/qsgdefaultrectanglenode_p.h>
+#include <QtQuick/private/qsgdefaultimagenode_p.h>
+#include <QtQuick/private/qsgdefaultpainternode_p.h>
+#include <QtQuick/private/qsgdefaultglyphnode_p.h>
+#include <QtQuick/private/qsgdistancefieldglyphnode_p.h>
+#include <QtQuick/private/qsgdistancefieldglyphnode_p_p.h>
+#include <QtQuick/private/qsgrenderloop_p.h>
+#include <QtQuick/private/qsgdefaultlayer_p.h>
+#include <QtQuick/private/qsgdefaultrendercontext_p.h>
+
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFramebufferObject>
+
+#include <QtQuick/QQuickWindow>
+
+#include <private/qqmlglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QSGMultisampleAntialiasing {
+ class ImageNode : public QSGDefaultImageNode {
+ public:
+ void setAntialiasing(bool) { }
+ };
+
+
+ class RectangleNode : public QSGDefaultRectangleNode {
+ public:
+ void setAntialiasing(bool) { }
+ };
+}
+
+DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
+
+QSGDefaultContext::QSGDefaultContext(QObject *parent)
+ : QSGContext (parent)
+ , m_antialiasingMethod(QSGContext::UndecidedAntialiasing)
+ , m_distanceFieldDisabled(qmlDisableDistanceField())
+ , m_distanceFieldAntialiasing(QSGGlyphNode::HighQualitySubPixelAntialiasing)
+ , m_distanceFieldAntialiasingDecided(false)
+{
+ if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QSG_DISTANCEFIELD_ANTIALIASING"))) {
+ const QByteArray mode = qgetenv("QSG_DISTANCEFIELD_ANTIALIASING");
+ m_distanceFieldAntialiasingDecided = true;
+ if (mode == "subpixel")
+ m_distanceFieldAntialiasing = QSGGlyphNode::HighQualitySubPixelAntialiasing;
+ else if (mode == "subpixel-lowq")
+ m_distanceFieldAntialiasing = QSGGlyphNode::LowQualitySubPixelAntialiasing;
+ else if (mode == "gray")
+ m_distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing;
+ }
+
+ // Adds compatibility with Qt 5.3 and earlier's QSG_RENDER_TIMING
+ if (qEnvironmentVariableIsSet("QSG_RENDER_TIMING")) {
+ const_cast<QLoggingCategory &>(QSG_LOG_TIME_GLYPH()).setEnabled(QtDebugMsg, true);
+ const_cast<QLoggingCategory &>(QSG_LOG_TIME_TEXTURE()).setEnabled(QtDebugMsg, true);
+ const_cast<QLoggingCategory &>(QSG_LOG_TIME_RENDERER()).setEnabled(QtDebugMsg, true);
+ const_cast<QLoggingCategory &>(QSG_LOG_TIME_RENDERLOOP()).setEnabled(QtDebugMsg, true);
+ const_cast<QLoggingCategory &>(QSG_LOG_TIME_COMPILATION()).setEnabled(QtDebugMsg, true);
+ }
+}
+
+QSGDefaultContext::~QSGDefaultContext()
+{
+
+}
+
+void QSGDefaultContext::renderContextInitialized(QSGRenderContext *renderContext)
+{
+ m_mutex.lock();
+
+ auto openglRenderContext = static_cast<const QSGDefaultRenderContext *>(renderContext);
+ if (m_antialiasingMethod == UndecidedAntialiasing) {
+ if (Q_UNLIKELY(qEnvironmentVariableIsSet("QSG_ANTIALIASING_METHOD"))) {
+ const QByteArray aaType = qgetenv("QSG_ANTIALIASING_METHOD");
+ if (aaType == "msaa")
+ m_antialiasingMethod = MsaaAntialiasing;
+ else if (aaType == "vertex")
+ m_antialiasingMethod = VertexAntialiasing;
+ }
+ if (m_antialiasingMethod == UndecidedAntialiasing) {
+ if (openglRenderContext->openglContext()->format().samples() > 0)
+ m_antialiasingMethod = MsaaAntialiasing;
+ else
+ m_antialiasingMethod = VertexAntialiasing;
+ }
+ }
+
+ // With OpenGL ES, except for Angle on Windows, use GrayAntialiasing, unless
+ // some value had been requested explicitly. This could not be decided
+ // before without a context. Now the context is ready.
+ if (!m_distanceFieldAntialiasingDecided) {
+ m_distanceFieldAntialiasingDecided = true;
+#ifndef Q_OS_WIN32
+ if (openglRenderContext->openglContext()->isOpenGLES())
+ m_distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing;
+#endif
+ }
+
+ static bool dumped = false;
+ if (!dumped && QSG_LOG_INFO().isDebugEnabled()) {
+ dumped = true;
+ QSurfaceFormat format = openglRenderContext->openglContext()->format();
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ qCDebug(QSG_LOG_INFO) << "R/G/B/A Buffers: " << format.redBufferSize() << format.greenBufferSize() << format.blueBufferSize() << format.alphaBufferSize();
+ qCDebug(QSG_LOG_INFO) << "Depth Buffer: " << format.depthBufferSize();
+ qCDebug(QSG_LOG_INFO) << "Stencil Buffer: " << format.stencilBufferSize();
+ qCDebug(QSG_LOG_INFO) << "Samples: " << format.samples();
+ qCDebug(QSG_LOG_INFO) << "GL_VENDOR: " << (const char *) funcs->glGetString(GL_VENDOR);
+ qCDebug(QSG_LOG_INFO) << "GL_RENDERER: " << (const char *) funcs->glGetString(GL_RENDERER);
+ qCDebug(QSG_LOG_INFO) << "GL_VERSION: " << (const char *) funcs->glGetString(GL_VERSION);
+ QSet<QByteArray> exts = openglRenderContext->openglContext()->extensions();
+ QByteArray all; foreach (const QByteArray &e, exts) all += ' ' + e;
+ qCDebug(QSG_LOG_INFO) << "GL_EXTENSIONS: " << all.constData();
+ qCDebug(QSG_LOG_INFO) << "Max Texture Size: " << openglRenderContext->maxTextureSize();
+ qCDebug(QSG_LOG_INFO) << "Debug context: " << format.testOption(QSurfaceFormat::DebugContext);
+ }
+
+ m_mutex.unlock();
+}
+
+void QSGDefaultContext::renderContextInvalidated(QSGRenderContext *)
+{
+}
+
+QSGRenderContext *QSGDefaultContext::createRenderContext()
+{
+ return new QSGDefaultRenderContext(this);
+}
+
+QSGRectangleNode *QSGDefaultContext::createRectangleNode()
+{
+ return m_antialiasingMethod == MsaaAntialiasing
+ ? new QSGMultisampleAntialiasing::RectangleNode
+ : new QSGDefaultRectangleNode;
+}
+
+QSGImageNode *QSGDefaultContext::createImageNode()
+{
+ return m_antialiasingMethod == MsaaAntialiasing
+ ? new QSGMultisampleAntialiasing::ImageNode
+ : new QSGDefaultImageNode;
+}
+
+QSGPainterNode *QSGDefaultContext::createPainterNode(QQuickPaintedItem *item)
+{
+ return new QSGDefaultPainterNode(item);
+}
+
+QSGGlyphNode *QSGDefaultContext::createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode)
+{
+ if (m_distanceFieldDisabled || preferNativeGlyphNode) {
+ return new QSGDefaultGlyphNode;
+ } else {
+ QSGDistanceFieldGlyphNode *node = new QSGDistanceFieldGlyphNode(rc);
+ node->setPreferredAntialiasingMode(m_distanceFieldAntialiasing);
+ return node;
+ }
+}
+
+/*!
+ * Factory function for scene graph backends of the QStyle stylable elements. Returns a
+ * null pointer if the backend doesn't provide its own node type.
+ */
+QSGNinePatchNode *QSGDefaultContext::createNinePatchNode()
+{
+ return nullptr;
+}
+
+QSGLayer *QSGDefaultContext::createLayer(QSGRenderContext *renderContext)
+{
+ return new QSGDefaultLayer(renderContext);
+}
+
+QSurfaceFormat QSGDefaultContext::defaultSurfaceFormat() const
+{
+ QSurfaceFormat format = QSurfaceFormat::defaultFormat();
+ static bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER");
+ static bool useStencil = qEnvironmentVariableIsEmpty("QSG_NO_STENCIL_BUFFER");
+ static bool enableDebug = qEnvironmentVariableIsSet("QSG_OPENGL_DEBUG");
+ format.setDepthBufferSize(useDepth ? 24 : 0);
+ format.setStencilBufferSize(useStencil ? 8 : 0);
+ if (enableDebug)
+ format.setOption(QSurfaceFormat::DebugContext);
+ if (QQuickWindow::hasDefaultAlphaBuffer())
+ format.setAlphaBufferSize(8);
+ format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
+ return format;
+}
+
+void QSGDefaultContext::setDistanceFieldEnabled(bool enabled)
+{
+ m_distanceFieldDisabled = !enabled;
+}
+
+bool QSGDefaultContext::isDistanceFieldEnabled() const
+{
+ return !m_distanceFieldDisabled;
+}
+
+QSGRendererInterface *QSGDefaultContext::rendererInterface(QSGRenderContext *renderContext)
+{
+ Q_UNUSED(renderContext);
+ return this;
+}
+
+QSGRendererInterface::GraphicsApi QSGDefaultContext::graphicsApi() const
+{
+ return OpenGL;
+}
+
+QSGRendererInterface::ShaderType QSGDefaultContext::shaderType() const
+{
+ return GLSL;
+}
+
+QSGRendererInterface::ShaderCompilationTypes QSGDefaultContext::shaderCompilationType() const
+{
+ return RuntimeCompilation;
+}
+
+QSGRendererInterface::ShaderSourceTypes QSGDefaultContext::shaderSourceType() const
+{
+ return ShaderSourceString;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultcontext_p.h b/src/quick/scenegraph/qsgdefaultcontext_p.h
new file mode 100644
index 0000000000..6686ab98a0
--- /dev/null
+++ b/src/quick/scenegraph/qsgdefaultcontext_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGDEFAULTCONTEXT_H
+#define QSGDEFAULTCONTEXT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/private/qsgcontext_p.h>
+#include <QtQuick/private/qsgdistancefieldglyphnode_p.h>
+#include "qsgrendererinterface.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGDefaultContext : public QSGContext, public QSGRendererInterface
+{
+public:
+ QSGDefaultContext(QObject *parent = 0);
+ ~QSGDefaultContext();
+
+ void renderContextInitialized(QSGRenderContext *renderContext) override;
+ void renderContextInvalidated(QSGRenderContext *) override;
+ QSGRenderContext *createRenderContext() override;
+ QSGRectangleNode *createRectangleNode() override;
+ QSGImageNode *createImageNode() override;
+ QSGPainterNode *createPainterNode(QQuickPaintedItem *item) override;
+ QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) override;
+ QSGNinePatchNode *createNinePatchNode() override;
+ QSGLayer *createLayer(QSGRenderContext *renderContext) override;
+ QSurfaceFormat defaultSurfaceFormat() const override;
+ QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override;
+
+ void setDistanceFieldEnabled(bool enabled);
+ bool isDistanceFieldEnabled() const;
+
+ GraphicsApi graphicsApi() const override;
+ ShaderType shaderType() const override;
+ ShaderCompilationTypes shaderCompilationType() const override;
+ ShaderSourceTypes shaderSourceType() const override;
+
+private:
+ QMutex m_mutex;
+ QSGContext::AntialiasingMethod m_antialiasingMethod;
+ bool m_distanceFieldDisabled;
+ QSGDistanceFieldGlyphNode::AntialiasingMode m_distanceFieldAntialiasing;
+ bool m_distanceFieldAntialiasingDecided;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGDEFAULTCONTEXT_H
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
index b28ca7725a..afb9b673d9 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
@@ -507,7 +507,7 @@ bool QSGDefaultDistanceFieldGlyphCache::useTextureUploadWorkaround() const
bool QSGDefaultDistanceFieldGlyphCache::createFullSizeTextures() const
{
- return qsgPreferFullSizeGlyphCacheTextures() && glyphCount() > QT_DISTANCEFIELD_HIGHGLYPHCOUNT;
+ return qsgPreferFullSizeGlyphCacheTextures() && glyphCount() > QT_DISTANCEFIELD_HIGHGLYPHCOUNT();
}
int QSGDefaultDistanceFieldGlyphCache::maxTextureSize() const
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode.cpp b/src/quick/scenegraph/qsgdefaultglyphnode.cpp
index 082a4f8c09..b856d99bc1 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode.cpp
@@ -40,59 +40,11 @@
#include "qsgdefaultglyphnode_p.h"
#include "qsgdefaultglyphnode_p_p.h"
-#include <qopenglshaderprogram.h>
-#include <private/qfont_p.h>
-
QT_BEGIN_NAMESPACE
-QSGDefaultGlyphNode::QSGDefaultGlyphNode()
- : m_style(QQuickText::Normal)
- , m_material(0)
- , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
-{
- m_geometry.setDrawingMode(GL_TRIANGLES);
- setGeometry(&m_geometry);
-}
-
-QSGDefaultGlyphNode::~QSGDefaultGlyphNode()
-{
- delete m_material;
-}
-
-void QSGDefaultGlyphNode::setColor(const QColor &color)
-{
- m_color = color;
- if (m_material != 0) {
- m_material->setColor(color);
- markDirty(DirtyMaterial);
- }
-}
-
-void QSGDefaultGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
-{
- if (m_material != 0)
- delete m_material;
-
- m_position = position;
- m_glyphs = glyphs;
-
-#ifdef QSG_RUNTIME_DESCRIPTION
- qsgnode_set_description(this, QLatin1String("glyphs"));
-#endif
-}
-
-void QSGDefaultGlyphNode::setStyle(QQuickText::TextStyle style)
-{
- if (m_style == style)
- return;
- m_style = style;
-}
-
-void QSGDefaultGlyphNode::setStyleColor(const QColor &color)
+void QSGDefaultGlyphNode::setMaterialColor(const QColor &color)
{
- if (m_styleColor == color)
- return;
- m_styleColor = color;
+ static_cast<QSGTextMaskMaterial *>(m_material)->setColor(color);
}
void QSGDefaultGlyphNode::update()
@@ -120,11 +72,12 @@ void QSGDefaultGlyphNode::update()
m_material = material;
}
- m_material->setColor(m_color);
+ QSGTextMaskMaterial *textMaskMaterial = static_cast<QSGTextMaskMaterial *>(m_material);
+ textMaskMaterial->setColor(m_color);
QRectF boundingRect;
- m_material->populate(m_position, m_glyphs.glyphIndexes(), m_glyphs.positions(), geometry(),
- &boundingRect, &m_baseLine, margins);
+ textMaskMaterial->populate(m_position, m_glyphs.glyphIndexes(), m_glyphs.positions(), geometry(),
+ &boundingRect, &m_baseLine, margins);
setBoundingRect(boundingRect);
setMaterial(m_material);
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 3da7a10456..7c2663d5a3 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -49,6 +49,7 @@
#include <QtQuick/qquickwindow.h>
#include <QtQuick/private/qsgtexture_p.h>
+#include <QtQuick/private/qsgdefaultrendercontext_p.h>
#include <private/qrawfont_p.h>
#include <QtCore/qmath.h>
@@ -427,7 +428,7 @@ void QSGTextMaskMaterial::init(QFontEngine::GlyphFormat glyphFormat)
if (!m_glyphCache || int(m_glyphCache->glyphFormat()) != glyphFormat) {
m_glyphCache = new QOpenGLTextureGlyphCache(glyphFormat, glyphCacheTransform);
fontEngine->setGlyphCache(ctx, m_glyphCache.data());
- QSGRenderContext *sg = QSGRenderContext::from(ctx);
+ auto sg = QSGDefaultRenderContext::from(ctx);
Q_ASSERT(sg);
sg->registerFontengineForCleanup(fontEngine);
}
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.h b/src/quick/scenegraph/qsgdefaultglyphnode_p.h
index ea4c0ff787..0eb7a4e4bd 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.h
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.h
@@ -52,38 +52,15 @@
//
#include <private/qsgadaptationlayer_p.h>
-#include <QtQuick/qsgnode.h>
+#include <private/qsgbasicglyphnode_p.h>
QT_BEGIN_NAMESPACE
-class QSGTextMaskMaterial;
-class QSGDefaultGlyphNode: public QSGGlyphNode
+class QSGDefaultGlyphNode : public QSGBasicGlyphNode
{
public:
- QSGDefaultGlyphNode();
- virtual ~QSGDefaultGlyphNode();
-
- virtual QPointF baseLine() const { return m_baseLine; }
- virtual void setGlyphs(const QPointF &position, const QGlyphRun &glyphs);
- virtual void setColor(const QColor &color);
-
- virtual void setPreferredAntialiasingMode(AntialiasingMode) { }
- virtual void setStyle(QQuickText::TextStyle);
- virtual void setStyleColor(const QColor &);
-
- virtual void update();
-
-protected:
- QGlyphRun m_glyphs;
- QPointF m_position;
- QColor m_color;
- QQuickText::TextStyle m_style;
- QColor m_styleColor;
-
- QPointF m_baseLine;
- QSGTextMaskMaterial *m_material;
-
- QSGGeometry m_geometry;
+ void setMaterialColor(const QColor &color) override;
+ void update() override;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultimagenode.cpp b/src/quick/scenegraph/qsgdefaultimagenode.cpp
index bb4db150c0..9fed70a7de 100644
--- a/src/quick/scenegraph/qsgdefaultimagenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultimagenode.cpp
@@ -39,38 +39,12 @@
#include "qsgdefaultimagenode_p.h"
#include <private/qsgmaterialshader_p.h>
-
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qmath.h>
-#include <QtGui/qopenglfunctions.h>
-
-#include <qsgtexturematerial.h>
#include <private/qsgtexturematerial_p.h>
-#include <qsgmaterial.h>
+#include <QtGui/qopenglfunctions.h>
+#include <QtCore/qmath.h>
QT_BEGIN_NAMESPACE
-namespace
-{
- struct SmoothVertex
- {
- float x, y, u, v;
- float dx, dy, du, dv;
- };
-
- const QSGGeometry::AttributeSet &smoothAttributeSet()
- {
- static QSGGeometry::Attribute data[] = {
- QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),
- QSGGeometry::Attribute::create(1, 2, GL_FLOAT, false),
- QSGGeometry::Attribute::create(2, 2, GL_FLOAT, false),
- QSGGeometry::Attribute::create(3, 2, GL_FLOAT, false)
- };
- static QSGGeometry::AttributeSet attrs = { 4, sizeof(SmoothVertex), data };
- return attrs;
- }
-}
-
class SmoothTextureMaterialShader : public QSGTextureMaterialShader
{
public:
@@ -144,52 +118,9 @@ void SmoothTextureMaterialShader::initialize()
}
QSGDefaultImageNode::QSGDefaultImageNode()
- : m_innerSourceRect(0, 0, 1, 1)
- , m_subSourceRect(0, 0, 1, 1)
- , m_antialiasing(false)
- , m_mirror(false)
- , m_dirtyGeometry(false)
- , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
{
setMaterial(&m_materialO);
setOpaqueMaterial(&m_material);
- setGeometry(&m_geometry);
-
-#ifdef QSG_RUNTIME_DESCRIPTION
- qsgnode_set_description(this, QLatin1String("image"));
-#endif
-}
-
-void QSGDefaultImageNode::setTargetRect(const QRectF &rect)
-{
- if (rect == m_targetRect)
- return;
- m_targetRect = rect;
- m_dirtyGeometry = true;
-}
-
-void QSGDefaultImageNode::setInnerTargetRect(const QRectF &rect)
-{
- if (rect == m_innerTargetRect)
- return;
- m_innerTargetRect = rect;
- m_dirtyGeometry = true;
-}
-
-void QSGDefaultImageNode::setInnerSourceRect(const QRectF &rect)
-{
- if (rect == m_innerSourceRect)
- return;
- m_innerSourceRect = rect;
- m_dirtyGeometry = true;
-}
-
-void QSGDefaultImageNode::setSubSourceRect(const QRectF &rect)
-{
- if (rect == m_subSourceRect)
- return;
- m_subSourceRect = rect;
- m_dirtyGeometry = true;
}
void QSGDefaultImageNode::setFiltering(QSGTexture::Filtering filtering)
@@ -203,7 +134,6 @@ void QSGDefaultImageNode::setFiltering(QSGTexture::Filtering filtering)
markDirty(DirtyMaterial);
}
-
void QSGDefaultImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
{
if (m_material.mipmapFiltering() == filtering)
@@ -237,73 +167,37 @@ void QSGDefaultImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
markDirty(DirtyMaterial);
}
-
-void QSGDefaultImageNode::setTexture(QSGTexture *texture)
-{
- Q_ASSERT(texture);
-
- m_material.setTexture(texture);
- m_materialO.setTexture(texture);
- m_smoothMaterial.setTexture(texture);
- m_material.setFlag(QSGMaterial::Blending, texture->hasAlphaChannel());
-
- markDirty(DirtyMaterial);
-
- // Because the texture can be a different part of the atlas, we need to update it...
- m_dirtyGeometry = true;
-}
-
-void QSGDefaultImageNode::setAntialiasing(bool antialiasing)
+void QSGDefaultImageNode::updateMaterialAntialiasing()
{
- if (antialiasing == m_antialiasing)
- return;
- m_antialiasing = antialiasing;
if (m_antialiasing) {
setMaterial(&m_smoothMaterial);
setOpaqueMaterial(0);
- setGeometry(new QSGGeometry(smoothAttributeSet(), 0));
- setFlag(OwnsGeometry, true);
} else {
setMaterial(&m_materialO);
setOpaqueMaterial(&m_material);
- setGeometry(&m_geometry);
- setFlag(OwnsGeometry, false);
}
- m_dirtyGeometry = true;
}
-void QSGDefaultImageNode::setMirror(bool mirror)
+void QSGDefaultImageNode::setMaterialTexture(QSGTexture *texture)
{
- if (mirror == m_mirror)
- return;
- m_mirror = mirror;
- m_dirtyGeometry = true;
+ m_material.setTexture(texture);
+ m_materialO.setTexture(texture);
+ m_smoothMaterial.setTexture(texture);
}
-
-void QSGDefaultImageNode::update()
+QSGTexture *QSGDefaultImageNode::materialTexture() const
{
- if (m_dirtyGeometry)
- updateGeometry();
+ return m_material.texture();
}
-void QSGDefaultImageNode::preprocess()
+bool QSGDefaultImageNode::updateMaterialBlending()
{
- bool doDirty = false;
- QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(m_material.texture());
- if (t) {
- doDirty = t->updateTexture();
- if (doDirty)
- updateGeometry();
- }
- bool alpha = m_material.flags() & QSGMaterial::Blending;
- if (m_material.texture() && alpha != m_material.texture()->hasAlphaChannel()) {
+ const bool alpha = m_material.flags() & QSGMaterial::Blending;
+ if (materialTexture() && alpha != materialTexture()->hasAlphaChannel()) {
m_material.setFlag(QSGMaterial::Blending, !alpha);
- doDirty = true;
+ return true;
}
-
- if (doDirty)
- markDirty(DirtyMaterial);
+ return false;
}
inline static bool isPowerOfTwo(int x)
@@ -312,360 +206,21 @@ inline static bool isPowerOfTwo(int x)
return x == (x & -x);
}
-namespace {
- struct X { float x, tx; };
- struct Y { float y, ty; };
-}
-
-static inline void appendQuad(quint16 **indices, quint16 topLeft, quint16 topRight,
- quint16 bottomLeft, quint16 bottomRight)
-{
- *(*indices)++ = topLeft;
- *(*indices)++ = bottomLeft;
- *(*indices)++ = bottomRight;
- *(*indices)++ = bottomRight;
- *(*indices)++ = topRight;
- *(*indices)++ = topLeft;
-}
-
-void QSGDefaultImageNode::updateGeometry()
+bool QSGDefaultImageNode::supportsWrap(const QSize &size) const
{
- Q_ASSERT(!m_targetRect.isEmpty());
- const QSGTexture *t = m_material.texture();
- if (!t) {
- QSGGeometry *g = geometry();
- g->allocate(4);
- g->setDrawingMode(GL_TRIANGLE_STRIP);
- memset(g->vertexData(), 0, g->sizeOfVertex() * 4);
- } else {
- QRectF sourceRect = t->normalizedTextureSubRect();
-
- QRectF innerSourceRect(sourceRect.x() + m_innerSourceRect.x() * sourceRect.width(),
- sourceRect.y() + m_innerSourceRect.y() * sourceRect.height(),
- m_innerSourceRect.width() * sourceRect.width(),
- m_innerSourceRect.height() * sourceRect.height());
-
- bool hasMargins = m_targetRect != m_innerTargetRect;
-
- int floorLeft = qFloor(m_subSourceRect.left());
- int ceilRight = qCeil(m_subSourceRect.right());
- int floorTop = qFloor(m_subSourceRect.top());
- int ceilBottom = qCeil(m_subSourceRect.bottom());
- int hTiles = ceilRight - floorLeft;
- int vTiles = ceilBottom - floorTop;
+ bool wrapSupported = true;
- bool hasTiles = hTiles != 1 || vTiles != 1;
- bool fullTexture = innerSourceRect == QRectF(0, 0, 1, 1);
-
- bool wrapSupported = true;
-
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
#ifndef QT_OPENGL_ES_2
- if (ctx->isOpenGLES())
+ if (ctx->isOpenGLES())
#endif
- {
- bool npotSupported = ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat);
- QSize size = t->textureSize();
- const bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
- wrapSupported = npotSupported || !isNpot;
- }
-
- // An image can be rendered as a single quad if:
- // - There are no margins, and either:
- // - the image isn't repeated
- // - the source rectangle fills the entire texture so that texture wrapping can be used,
- // and NPOT is supported
- if (!hasMargins && (!hasTiles || (fullTexture && wrapSupported))) {
- QRectF sr;
- if (!fullTexture) {
- sr = QRectF(innerSourceRect.x() + (m_subSourceRect.left() - floorLeft) * innerSourceRect.width(),
- innerSourceRect.y() + (m_subSourceRect.top() - floorTop) * innerSourceRect.height(),
- m_subSourceRect.width() * innerSourceRect.width(),
- m_subSourceRect.height() * innerSourceRect.height());
- } else {
- sr = QRectF(m_subSourceRect.left() - floorLeft, m_subSourceRect.top() - floorTop,
- m_subSourceRect.width(), m_subSourceRect.height());
- }
- if (m_mirror) {
- qreal oldLeft = sr.left();
- sr.setLeft(sr.right());
- sr.setRight(oldLeft);
- }
-
- if (m_antialiasing) {
- QSGGeometry *g = geometry();
- Q_ASSERT(g != &m_geometry);
- g->allocate(8, 14);
- g->setDrawingMode(GL_TRIANGLE_STRIP);
- SmoothVertex *vertices = reinterpret_cast<SmoothVertex *>(g->vertexData());
- float delta = float(qAbs(m_targetRect.width()) < qAbs(m_targetRect.height())
- ? m_targetRect.width() : m_targetRect.height()) * 0.5f;
- float sx = float(sr.width() / m_targetRect.width());
- float sy = float(sr.height() / m_targetRect.height());
- for (int d = -1; d <= 1; d += 2) {
- for (int j = 0; j < 2; ++j) {
- for (int i = 0; i < 2; ++i, ++vertices) {
- vertices->x = m_targetRect.x() + i * m_targetRect.width();
- vertices->y = m_targetRect.y() + j * m_targetRect.height();
- vertices->u = sr.x() + i * sr.width();
- vertices->v = sr.y() + j * sr.height();
- vertices->dx = (i == 0 ? delta : -delta) * d;
- vertices->dy = (j == 0 ? delta : -delta) * d;
- vertices->du = (d < 0 ? 0 : vertices->dx * sx);
- vertices->dv = (d < 0 ? 0 : vertices->dy * sy);
- }
- }
- }
- Q_ASSERT(vertices - g->vertexCount() == g->vertexData());
- static const quint16 indices[] = {
- 0, 4, 1, 5, 3, 7, 2, 6, 0, 4,
- 4, 6, 5, 7
- };
- Q_ASSERT(g->sizeOfIndex() * g->indexCount() == sizeof(indices));
- memcpy(g->indexDataAsUShort(), indices, sizeof(indices));
- } else {
- m_geometry.allocate(4);
- m_geometry.setDrawingMode(GL_TRIANGLE_STRIP);
- QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_targetRect, sr);
- }
- } else {
- int hCells = hTiles;
- int vCells = vTiles;
- if (m_innerTargetRect.width() == 0)
- hCells = 0;
- if (m_innerTargetRect.left() != m_targetRect.left())
- ++hCells;
- if (m_innerTargetRect.right() != m_targetRect.right())
- ++hCells;
- if (m_innerTargetRect.height() == 0)
- vCells = 0;
- if (m_innerTargetRect.top() != m_targetRect.top())
- ++vCells;
- if (m_innerTargetRect.bottom() != m_targetRect.bottom())
- ++vCells;
- QVarLengthArray<X, 32> xData(2 * hCells);
- QVarLengthArray<Y, 32> yData(2 * vCells);
- X *xs = xData.data();
- Y *ys = yData.data();
-
- if (m_innerTargetRect.left() != m_targetRect.left()) {
- xs[0].x = m_targetRect.left();
- xs[0].tx = sourceRect.left();
- xs[1].x = m_innerTargetRect.left();
- xs[1].tx = innerSourceRect.left();
- xs += 2;
- }
- if (m_innerTargetRect.width() != 0) {
- xs[0].x = m_innerTargetRect.left();
- xs[0].tx = innerSourceRect.x() + (m_subSourceRect.left() - floorLeft) * innerSourceRect.width();
- ++xs;
- float b = m_innerTargetRect.width() / m_subSourceRect.width();
- float a = m_innerTargetRect.x() - m_subSourceRect.x() * b;
- for (int i = floorLeft + 1; i <= ceilRight - 1; ++i) {
- xs[0].x = xs[1].x = a + b * i;
- xs[0].tx = innerSourceRect.right();
- xs[1].tx = innerSourceRect.left();
- xs += 2;
- }
- xs[0].x = m_innerTargetRect.right();
- xs[0].tx = innerSourceRect.x() + (m_subSourceRect.right() - ceilRight + 1) * innerSourceRect.width();
- ++xs;
- }
- if (m_innerTargetRect.right() != m_targetRect.right()) {
- xs[0].x = m_innerTargetRect.right();
- xs[0].tx = innerSourceRect.right();
- xs[1].x = m_targetRect.right();
- xs[1].tx = sourceRect.right();
- xs += 2;
- }
- Q_ASSERT(xs == xData.data() + xData.size());
- if (m_mirror) {
- float leftPlusRight = m_targetRect.left() + m_targetRect.right();
- int count = xData.size();
- xs = xData.data();
- for (int i = 0; i < count >> 1; ++i)
- qSwap(xs[i], xs[count - 1 - i]);
- for (int i = 0; i < count; ++i)
- xs[i].x = leftPlusRight - xs[i].x;
- }
-
- if (m_innerTargetRect.top() != m_targetRect.top()) {
- ys[0].y = m_targetRect.top();
- ys[0].ty = sourceRect.top();
- ys[1].y = m_innerTargetRect.top();
- ys[1].ty = innerSourceRect.top();
- ys += 2;
- }
- if (m_innerTargetRect.height() != 0) {
- ys[0].y = m_innerTargetRect.top();
- ys[0].ty = innerSourceRect.y() + (m_subSourceRect.top() - floorTop) * innerSourceRect.height();
- ++ys;
- float b = m_innerTargetRect.height() / m_subSourceRect.height();
- float a = m_innerTargetRect.y() - m_subSourceRect.y() * b;
- for (int i = floorTop + 1; i <= ceilBottom - 1; ++i) {
- ys[0].y = ys[1].y = a + b * i;
- ys[0].ty = innerSourceRect.bottom();
- ys[1].ty = innerSourceRect.top();
- ys += 2;
- }
- ys[0].y = m_innerTargetRect.bottom();
- ys[0].ty = innerSourceRect.y() + (m_subSourceRect.bottom() - ceilBottom + 1) * innerSourceRect.height();
- ++ys;
- }
- if (m_innerTargetRect.bottom() != m_targetRect.bottom()) {
- ys[0].y = m_innerTargetRect.bottom();
- ys[0].ty = innerSourceRect.bottom();
- ys[1].y = m_targetRect.bottom();
- ys[1].ty = sourceRect.bottom();
- ys += 2;
- }
- Q_ASSERT(ys == yData.data() + yData.size());
-
- if (m_antialiasing) {
- QSGGeometry *g = geometry();
- Q_ASSERT(g != &m_geometry);
-
- g->allocate(hCells * vCells * 4 + (hCells + vCells - 1) * 4,
- hCells * vCells * 6 + (hCells + vCells) * 12);
- g->setDrawingMode(GL_TRIANGLES);
- SmoothVertex *vertices = reinterpret_cast<SmoothVertex *>(g->vertexData());
- memset(vertices, 0, g->vertexCount() * g->sizeOfVertex());
- quint16 *indices = g->indexDataAsUShort();
-
- // The deltas are how much the fuzziness can reach into the image.
- // Only the border vertices are moved by the vertex shader, so the fuzziness
- // can't reach further into the image than the closest interior vertices.
- float leftDx = xData.at(1).x - xData.at(0).x;
- float rightDx = xData.at(xData.size() - 1).x - xData.at(xData.size() - 2).x;
- float topDy = yData.at(1).y - yData.at(0).y;
- float bottomDy = yData.at(yData.size() - 1).y - yData.at(yData.size() - 2).y;
-
- float leftDu = xData.at(1).tx - xData.at(0).tx;
- float rightDu = xData.at(xData.size() - 1).tx - xData.at(xData.size() - 2).tx;
- float topDv = yData.at(1).ty - yData.at(0).ty;
- float bottomDv = yData.at(yData.size() - 1).ty - yData.at(yData.size() - 2).ty;
-
- if (hCells == 1) {
- leftDx = rightDx *= 0.5f;
- leftDu = rightDu *= 0.5f;
- }
- if (vCells == 1) {
- topDy = bottomDy *= 0.5f;
- topDv = bottomDv *= 0.5f;
- }
-
- // This delta is how much the fuzziness can reach out from the image.
- float delta = float(qAbs(m_targetRect.width()) < qAbs(m_targetRect.height())
- ? m_targetRect.width() : m_targetRect.height()) * 0.5f;
-
- quint16 index = 0;
- ys = yData.data();
- for (int j = 0; j < vCells; ++j, ys += 2) {
- xs = xData.data();
- bool isTop = j == 0;
- bool isBottom = j == vCells - 1;
- for (int i = 0; i < hCells; ++i, xs += 2) {
- bool isLeft = i == 0;
- bool isRight = i == hCells - 1;
-
- SmoothVertex *v = vertices + index;
-
- quint16 topLeft = index;
- for (int k = (isTop || isLeft ? 2 : 1); k--; ++v, ++index) {
- v->x = xs[0].x;
- v->u = xs[0].tx;
- v->y = ys[0].y;
- v->v = ys[0].ty;
- }
-
- quint16 topRight = index;
- for (int k = (isTop || isRight ? 2 : 1); k--; ++v, ++index) {
- v->x = xs[1].x;
- v->u = xs[1].tx;
- v->y = ys[0].y;
- v->v = ys[0].ty;
- }
-
- quint16 bottomLeft = index;
- for (int k = (isBottom || isLeft ? 2 : 1); k--; ++v, ++index) {
- v->x = xs[0].x;
- v->u = xs[0].tx;
- v->y = ys[1].y;
- v->v = ys[1].ty;
- }
-
- quint16 bottomRight = index;
- for (int k = (isBottom || isRight ? 2 : 1); k--; ++v, ++index) {
- v->x = xs[1].x;
- v->u = xs[1].tx;
- v->y = ys[1].y;
- v->v = ys[1].ty;
- }
-
- appendQuad(&indices, topLeft, topRight, bottomLeft, bottomRight);
-
- if (isTop) {
- vertices[topLeft].dy = vertices[topRight].dy = topDy;
- vertices[topLeft].dv = vertices[topRight].dv = topDv;
- vertices[topLeft + 1].dy = vertices[topRight + 1].dy = -delta;
- appendQuad(&indices, topLeft + 1, topRight + 1, topLeft, topRight);
- }
-
- if (isBottom) {
- vertices[bottomLeft].dy = vertices[bottomRight].dy = -bottomDy;
- vertices[bottomLeft].dv = vertices[bottomRight].dv = -bottomDv;
- vertices[bottomLeft + 1].dy = vertices[bottomRight + 1].dy = delta;
- appendQuad(&indices, bottomLeft, bottomRight, bottomLeft + 1, bottomRight + 1);
- }
-
- if (isLeft) {
- vertices[topLeft].dx = vertices[bottomLeft].dx = leftDx;
- vertices[topLeft].du = vertices[bottomLeft].du = leftDu;
- vertices[topLeft + 1].dx = vertices[bottomLeft + 1].dx = -delta;
- appendQuad(&indices, topLeft + 1, topLeft, bottomLeft + 1, bottomLeft);
- }
-
- if (isRight) {
- vertices[topRight].dx = vertices[bottomRight].dx = -rightDx;
- vertices[topRight].du = vertices[bottomRight].du = -rightDu;
- vertices[topRight + 1].dx = vertices[bottomRight + 1].dx = delta;
- appendQuad(&indices, topRight, topRight + 1, bottomRight, bottomRight + 1);
- }
- }
- }
-
- Q_ASSERT(index == g->vertexCount());
- Q_ASSERT(indices - g->indexCount() == g->indexData());
- } else {
- m_geometry.allocate(hCells * vCells * 4, hCells * vCells * 6);
- m_geometry.setDrawingMode(GL_TRIANGLES);
- QSGGeometry::TexturedPoint2D *vertices = m_geometry.vertexDataAsTexturedPoint2D();
- ys = yData.data();
- for (int j = 0; j < vCells; ++j, ys += 2) {
- xs = xData.data();
- for (int i = 0; i < hCells; ++i, xs += 2) {
- vertices[0].x = vertices[2].x = xs[0].x;
- vertices[0].tx = vertices[2].tx = xs[0].tx;
- vertices[1].x = vertices[3].x = xs[1].x;
- vertices[1].tx = vertices[3].tx = xs[1].tx;
-
- vertices[0].y = vertices[1].y = ys[0].y;
- vertices[0].ty = vertices[1].ty = ys[0].ty;
- vertices[2].y = vertices[3].y = ys[1].y;
- vertices[2].ty = vertices[3].ty = ys[1].ty;
-
- vertices += 4;
- }
- }
-
- quint16 *indices = m_geometry.indexDataAsUShort();
- for (int i = 0; i < 4 * vCells * hCells; i += 4)
- appendQuad(&indices, i, i + 1, i + 2, i + 3);
- }
- }
+ {
+ bool npotSupported = ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat);
+ const bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
+ wrapSupported = npotSupported || !isNpot;
}
- markDirty(DirtyGeometry);
- m_dirtyGeometry = false;
+
+ return wrapSupported;
}
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultimagenode_p.h b/src/quick/scenegraph/qsgdefaultimagenode_p.h
index 2d8abc1d35..688c5a5039 100644
--- a/src/quick/scenegraph/qsgdefaultimagenode_p.h
+++ b/src/quick/scenegraph/qsgdefaultimagenode_p.h
@@ -53,6 +53,7 @@
//
#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgbasicimagenode_p.h>
#include <QtQuick/qsgtexturematerial.h>
QT_BEGIN_NAMESPACE
@@ -65,47 +66,30 @@ public:
void setTexture(QSGTexture *texture);
protected:
- virtual QSGMaterialType *type() const;
- virtual QSGMaterialShader *createShader() const;
+ QSGMaterialType *type() const override;
+ QSGMaterialShader *createShader() const override;
};
-class Q_QUICK_PRIVATE_EXPORT QSGDefaultImageNode : public QSGImageNode
+class Q_QUICK_PRIVATE_EXPORT QSGDefaultImageNode : public QSGBasicImageNode
{
public:
QSGDefaultImageNode();
- virtual void setTargetRect(const QRectF &rect);
- virtual void setInnerTargetRect(const QRectF &rect);
- virtual void setInnerSourceRect(const QRectF &rect);
- virtual void setSubSourceRect(const QRectF &rect);
- virtual void setTexture(QSGTexture *t);
- virtual void setAntialiasing(bool antialiasing);
- virtual void setMirror(bool mirror);
- virtual void update();
- virtual void setMipmapFiltering(QSGTexture::Filtering filtering);
- virtual void setFiltering(QSGTexture::Filtering filtering);
- virtual void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode);
- virtual void setVerticalWrapMode(QSGTexture::WrapMode wrapMode);
+ void setMipmapFiltering(QSGTexture::Filtering filtering) override;
+ void setFiltering(QSGTexture::Filtering filtering) override;
+ void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) override;
+ void setVerticalWrapMode(QSGTexture::WrapMode wrapMode) override;
- virtual void preprocess();
+ void updateMaterialAntialiasing() override;
+ void setMaterialTexture(QSGTexture *texture) override;
+ QSGTexture *materialTexture() const override;
+ bool updateMaterialBlending() override;
+ bool supportsWrap(const QSize &size) const override;
private:
- void updateGeometry();
-
- QRectF m_targetRect;
- QRectF m_innerTargetRect;
- QRectF m_innerSourceRect;
- QRectF m_subSourceRect;
-
QSGOpaqueTextureMaterial m_material;
QSGTextureMaterial m_materialO;
QSGSmoothTextureMaterial m_smoothMaterial;
-
- uint m_antialiasing : 1;
- uint m_mirror : 1;
- uint m_dirtyGeometry : 1;
-
- QSGGeometry m_geometry;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp
index 2f1c1d454c..ad5b57ff83 100644
--- a/src/quick/scenegraph/qsgdefaultlayer.cpp
+++ b/src/quick/scenegraph/qsgdefaultlayer.cpp
@@ -40,8 +40,12 @@
#include <private/qqmlglobal_p.h>
#include <private/qsgrenderer_p.h>
+#include <private/qsgdefaultrendercontext_p.h>
-#include <QOpenGLFramebufferObject>
+#include <QtGui/QOpenGLFramebufferObject>
+#include <QtGui/QOpenGLFunctions>
+
+#include <QtQuick/private/qsgdepthstencilbuffer_p.h>
#ifdef QSG_DEBUG_FBO_OVERLAY
DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY)
@@ -95,7 +99,6 @@ QSGDefaultLayer::QSGDefaultLayer(QSGRenderContext *context)
#ifdef QSG_DEBUG_FBO_OVERLAY
, m_debugOverlay(0)
#endif
- , m_context(context)
, m_mipmap(false)
, m_live(true)
, m_recursive(false)
@@ -106,6 +109,7 @@ QSGDefaultLayer::QSGDefaultLayer(QSGRenderContext *context)
, m_mirrorHorizontal(false)
, m_mirrorVertical(true)
{
+ m_context = static_cast<QSGDefaultRenderContext *>(context);
}
QSGDefaultLayer::~QSGDefaultLayer()
diff --git a/src/quick/scenegraph/qsgdefaultlayer_p.h b/src/quick/scenegraph/qsgdefaultlayer_p.h
index 8bb565f845..ae39994096 100644
--- a/src/quick/scenegraph/qsgdefaultlayer_p.h
+++ b/src/quick/scenegraph/qsgdefaultlayer_p.h
@@ -54,8 +54,14 @@
#include <private/qsgcontext_p.h>
#include <qsgsimplerectnode.h>
+QT_BEGIN_NAMESPACE
+
#define QSG_DEBUG_FBO_OVERLAY
+class QOpenGLFramebufferObject;
+class QSGDepthStencilBuffer;
+class QSGDefaultRenderContext;
+
class Q_QUICK_PRIVATE_EXPORT QSGDefaultLayer : public QSGLayer
{
Q_OBJECT
@@ -131,7 +137,7 @@ private:
QSGSimpleRectNode *m_debugOverlay;
#endif
- QSGRenderContext *m_context;
+ QSGDefaultRenderContext *m_context;
uint m_mipmap : 1;
uint m_live : 1;
@@ -144,4 +150,6 @@ private:
uint m_mirrorVertical : 1;
};
+QT_END_NAMESPACE
+
#endif // QSGDEFAULTLAYER_P_H
diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
index 5ef52e8722..117a9272e5 100644
--- a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
@@ -38,8 +38,6 @@
**
****************************************************************************/
-
-
#include "qsgdefaultrectanglenode_p.h"
#include <QtQuick/qsgvertexcolormaterial.h>
@@ -52,59 +50,6 @@
QT_BEGIN_NAMESPACE
-namespace
-{
- struct Color4ub
- {
- unsigned char r, g, b, a;
- };
-
- Color4ub operator *(Color4ub c, float t) { c.a *= t; c.r *= t; c.g *= t; c.b *= t; return c; }
- Color4ub operator +(Color4ub a, Color4ub b) { a.a += b.a; a.r += b.r; a.g += b.g; a.b += b.b; return a; }
-
- inline Color4ub colorToColor4ub(const QColor &c)
- {
- Color4ub color = { uchar(qRound(c.redF() * c.alphaF() * 255)),
- uchar(qRound(c.greenF() * c.alphaF() * 255)),
- uchar(qRound(c.blueF() * c.alphaF() * 255)),
- uchar(qRound(c.alphaF() * 255))
- };
- return color;
- }
-
- // Same layout as QSGGeometry::ColoredPoint2D, but uses Color4ub for convenience.
- struct Vertex
- {
- float x, y;
- Color4ub color;
- void set(float nx, float ny, Color4ub ncolor)
- {
- x = nx; y = ny; color = ncolor;
- }
- };
-
- struct SmoothVertex : public Vertex
- {
- float dx, dy;
- void set(float nx, float ny, Color4ub ncolor, float ndx, float ndy)
- {
- Vertex::set(nx, ny, ncolor);
- dx = ndx; dy = ndy;
- }
- };
-
- const QSGGeometry::AttributeSet &smoothAttributeSet()
- {
- static QSGGeometry::Attribute data[] = {
- QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),
- QSGGeometry::Attribute::create(1, 4, GL_UNSIGNED_BYTE, false),
- QSGGeometry::Attribute::create(2, 2, GL_FLOAT, false)
- };
- static QSGGeometry::AttributeSet attrs = { 3, sizeof(SmoothVertex), data };
- return attrs;
- }
-}
-
class SmoothColorMaterialShader : public QSGMaterialShader
{
public:
@@ -183,604 +128,32 @@ QSGMaterialShader *QSGSmoothColorMaterial::createShader() const
return new SmoothColorMaterialShader;
}
-
QSGDefaultRectangleNode::QSGDefaultRectangleNode()
- : m_radius(0)
- , m_pen_width(0)
- , m_aligned(true)
- , m_antialiasing(false)
- , m_gradient_is_opaque(true)
- , m_dirty_geometry(false)
- , m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0)
{
- setGeometry(&m_geometry);
setMaterial(&m_material);
-
-#ifdef QSG_RUNTIME_DESCRIPTION
- qsgnode_set_description(this, QLatin1String("rectangle"));
-#endif
-}
-
-void QSGDefaultRectangleNode::setRect(const QRectF &rect)
-{
- if (rect == m_rect)
- return;
- m_rect = rect;
- m_dirty_geometry = true;
-}
-
-void QSGDefaultRectangleNode::setColor(const QColor &color)
-{
- if (color == m_color)
- return;
- m_color = color;
- if (m_gradient_stops.isEmpty())
- m_dirty_geometry = true;
-}
-
-void QSGDefaultRectangleNode::setPenColor(const QColor &color)
-{
- if (color == m_border_color)
- return;
- m_border_color = color;
- if (m_pen_width > 0)
- m_dirty_geometry = true;
-}
-
-void QSGDefaultRectangleNode::setPenWidth(qreal width)
-{
- if (width == m_pen_width)
- return;
- m_pen_width = width;
- m_dirty_geometry = true;
-}
-
-
-void QSGDefaultRectangleNode::setGradientStops(const QGradientStops &stops)
-{
- if (stops.constData() == m_gradient_stops.constData())
- return;
-
- m_gradient_stops = stops;
-
- m_gradient_is_opaque = true;
- for (int i = 0; i < stops.size(); ++i)
- m_gradient_is_opaque &= stops.at(i).second.alpha() == 0xff;
- m_dirty_geometry = true;
}
-void QSGDefaultRectangleNode::setRadius(qreal radius)
+void QSGDefaultRectangleNode::updateMaterialAntialiasing()
{
- if (radius == m_radius)
- return;
- m_radius = radius;
- m_dirty_geometry = true;
-}
-
-void QSGDefaultRectangleNode::setAntialiasing(bool antialiasing)
-{
- if (antialiasing == m_antialiasing)
- return;
- m_antialiasing = antialiasing;
- if (m_antialiasing) {
+ if (m_antialiasing)
setMaterial(&m_smoothMaterial);
- setGeometry(new QSGGeometry(smoothAttributeSet(), 0));
- setFlag(OwnsGeometry, true);
- } else {
+ else
setMaterial(&m_material);
- setGeometry(&m_geometry);
- setFlag(OwnsGeometry, false);
- }
- m_dirty_geometry = true;
-}
-
-void QSGDefaultRectangleNode::setAligned(bool aligned)
-{
- if (aligned == m_aligned)
- return;
- m_aligned = aligned;
- m_dirty_geometry = true;
-}
-
-void QSGDefaultRectangleNode::update()
-{
- if (m_dirty_geometry) {
- updateGeometry();
- m_dirty_geometry = false;
-
- QSGNode::DirtyState state = QSGNode::DirtyGeometry;
- // smoothed material is always blended, so no change in material state
- if (material() == &m_material) {
- bool wasBlending = (m_material.flags() & QSGMaterial::Blending);
- bool isBlending = (m_gradient_stops.size() > 0 && !m_gradient_is_opaque)
- || (m_color.alpha() < 255 && m_color.alpha() != 0)
- || (m_pen_width > 0 && m_border_color.alpha() < 255);
- if (wasBlending != isBlending) {
- m_material.setFlag(QSGMaterial::Blending, isBlending);
- state |= QSGNode::DirtyMaterial;
- }
- }
-
- markDirty(state);
- }
}
-void QSGDefaultRectangleNode::updateGeometry()
+void QSGDefaultRectangleNode::updateMaterialBlending(QSGNode::DirtyState *state)
{
- float width = float(m_rect.width());
- float height = float(m_rect.height());
- float penWidth = qMin(qMin(width, height) * 0.5f, float(m_pen_width));
-
- if (m_aligned)
- penWidth = qRound(penWidth);
-
- QSGGeometry *g = geometry();
- g->setDrawingMode(GL_TRIANGLE_STRIP);
- int vertexStride = g->sizeOfVertex();
-
- union {
- Vertex *vertices;
- SmoothVertex *smoothVertices;
- };
-
- Color4ub fillColor = colorToColor4ub(m_color);
- Color4ub borderColor = colorToColor4ub(m_border_color);
- Color4ub transparent = { 0, 0, 0, 0 };
- const QGradientStops &stops = m_gradient_stops;
-
- int nextGradientStop = 0;
- float gradientPos = penWidth / height;
- while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos)
- ++nextGradientStop;
- int lastGradientStop = stops.size() - 1;
- float lastGradientPos = 1.0f - penWidth / height;
- while (lastGradientStop >= nextGradientStop && stops.at(lastGradientStop).first >= lastGradientPos)
- --lastGradientStop;
- int gradientIntersections = (lastGradientStop - nextGradientStop + 1);
-
- if (m_radius > 0) {
- // Rounded corners.
-
- // Radius should never exceeds half of the width or half of the height
- float radius = qMin(qMin(width, height) * 0.5f, float(m_radius));
- QRectF innerRect = m_rect;
- innerRect.adjust(radius, radius, -radius, -radius);
-
- float innerRadius = radius - penWidth * 1.0f;
- float outerRadius = radius;
- float delta = qMin(width, height) * 0.5f;
-
- // Number of segments per corner, approximately one per 3 pixels.
- int segments = qBound(3, qCeil(outerRadius * (M_PI / 6)), 18);
-
- /*
-
- --+--__
- --+--__--__
- | --__--__
- | seg --__--+
- --+-__ ment _+ \
- --+-__--__ - \ \
- --__--+ se \ \
- + \ g \ \
- \ \ m \ \
- -----------+--+ e \ \ <- gradient line
- \ \ nt\ \
- fill +--+----+--+
- | | | |
- border
- inner AA outer AA (AA = antialiasing)
-
- */
-
- int innerVertexCount = (segments + 1) * 4 + gradientIntersections * 2;
- int outerVertexCount = (segments + 1) * 4;
- int vertexCount = innerVertexCount;
- if (m_antialiasing || penWidth)
- vertexCount += innerVertexCount;
- if (penWidth)
- vertexCount += outerVertexCount;
- if (m_antialiasing && penWidth)
- vertexCount += outerVertexCount;
-
- int fillIndexCount = innerVertexCount;
- int innerAAIndexCount = innerVertexCount * 2 + 2;
- int borderIndexCount = innerVertexCount * 2 + 2;
- int outerAAIndexCount = outerVertexCount * 2 + 2;
- int indexCount = 0;
- int fillHead = 0;
- int innerAAHead = 0;
- int innerAATail = 0;
- int borderHead = 0;
- int borderTail = 0;
- int outerAAHead = 0;
- int outerAATail = 0;
- bool hasFill = m_color.alpha() > 0 || !stops.isEmpty();
- if (hasFill)
- indexCount += fillIndexCount;
- if (m_antialiasing) {
- innerAATail = innerAAHead = indexCount + (innerAAIndexCount >> 1) + 1;
- indexCount += innerAAIndexCount;
- }
- if (penWidth) {
- borderTail = borderHead = indexCount + (borderIndexCount >> 1) + 1;
- indexCount += borderIndexCount;
- }
- if (m_antialiasing && penWidth) {
- outerAATail = outerAAHead = indexCount + (outerAAIndexCount >> 1) + 1;
- indexCount += outerAAIndexCount;
- }
-
- g->allocate(vertexCount, indexCount);
- vertices = reinterpret_cast<Vertex *>(g->vertexData());
- memset(vertices, 0, vertexCount * vertexStride);
- quint16 *indices = g->indexDataAsUShort();
- quint16 index = 0;
-
- float py = 0; // previous inner y-coordinate.
- float plx = 0; // previous inner left x-coordinate.
- float prx = 0; // previous inner right x-coordinate.
-
- float angle = 0.5f * float(M_PI) / segments;
- float cosStep = qFastCos(angle);
- float sinStep = qFastSin(angle);
-
- for (int part = 0; part < 2; ++part) {
- float c = 1 - part;
- float s = part;
- for (int i = 0; i <= segments; ++i) {
- float y, lx, rx;
- if (innerRadius > 0) {
- y = (part ? innerRect.bottom() : innerRect.top()) - innerRadius * c; // current inner y-coordinate.
- lx = innerRect.left() - innerRadius * s; // current inner left x-coordinate.
- rx = innerRect.right() + innerRadius * s; // current inner right x-coordinate.
- gradientPos = ((part ? innerRect.height() : 0) + radius - innerRadius * c) / height;
- } else {
- y = (part ? innerRect.bottom() + innerRadius : innerRect.top() - innerRadius); // current inner y-coordinate.
- lx = innerRect.left() - innerRadius; // current inner left x-coordinate.
- rx = innerRect.right() + innerRadius; // current inner right x-coordinate.
- gradientPos = ((part ? innerRect.height() + innerRadius : -innerRadius) + radius) / height;
- }
- float Y = (part ? innerRect.bottom() : innerRect.top()) - outerRadius * c; // current outer y-coordinate.
- float lX = innerRect.left() - outerRadius * s; // current outer left x-coordinate.
- float rX = innerRect.right() + outerRadius * s; // current outer right x-coordinate.
-
- while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
- // Insert vertices at gradient stops.
- float gy = (innerRect.top() - radius) + stops.at(nextGradientStop).first * height;
- float t = (gy - py) / (y - py);
- float glx = plx * (1 - t) + t * lx;
- float grx = prx * (1 - t) + t * rx;
-
- fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
-
- if (hasFill) {
- indices[fillHead++] = index;
- indices[fillHead++] = index + 1;
- }
-
- if (penWidth) {
- --borderHead;
- indices[borderHead] = indices[borderHead + 2];
- indices[--borderHead] = index + 2;
- indices[borderTail++] = index + 3;
- indices[borderTail] = indices[borderTail - 2];
- ++borderTail;
- }
-
- if (m_antialiasing) {
- indices[--innerAAHead] = index + 2;
- indices[--innerAAHead] = index;
- indices[innerAATail++] = index + 1;
- indices[innerAATail++] = index + 3;
-
- bool lower = stops.at(nextGradientStop).first > 0.5f;
- float dy = lower ? qMin(0.0f, height - gy - delta) : qMax(0.0f, delta - gy);
- smoothVertices[index++].set(grx, gy, fillColor, width - grx - delta, dy);
- smoothVertices[index++].set(glx, gy, fillColor, delta - glx, dy);
- if (penWidth) {
- smoothVertices[index++].set(grx, gy, borderColor, 0.49f * penWidth * s, -0.49f * penWidth * c);
- smoothVertices[index++].set(glx, gy, borderColor, -0.49f * penWidth * s, -0.49f * penWidth * c);
- } else {
- dy = lower ? delta : -delta;
- smoothVertices[index++].set(grx, gy, transparent, delta, dy);
- smoothVertices[index++].set(glx, gy, transparent, -delta, dy);
- }
- } else {
- vertices[index++].set(grx, gy, fillColor);
- vertices[index++].set(glx, gy, fillColor);
- if (penWidth) {
- vertices[index++].set(grx, gy, borderColor);
- vertices[index++].set(glx, gy, borderColor);
- }
- }
- ++nextGradientStop;
- }
-
- if (!stops.isEmpty()) {
- if (nextGradientStop == 0) {
- fillColor = colorToColor4ub(stops.at(0).second);
- } else if (nextGradientStop == stops.size()) {
- fillColor = colorToColor4ub(stops.last().second);
- } else {
- const QGradientStop &prev = stops.at(nextGradientStop - 1);
- const QGradientStop &next = stops.at(nextGradientStop);
- float t = (gradientPos - prev.first) / (next.first - prev.first);
- fillColor = colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t;
- }
- }
-
- if (hasFill) {
- indices[fillHead++] = index;
- indices[fillHead++] = index + 1;
- }
-
- if (penWidth) {
- indices[--borderHead] = index + 4;
- indices[--borderHead] = index + 2;
- indices[borderTail++] = index + 3;
- indices[borderTail++] = index + 5;
- }
-
- if (m_antialiasing) {
- indices[--innerAAHead] = index + 2;
- indices[--innerAAHead] = index;
- indices[innerAATail++] = index + 1;
- indices[innerAATail++] = index + 3;
-
- float dy = part ? qMin(0.0f, height - y - delta) : qMax(0.0f, delta - y);
- smoothVertices[index++].set(rx, y, fillColor, width - rx - delta, dy);
- smoothVertices[index++].set(lx, y, fillColor, delta - lx, dy);
-
- dy = part ? delta : -delta;
- if (penWidth) {
- smoothVertices[index++].set(rx, y, borderColor, 0.49f * penWidth * s, -0.49f * penWidth * c);
- smoothVertices[index++].set(lx, y, borderColor, -0.49f * penWidth * s, -0.49f * penWidth * c);
- smoothVertices[index++].set(rX, Y, borderColor, -0.49f * penWidth * s, 0.49f * penWidth * c);
- smoothVertices[index++].set(lX, Y, borderColor, 0.49f * penWidth * s, 0.49f * penWidth * c);
- smoothVertices[index++].set(rX, Y, transparent, delta, dy);
- smoothVertices[index++].set(lX, Y, transparent, -delta, dy);
-
- indices[--outerAAHead] = index - 2;
- indices[--outerAAHead] = index - 4;
- indices[outerAATail++] = index - 3;
- indices[outerAATail++] = index - 1;
- } else {
- smoothVertices[index++].set(rx, y, transparent, delta, dy);
- smoothVertices[index++].set(lx, y, transparent, -delta, dy);
- }
- } else {
- vertices[index++].set(rx, y, fillColor);
- vertices[index++].set(lx, y, fillColor);
- if (penWidth) {
- vertices[index++].set(rx, y, borderColor);
- vertices[index++].set(lx, y, borderColor);
- vertices[index++].set(rX, Y, borderColor);
- vertices[index++].set(lX, Y, borderColor);
- }
- }
-
- py = y;
- plx = lx;
- prx = rx;
-
- // Rotate
- qreal tmp = c;
- c = c * cosStep - s * sinStep;
- s = s * cosStep + tmp * sinStep;
- }
- }
- Q_ASSERT(index == vertexCount);
-
- // Close the triangle strips.
- if (m_antialiasing) {
- indices[--innerAAHead] = indices[innerAATail - 1];
- indices[--innerAAHead] = indices[innerAATail - 2];
- Q_ASSERT(innerAATail <= indexCount);
- }
- if (penWidth) {
- indices[--borderHead] = indices[borderTail - 1];
- indices[--borderHead] = indices[borderTail - 2];
- Q_ASSERT(borderTail <= indexCount);
- }
- if (m_antialiasing && penWidth) {
- indices[--outerAAHead] = indices[outerAATail - 1];
- indices[--outerAAHead] = indices[outerAATail - 2];
- Q_ASSERT(outerAATail == indexCount);
- }
- } else {
- // Straight corners.
- QRectF innerRect = m_rect;
- QRectF outerRect = m_rect;
-
- if (penWidth)
- innerRect.adjust(1.0f * penWidth, 1.0f * penWidth, -1.0f * penWidth, -1.0f * penWidth);
-
- float delta = qMin(width, height) * 0.5f;
- int innerVertexCount = 4 + gradientIntersections * 2;
- int outerVertexCount = 4;
- int vertexCount = innerVertexCount;
- if (m_antialiasing || penWidth)
- vertexCount += innerVertexCount;
- if (penWidth)
- vertexCount += outerVertexCount;
- if (m_antialiasing && penWidth)
- vertexCount += outerVertexCount;
-
- int fillIndexCount = innerVertexCount;
- int innerAAIndexCount = innerVertexCount * 2 + 2;
- int borderIndexCount = innerVertexCount * 2 + 2;
- int outerAAIndexCount = outerVertexCount * 2 + 2;
- int indexCount = 0;
- int fillHead = 0;
- int innerAAHead = 0;
- int innerAATail = 0;
- int borderHead = 0;
- int borderTail = 0;
- int outerAAHead = 0;
- int outerAATail = 0;
- bool hasFill = m_color.alpha() > 0 || !stops.isEmpty();
- if (hasFill)
- indexCount += fillIndexCount;
- if (m_antialiasing) {
- innerAATail = innerAAHead = indexCount + (innerAAIndexCount >> 1) + 1;
- indexCount += innerAAIndexCount;
- }
- if (penWidth) {
- borderTail = borderHead = indexCount + (borderIndexCount >> 1) + 1;
- indexCount += borderIndexCount;
- }
- if (m_antialiasing && penWidth) {
- outerAATail = outerAAHead = indexCount + (outerAAIndexCount >> 1) + 1;
- indexCount += outerAAIndexCount;
- }
-
- g->allocate(vertexCount, indexCount);
- vertices = reinterpret_cast<Vertex *>(g->vertexData());
- memset(vertices, 0, vertexCount * vertexStride);
- quint16 *indices = g->indexDataAsUShort();
- quint16 index = 0;
-
- float lx = innerRect.left();
- float rx = innerRect.right();
- float lX = outerRect.left();
- float rX = outerRect.right();
-
- for (int part = -1; part <= 1; part += 2) {
- float y = (part == 1 ? innerRect.bottom() : innerRect.top());
- float Y = (part == 1 ? outerRect.bottom() : outerRect.top());
- gradientPos = (y - innerRect.top() + penWidth) / height;
-
- while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) {
- // Insert vertices at gradient stops.
- float gy = (innerRect.top() - penWidth) + stops.at(nextGradientStop).first * height;
-
- fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
-
- if (hasFill) {
- indices[fillHead++] = index;
- indices[fillHead++] = index + 1;
- }
-
- if (penWidth) {
- --borderHead;
- indices[borderHead] = indices[borderHead + 2];
- indices[--borderHead] = index + 2;
- indices[borderTail++] = index + 3;
- indices[borderTail] = indices[borderTail - 2];
- ++borderTail;
- }
-
- if (m_antialiasing) {
- indices[--innerAAHead] = index + 2;
- indices[--innerAAHead] = index;
- indices[innerAATail++] = index + 1;
- indices[innerAATail++] = index + 3;
-
- bool lower = stops.at(nextGradientStop).first > 0.5f;
- float dy = lower ? qMin(0.0f, height - gy - delta) : qMax(0.0f, delta - gy);
- smoothVertices[index++].set(rx, gy, fillColor, width - rx - delta, dy);
- smoothVertices[index++].set(lx, gy, fillColor, delta - lx, dy);
- if (penWidth) {
- smoothVertices[index++].set(rx, gy, borderColor, 0.49f * penWidth, (lower ? 0.49f : -0.49f) * penWidth);
- smoothVertices[index++].set(lx, gy, borderColor, -0.49f * penWidth, (lower ? 0.49f : -0.49f) * penWidth);
- } else {
- smoothVertices[index++].set(rx, gy, transparent, delta, lower ? delta : -delta);
- smoothVertices[index++].set(lx, gy, transparent, -delta, lower ? delta : -delta);
- }
- } else {
- vertices[index++].set(rx, gy, fillColor);
- vertices[index++].set(lx, gy, fillColor);
- if (penWidth) {
- vertices[index++].set(rx, gy, borderColor);
- vertices[index++].set(lx, gy, borderColor);
- }
- }
- ++nextGradientStop;
- }
-
- if (!stops.isEmpty()) {
- if (nextGradientStop == 0) {
- fillColor = colorToColor4ub(stops.at(0).second);
- } else if (nextGradientStop == stops.size()) {
- fillColor = colorToColor4ub(stops.last().second);
- } else {
- const QGradientStop &prev = stops.at(nextGradientStop - 1);
- const QGradientStop &next = stops.at(nextGradientStop);
- float t = (gradientPos - prev.first) / (next.first - prev.first);
- fillColor = colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t;
- }
- }
-
- if (hasFill) {
- indices[fillHead++] = index;
- indices[fillHead++] = index + 1;
- }
-
- if (penWidth) {
- indices[--borderHead] = index + 4;
- indices[--borderHead] = index + 2;
- indices[borderTail++] = index + 3;
- indices[borderTail++] = index + 5;
- }
-
- if (m_antialiasing) {
- indices[--innerAAHead] = index + 2;
- indices[--innerAAHead] = index;
- indices[innerAATail++] = index + 1;
- indices[innerAATail++] = index + 3;
-
- float dy = part == 1 ? qMin(0.0f, height - y - delta) : qMax(0.0f, delta - y);
- smoothVertices[index++].set(rx, y, fillColor, width - rx - delta, dy);
- smoothVertices[index++].set(lx, y, fillColor, delta - lx, dy);
-
- if (penWidth) {
- smoothVertices[index++].set(rx, y, borderColor, 0.49f * penWidth, 0.49f * penWidth * part);
- smoothVertices[index++].set(lx, y, borderColor, -0.49f * penWidth, 0.49f * penWidth * part);
- smoothVertices[index++].set(rX, Y, borderColor, -0.49f * penWidth, -0.49f * penWidth * part);
- smoothVertices[index++].set(lX, Y, borderColor, 0.49f * penWidth, -0.49f * penWidth * part);
- smoothVertices[index++].set(rX, Y, transparent, delta, delta * part);
- smoothVertices[index++].set(lX, Y, transparent, -delta, delta * part);
-
- indices[--outerAAHead] = index - 2;
- indices[--outerAAHead] = index - 4;
- indices[outerAATail++] = index - 3;
- indices[outerAATail++] = index - 1;
- } else {
- smoothVertices[index++].set(rx, y, transparent, delta, delta * part);
- smoothVertices[index++].set(lx, y, transparent, -delta, delta * part);
- }
- } else {
- vertices[index++].set(rx, y, fillColor);
- vertices[index++].set(lx, y, fillColor);
- if (penWidth) {
- vertices[index++].set(rx, y, borderColor);
- vertices[index++].set(lx, y, borderColor);
- vertices[index++].set(rX, Y, borderColor);
- vertices[index++].set(lX, Y, borderColor);
- }
- }
- }
- Q_ASSERT(index == vertexCount);
-
- // Close the triangle strips.
- if (m_antialiasing) {
- indices[--innerAAHead] = indices[innerAATail - 1];
- indices[--innerAAHead] = indices[innerAATail - 2];
- Q_ASSERT(innerAATail <= indexCount);
- }
- if (penWidth) {
- indices[--borderHead] = indices[borderTail - 1];
- indices[--borderHead] = indices[borderTail - 2];
- Q_ASSERT(borderTail <= indexCount);
- }
- if (m_antialiasing && penWidth) {
- indices[--outerAAHead] = indices[outerAATail - 1];
- indices[--outerAAHead] = indices[outerAATail - 2];
- Q_ASSERT(outerAATail == indexCount);
+ // smoothed material is always blended, so no change in material state
+ if (material() == &m_material) {
+ bool wasBlending = (m_material.flags() & QSGMaterial::Blending);
+ bool isBlending = (m_gradient_stops.size() > 0 && !m_gradient_is_opaque)
+ || (m_color.alpha() < 255 && m_color.alpha() != 0)
+ || (m_pen_width > 0 && m_border_color.alpha() < 255);
+ if (wasBlending != isBlending) {
+ m_material.setFlag(QSGMaterial::Blending, isBlending);
+ *state |= QSGNode::DirtyMaterial;
}
}
}
-
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode_p.h b/src/quick/scenegraph/qsgdefaultrectanglenode_p.h
index 4cfe921127..f30a3beed7 100644
--- a/src/quick/scenegraph/qsgdefaultrectanglenode_p.h
+++ b/src/quick/scenegraph/qsgdefaultrectanglenode_p.h
@@ -53,7 +53,7 @@
//
#include <private/qsgadaptationlayer_p.h>
-
+#include <private/qsgbasicrectanglenode_p.h>
#include <QtQuick/qsgvertexcolormaterial.h>
QT_BEGIN_NAMESPACE
@@ -68,45 +68,21 @@ public:
int compare(const QSGMaterial *other) const;
protected:
- virtual QSGMaterialType *type() const;
- virtual QSGMaterialShader *createShader() const;
+ QSGMaterialType *type() const override;
+ QSGMaterialShader *createShader() const override;
};
-class Q_QUICK_PRIVATE_EXPORT QSGDefaultRectangleNode : public QSGRectangleNode
+class Q_QUICK_PRIVATE_EXPORT QSGDefaultRectangleNode : public QSGBasicRectangleNode
{
public:
QSGDefaultRectangleNode();
- virtual void setRect(const QRectF &rect);
- virtual void setColor(const QColor &color);
- virtual void setPenColor(const QColor &color);
- virtual void setPenWidth(qreal width);
- virtual void setGradientStops(const QGradientStops &stops);
- virtual void setRadius(qreal radius);
- virtual void setAntialiasing(bool antialiasing);
- virtual void setAligned(bool aligned);
- virtual void update();
-
private:
- void updateGeometry();
- void updateGradientTexture();
+ void updateMaterialAntialiasing() override;
+ void updateMaterialBlending(QSGNode::DirtyState *state) override;
QSGVertexColorMaterial m_material;
QSGSmoothColorMaterial m_smoothMaterial;
-
- QRectF m_rect;
- QGradientStops m_gradient_stops;
- QColor m_color;
- QColor m_border_color;
- qreal m_radius;
- qreal m_pen_width;
-
- uint m_aligned : 1;
- uint m_antialiasing : 1;
- uint m_gradient_is_opaque : 1;
- uint m_dirty_geometry : 1;
-
- QSGGeometry m_geometry;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
new file mode 100644
index 0000000000..92e7f983a0
--- /dev/null
+++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
@@ -0,0 +1,302 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultrendercontext_p.h"
+
+#include <QtGui/QOpenGLFramebufferObject>
+
+#include <QtQuick/private/qsgbatchrenderer_p.h>
+#include <QtQuick/private/qsgrenderer_p.h>
+#include <QtQuick/private/qsgatlastexture_p.h>
+#include <QtQuick/private/qsgdefaultdistancefieldglyphcache_p.h>
+#include <QtQuick/private/qsgdistancefieldutil_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QSG_RENDERCONTEXT_PROPERTY "_q_sgrendercontext"
+
+QSGDefaultRenderContext::QSGDefaultRenderContext(QSGContext *context)
+ : QSGRenderContext(context)
+ , m_gl(nullptr)
+ , m_depthStencilManager(nullptr)
+ , m_maxTextureSize(0)
+ , m_brokenIBOs(false)
+ , m_serializedRender(false)
+ , m_attachToGLContext(true)
+ , m_atlasManager(nullptr)
+{
+
+}
+
+/*!
+ Initializes the scene graph render context with the GL context \a context. This also
+ emits the ready() signal so that the QML graph can start building scene graph nodes.
+ */
+void QSGDefaultRenderContext::initialize(void *context)
+{
+ QOpenGLContext *openglContext = static_cast<QOpenGLContext *>(context);
+
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
+
+ // Sanity check the surface format, in case it was overridden by the application
+ QSurfaceFormat requested = m_sg->defaultSurfaceFormat();
+ QSurfaceFormat actual = openglContext->format();
+ if (requested.depthBufferSize() > 0 && actual.depthBufferSize() <= 0)
+ qWarning("QSGContext::initialize: depth buffer support missing, expect rendering errors");
+ if (requested.stencilBufferSize() > 0 && actual.stencilBufferSize() <= 0)
+ qWarning("QSGContext::initialize: stencil buffer support missing, expect rendering errors");
+
+ if (!m_atlasManager)
+ m_atlasManager = new QSGAtlasTexture::Manager();
+
+ Q_ASSERT_X(!m_gl, "QSGRenderContext::initialize", "already initialized!");
+ m_gl = openglContext;
+ if (m_attachToGLContext) {
+ Q_ASSERT(!openglContext->property(QSG_RENDERCONTEXT_PROPERTY).isValid());
+ openglContext->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant::fromValue(this));
+ }
+ m_sg->renderContextInitialized(this);
+
+#ifdef Q_OS_LINUX
+ const char *vendor = (const char *) funcs->glGetString(GL_VENDOR);
+ if (strstr(vendor, "nouveau"))
+ m_brokenIBOs = true;
+ const char *renderer = (const char *) funcs->glGetString(GL_RENDERER);
+ if (strstr(renderer, "llvmpipe"))
+ m_serializedRender = true;
+ if (strstr(vendor, "Hisilicon Technologies") && strstr(renderer, "Immersion.16"))
+ m_brokenIBOs = true;
+#endif
+
+ emit initialized();
+}
+
+
+void QSGDefaultRenderContext::invalidate()
+{
+ if (!m_gl)
+ return;
+
+ qDeleteAll(m_texturesToDelete);
+ m_texturesToDelete.clear();
+
+ qDeleteAll(m_textures);
+ m_textures.clear();
+
+ /* The cleanup of the atlas textures is a bit intriguing.
+ As part of the cleanup in the threaded render loop, we
+ do:
+ 1. call this function
+ 2. call QCoreApp::sendPostedEvents() to immediately process
+ any pending deferred deletes.
+ 3. delete the GL context.
+
+ As textures need the atlas manager while cleaning up, the
+ manager needs to be cleaned up after the textures, so
+ we post a deleteLater here at the very bottom so it gets
+ deferred deleted last.
+
+ Another alternative would be to use a QPointer in
+ QSGAtlasTexture::Texture, but this seemed simpler.
+ */
+ m_atlasManager->invalidate();
+ m_atlasManager->deleteLater();
+ m_atlasManager = nullptr;
+
+ // The following piece of code will read/write to the font engine's caches,
+ // potentially from different threads. However, this is safe because this
+ // code is only called from QQuickWindow's shutdown which is called
+ // only when the GUI is blocked, and multiple threads will call it in
+ // sequence. (see qsgdefaultglyphnode_p.cpp's init())
+ for (QSet<QFontEngine *>::const_iterator it = m_fontEnginesToClean.constBegin(),
+ end = m_fontEnginesToClean.constEnd(); it != end; ++it) {
+ (*it)->clearGlyphCache(m_gl);
+ if (!(*it)->ref.deref())
+ delete *it;
+ }
+ m_fontEnginesToClean.clear();
+
+ delete m_depthStencilManager;
+ m_depthStencilManager = 0;
+
+ delete m_distanceFieldCacheManager;
+ m_distanceFieldCacheManager = 0;
+
+ if (m_gl->property(QSG_RENDERCONTEXT_PROPERTY) == QVariant::fromValue(this))
+ m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant());
+ m_gl = 0;
+
+ QSGRenderContext::invalidate();
+}
+
+static QBasicMutex qsg_framerender_mutex;
+
+void QSGDefaultRenderContext::renderNextFrame(QSGRenderer *renderer, uint fboId)
+{
+ if (m_serializedRender)
+ qsg_framerender_mutex.lock();
+
+ renderer->renderScene(fboId);
+
+ if (m_serializedRender)
+ qsg_framerender_mutex.unlock();
+}
+
+/*!
+ Returns a shared pointer to a depth stencil buffer that can be used with \a fbo.
+*/
+QSharedPointer<QSGDepthStencilBuffer> QSGDefaultRenderContext::depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo)
+{
+ if (!m_gl)
+ return QSharedPointer<QSGDepthStencilBuffer>();
+ QSGDepthStencilBufferManager *manager = depthStencilBufferManager();
+ QSGDepthStencilBuffer::Format format;
+ format.size = fbo->size();
+ format.samples = fbo->format().samples();
+ format.attachments = QSGDepthStencilBuffer::DepthAttachment | QSGDepthStencilBuffer::StencilAttachment;
+ QSharedPointer<QSGDepthStencilBuffer> buffer = manager->bufferForFormat(format);
+ if (buffer.isNull()) {
+ buffer = QSharedPointer<QSGDepthStencilBuffer>(new QSGDefaultDepthStencilBuffer(m_gl, format));
+ manager->insertBuffer(buffer);
+ }
+ return buffer;
+}
+
+/*!
+ Returns a pointer to the context's depth/stencil buffer manager. This is useful for custom
+ implementations of \l depthStencilBufferForFbo().
+*/
+QSGDepthStencilBufferManager *QSGDefaultRenderContext::depthStencilBufferManager()
+{
+ if (!m_gl)
+ return 0;
+ if (!m_depthStencilManager)
+ m_depthStencilManager = new QSGDepthStencilBufferManager(m_gl);
+ return m_depthStencilManager;
+}
+
+QSGTexture *QSGDefaultRenderContext::createTexture(const QImage &image, uint flags) const
+{
+ bool atlas = flags & CreateTexture_Atlas;
+ bool mipmap = flags & CreateTexture_Mipmap;
+ bool alpha = flags & CreateTexture_Alpha;
+
+ // The atlas implementation is only supported from the render thread and
+ // does not support mipmaps.
+ if (!mipmap && atlas && openglContext() && QThread::currentThread() == openglContext()->thread()) {
+ QSGTexture *t = m_atlasManager->create(image, alpha);
+ if (t)
+ return t;
+ }
+
+ QSGPlainTexture *texture = new QSGPlainTexture();
+ texture->setImage(image);
+ if (texture->hasAlphaChannel() && !alpha)
+ texture->setHasAlphaChannel(false);
+
+ return texture;
+}
+
+QSGRenderer *QSGDefaultRenderContext::createRenderer()
+{
+ return new QSGBatchRenderer::Renderer(this);
+}
+
+/*!
+ Compile \a shader, optionally using \a vertexCode and \a fragmentCode as
+ replacement for the source code supplied by \a shader.
+
+ If \a vertexCode or \a fragmentCode is supplied, the caller is responsible
+ for setting up attribute bindings.
+
+ \a material is supplied in case the implementation needs to take the
+ material flags into account.
+ */
+void QSGDefaultRenderContext::compileShader(QSGMaterialShader *shader, QSGMaterial *material, const char *vertexCode, const char *fragmentCode)
+{
+ Q_UNUSED(material);
+ if (vertexCode || fragmentCode) {
+ Q_ASSERT_X((material->flags() & QSGMaterial::CustomCompileStep) == 0,
+ "QSGRenderContext::compile()",
+ "materials with custom compile step cannot have custom vertex/fragment code");
+ QOpenGLShaderProgram *p = shader->program();
+ p->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexCode ? vertexCode : shader->vertexShader());
+ p->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentCode ? fragmentCode : shader->fragmentShader());
+ p->link();
+ if (!p->isLinked())
+ qWarning() << "shader compilation failed:" << endl << p->log();
+ } else {
+ shader->compile();
+ }
+}
+
+void QSGDefaultRenderContext::initializeShader(QSGMaterialShader *shader)
+{
+ shader->program()->bind();
+ shader->initialize();
+}
+
+void QSGDefaultRenderContext::setAttachToGLContext(bool attach)
+{
+ Q_ASSERT(!isValid());
+ m_attachToGLContext = attach;
+}
+
+QSGDefaultRenderContext *QSGDefaultRenderContext::from(QOpenGLContext *context)
+{
+ return qobject_cast<QSGDefaultRenderContext *>(context->property(QSG_RENDERCONTEXT_PROPERTY).value<QObject *>());
+}
+
+QT_END_NAMESPACE
+
+
+QSGDistanceFieldGlyphCache *QSGDefaultRenderContext::distanceFieldGlyphCache(const QRawFont &font)
+{
+ if (!m_distanceFieldCacheManager)
+ m_distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager;
+
+ QSGDistanceFieldGlyphCache *cache = m_distanceFieldCacheManager->cache(font);
+ if (!cache) {
+ cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font);
+ m_distanceFieldCacheManager->insertCache(font, cache);
+ }
+
+ return cache;
+}
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext_p.h b/src/quick/scenegraph/qsgdefaultrendercontext_p.h
new file mode 100644
index 0000000000..bfb15b1eb9
--- /dev/null
+++ b/src/quick/scenegraph/qsgdefaultrendercontext_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGDEFAULTRENDERCONTEXT_H
+#define QSGDEFAULTRENDERCONTEXT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/private/qsgcontext_p.h>
+#include <QtQuick/private/qsgdepthstencilbuffer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLContext;
+class QSGMaterialShader;
+class QOpenGLFramebufferObject;
+
+namespace QSGAtlasTexture {
+ class Manager;
+}
+
+class QSGDefaultRenderContext : public QSGRenderContext
+{
+ Q_OBJECT
+public:
+ QSGDefaultRenderContext(QSGContext *context);
+
+ QOpenGLContext *openglContext() const { return m_gl; }
+ bool isValid() const override { return m_gl; }
+
+ void initialize(void *context) override;
+ void invalidate() override;
+ void renderNextFrame(QSGRenderer *renderer, uint fboId) override;
+
+ QSGDistanceFieldGlyphCache *distanceFieldGlyphCache(const QRawFont &font) override;
+
+ virtual QSharedPointer<QSGDepthStencilBuffer> depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo);
+ QSGDepthStencilBufferManager *depthStencilBufferManager();
+
+ QSGTexture *createTexture(const QImage &image, uint flags) const override;
+ QSGRenderer *createRenderer() override;
+
+ virtual void compileShader(QSGMaterialShader *shader, QSGMaterial *material, const char *vertexCode = 0, const char *fragmentCode = 0);
+ virtual void initializeShader(QSGMaterialShader *shader);
+
+ void setAttachToGLContext(bool attach);
+
+ static QSGDefaultRenderContext *from(QOpenGLContext *context);
+
+ bool hasBrokenIndexBufferObjects() const { return m_brokenIBOs; }
+ int maxTextureSize() const { return m_maxTextureSize; }
+
+protected:
+ QOpenGLContext *m_gl;
+ QSGDepthStencilBufferManager *m_depthStencilManager;
+ int m_maxTextureSize;
+ bool m_brokenIBOs;
+ bool m_serializedRender;
+ bool m_attachToGLContext;
+ QSGAtlasTexture::Manager *m_atlasManager;
+
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGDEFAULTRENDERCONTEXT_H
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index b5f149eff7..1a9b576af4 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -47,7 +47,6 @@
#include <QtCore/QLibraryInfo>
#include <QtCore/private/qabstractanimation_p.h>
-#include <QtGui/QOpenGLContext>
#include <QtGui/QOffscreenSurface>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
@@ -59,7 +58,11 @@
#include <QtQuick/private/qsgcontext_p.h>
#include <private/qquickprofiler_p.h>
-#include <private/qquickshadereffectnode_p.h>
+#ifndef QT_NO_OPENGL
+# include <QtGui/QOpenGLContext>
+# include <private/qsgdefaultrendercontext_p.h>
+# include <private/qquickopenglshadereffectnode_p.h>
+#endif
#ifdef Q_OS_WIN
# include <QtCore/qt_windows.h>
@@ -67,9 +70,9 @@
QT_BEGIN_NAMESPACE
-
+extern bool qsg_useConsistentTiming();
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
-
+#ifndef QT_NO_OPENGL
/*!
expectations for this manager to work:
- one opengl context to render multiple windows
@@ -81,7 +84,7 @@ extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_
DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_BAD_GUI_RENDER_LOOP);
DEFINE_BOOL_CONFIG_OPTION(qmlForceThreadedRenderer, QML_FORCE_THREADED_RENDERER); // Might trigger graphics driver threading bugs, use at own risk
-
+#endif
QSGRenderLoop *QSGRenderLoop::s_instance = 0;
QSGRenderLoop::~QSGRenderLoop()
@@ -113,17 +116,20 @@ void QSGRenderLoop::cleanup()
*/
void QSGRenderLoop::postJob(QQuickWindow *window, QRunnable *job)
{
- Q_ASSERT(window);
Q_ASSERT(job);
-
+#ifndef QT_NO_OPENGL
+ Q_ASSERT(window);
if (window->openglContext()) {
window->openglContext()->makeCurrent(window);
job->run();
}
-
+#else
+ Q_UNUSED(window)
+ job->run();
+#endif
delete job;
}
-
+#ifndef QT_NO_OPENGL
class QSGGuiThreadRenderLoop : public QSGRenderLoop
{
Q_OBJECT
@@ -164,7 +170,7 @@ public:
QImage grabContent;
};
-
+#endif
QSGRenderLoop *QSGRenderLoop::instance()
{
if (!s_instance) {
@@ -174,7 +180,7 @@ QSGRenderLoop *QSGRenderLoop::instance()
const_cast<QLoggingCategory &>(QSG_LOG_INFO()).setEnabled(QtDebugMsg, true);
s_instance = QSGContext::createWindowManager();
-
+#ifndef QT_NO_OPENGL
if (!s_instance) {
enum RenderLoopType {
@@ -226,9 +232,10 @@ QSGRenderLoop *QSGRenderLoop::instance()
break;
}
}
-
+#endif
qAddPostRoutine(QSGRenderLoop::cleanup);
}
+
return s_instance;
}
@@ -253,20 +260,24 @@ void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window,
const bool signalEmitted =
QQuickWindowPrivate::get(window)->emitError(QQuickWindow::ContextNotAvailable,
translatedMessage);
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
if (!signalEmitted && !QLibraryInfo::isDebugBuild() && !GetConsoleWindow()) {
MessageBox(0, (LPCTSTR) translatedMessage.utf16(),
(LPCTSTR)(QCoreApplication::applicationName().utf16()),
MB_OK | MB_ICONERROR);
}
-#endif // Q_OS_WIN && !Q_OS_WINCE && !Q_OS_WINRT
+#endif // Q_OS_WIN && !Q_OS_WINRT
if (!signalEmitted)
qFatal("%s", qPrintable(untranslatedMessage));
}
-
+#ifndef QT_NO_OPENGL
QSGGuiThreadRenderLoop::QSGGuiThreadRenderLoop()
: gl(0)
{
+ if (qsg_useConsistentTiming()) {
+ QUnifiedTimer::instance(true)->setConsistentTiming(true);
+ qCDebug(QSG_LOG_INFO, "using fixed animation steps");
+ }
sg = QSGContext::createDefaultContext();
rc = sg->createRenderContext();
}
@@ -315,7 +326,9 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
if (Q_UNLIKELY(!current))
qCDebug(QSG_LOG_RENDERLOOP) << "cleanup without an OpenGL context";
- QQuickShaderEffectMaterial::cleanupMaterialCache();
+#ifndef QT_NO_OPENGL
+ QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
+#endif
d->cleanupNodesOnShutdown();
if (m_windows.size() == 0) {
@@ -354,8 +367,10 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
cd->fireOpenGLContextCreated(gl);
current = gl->makeCurrent(window);
}
- if (current)
- cd->context->initialize(gl);
+ if (current) {
+ auto openglRenderContext = static_cast<QSGDefaultRenderContext *>(cd->context);
+ openglRenderContext->initialize(gl);
+ }
} else {
current = gl->makeCurrent(window);
}
@@ -367,7 +382,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
return;
if (!data.grabOnly) {
- cd->flushDelayedTouchEvent();
+ cd->flushFrameSynchronousEvents();
// Event delivery/processing triggered the window to be deleted or stop rendering.
if (!m_windows.contains(window))
return;
@@ -476,6 +491,8 @@ void QSGGuiThreadRenderLoop::handleUpdateRequest(QQuickWindow *window)
renderWindow(window);
}
+#endif
+
#include "qsgrenderloop.moc"
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h
index 9159a2f01d..7bf40ecac4 100644
--- a/src/quick/scenegraph/qsgrenderloop_p.h
+++ b/src/quick/scenegraph/qsgrenderloop_p.h
@@ -69,6 +69,10 @@ class Q_QUICK_PRIVATE_EXPORT QSGRenderLoop : public QObject
Q_OBJECT
public:
+ enum RenderLoopFlags {
+ SupportsGrabWithoutExpose = 0x01
+ };
+
virtual ~QSGRenderLoop();
virtual void show(QQuickWindow *window) = 0;
@@ -104,6 +108,8 @@ public:
virtual bool interleaveIncubation() const { return false; }
+ virtual int flags() const { return 0; }
+
static void cleanup();
Q_SIGNALS:
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 7c3405b715..3ff32b360d 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -63,7 +63,8 @@
#include <private/qqmldebugserviceinterfaces_p.h>
#include <private/qqmldebugconnector_p.h>
-#include <private/qquickshadereffectnode_p.h>
+#include <private/qquickopenglshadereffectnode_p.h>
+#include <private/qsgdefaultrendercontext_p.h>
/*
Overall design:
@@ -268,7 +269,6 @@ public:
QSGRenderThread(QSGThreadedRenderLoop *w, QSGRenderContext *renderContext)
: wm(w)
, gl(0)
- , sgrc(renderContext)
, animatorDriver(0)
, pendingUpdate(0)
, sleeping(false)
@@ -277,6 +277,7 @@ public:
, window(0)
, stopEventProcessing(false)
{
+ sgrc = static_cast<QSGDefaultRenderContext *>(renderContext);
#if defined(Q_OS_QNX) && !defined(Q_OS_BLACKBERRY) && defined(Q_PROCESSOR_X86)
// The SDP 6.6.0 x86 MESA driver requires a larger stack than the default.
setStackSize(1024 * 1024);
@@ -325,7 +326,7 @@ public:
QSGThreadedRenderLoop *wm;
QOpenGLContext *gl;
- QSGRenderContext *sgrc;
+ QSGDefaultRenderContext *sgrc;
QAnimationDriver *animatorDriver;
@@ -486,7 +487,7 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor,
QQuickWindowPrivate *dd = QQuickWindowPrivate::get(window);
- QQuickShaderEffectMaterial::cleanupMaterialCache();
+ QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
// The canvas nodes must be cleaned up regardless if we are in the destructor..
if (wipeSG) {
@@ -1141,7 +1142,7 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose)
}
// Flush pending touch events.
- QQuickWindowPrivate::get(window)->flushDelayedTouchEvent();
+ QQuickWindowPrivate::get(window)->flushFrameSynchronousEvents();
// The delivery of the event might have caused the window to stop rendering
w = windowFor(m_windows, window);
if (!w || !w->thread || !w->thread->window) {
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 901fbbec43..371f512c6e 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -48,13 +48,17 @@
#include <QtQuick/private/qsgcontext_p.h>
#include <QtQuick/private/qquickwindow_p.h>
+#include <QtQuick/private/qsgdefaultrendercontext_p.h>
#include <QtQuick/QQuickWindow>
#include <private/qquickprofiler_p.h>
-#include <private/qquickshadereffectnode_p.h>
#include <private/qquickanimatorcontroller_p.h>
+#ifndef QT_NO_OPENGL
+#include <private/qquickopenglshadereffectnode_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
@@ -78,7 +82,7 @@ QSGWindowsRenderLoop::QSGWindowsRenderLoop()
, m_updateTimer(0)
, m_animationTimer(0)
{
- m_rc = m_sg->createRenderContext();
+ m_rc = static_cast<QSGDefaultRenderContext *>(m_sg->createRenderContext());
m_animationDriver = m_sg->createAnimationDriver(m_sg);
m_animationDriver->install();
@@ -241,7 +245,9 @@ void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window)
if (Q_UNLIKELY(!current))
qCDebug(QSG_LOG_RENDERLOOP) << "cleanup without an OpenGL context";
- QQuickShaderEffectMaterial::cleanupMaterialCache();
+#ifndef QT_NO_OPENGL
+ QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
+#endif
d->cleanupNodesOnShutdown();
if (m_windows.size() == 0) {
@@ -341,6 +347,11 @@ void QSGWindowsRenderLoop::maybeUpdate(QQuickWindow *window)
maybePostUpdateTimer();
}
+QSGRenderContext *QSGWindowsRenderLoop::createRenderContext(QSGContext *) const
+{
+ return m_rc;
+}
+
bool QSGWindowsRenderLoop::event(QEvent *event)
{
switch (event->type()) {
@@ -434,7 +445,7 @@ void QSGWindowsRenderLoop::renderWindow(QQuickWindow *window)
}
}
- d->flushDelayedTouchEvent();
+ d->flushFrameSynchronousEvents();
// Event delivery or processing has caused the window to stop rendering.
if (!windowData(window))
return;
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop_p.h b/src/quick/scenegraph/qsgwindowsrenderloop_p.h
index ad7986035f..9e5d7f04d3 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop_p.h
+++ b/src/quick/scenegraph/qsgwindowsrenderloop_p.h
@@ -61,6 +61,7 @@
QT_BEGIN_NAMESPACE
class QSGRenderContext;
+class QSGDefaultRenderContext;
class QSGWindowsRenderLoop : public QSGRenderLoop
{
@@ -83,7 +84,7 @@ public:
QAnimationDriver *animationDriver() const { return m_animationDriver; }
QSGContext *sceneGraphContext() const { return m_sg; }
- QSGRenderContext *createRenderContext(QSGContext *) const { return m_rc; }
+ QSGRenderContext *createRenderContext(QSGContext *) const;
void releaseResources(QQuickWindow *) { }
@@ -113,7 +114,7 @@ private:
QOpenGLContext *m_gl;
QSGContext *m_sg;
- QSGRenderContext *m_rc;
+ QSGDefaultRenderContext *m_rc;
QAnimationDriver *m_animationDriver;
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index 84cc2ba135..d8dfd01e7a 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -5,169 +5,202 @@
# Core API
HEADERS += \
- $$PWD/coreapi/qsgbatchrenderer_p.h \
$$PWD/coreapi/qsggeometry.h \
$$PWD/coreapi/qsgmaterial.h \
+ $$PWD/coreapi/qsgmaterialshader_p.h \
$$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.h \
$$PWD/coreapi/qsgrendernode_p.h \
- $$PWD/coreapi/qsggeometry_p.h \
- $$PWD/coreapi/qsgmaterialshader_p.h
+ $$PWD/coreapi/qsgrendererinterface.h \
+ $$PWD/coreapi/qsggeometry_p.h
SOURCES += \
$$PWD/coreapi/qsgabstractrenderer.cpp \
- $$PWD/coreapi/qsgbatchrenderer.cpp \
$$PWD/coreapi/qsggeometry.cpp \
$$PWD/coreapi/qsgmaterial.cpp \
$$PWD/coreapi/qsgnode.cpp \
$$PWD/coreapi/qsgnodeupdater.cpp \
$$PWD/coreapi/qsgrenderer.cpp \
$$PWD/coreapi/qsgrendernode.cpp \
- $$PWD/coreapi/qsgshaderrewriter.cpp
+ $$PWD/coreapi/qsgrendererinterface.cpp
+
+contains(QT_CONFIG, opengl(es1|es2)?) {
+ HEADERS += \
+ $$PWD/coreapi/qsgbatchrenderer_p.h
+ SOURCES += \
+ $$PWD/coreapi/qsgbatchrenderer.cpp \
+ $$PWD/coreapi/qsgshaderrewriter.cpp
+}
# Util API
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 \
$$PWD/util/qsgsimpletexturenode.h \
- $$PWD/util/qsgtexturematerial.h \
- $$PWD/util/qsgtexturematerial_p.h \
- $$PWD/util/qsgvertexcolormaterial.h \
$$PWD/util/qsgtexture.h \
$$PWD/util/qsgtexture_p.h \
$$PWD/util/qsgtextureprovider.h \
- $$PWD/util/qsgdefaultpainternode_p.h \
$$PWD/util/qsgdistancefieldutil_p.h \
- $$PWD/util/qsgshadersourcebuilder_p.h
+ $$PWD/util/qsgflatcolormaterial.h \
+ $$PWD/util/qsgsimplematerial.h \
+ $$PWD/util/qsgtexturematerial.h \
+ $$PWD/util/qsgtexturematerial_p.h \
+ $$PWD/util/qsgvertexcolormaterial.h
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 \
- $$PWD/util/qsgtexturematerial.cpp \
- $$PWD/util/qsgvertexcolormaterial.cpp \
$$PWD/util/qsgtexture.cpp \
$$PWD/util/qsgtextureprovider.cpp \
- $$PWD/util/qsgdefaultpainternode.cpp \
$$PWD/util/qsgdistancefieldutil.cpp \
+ $$PWD/util/qsgflatcolormaterial.cpp \
$$PWD/util/qsgsimplematerial.cpp \
- $$PWD/util/qsgshadersourcebuilder.cpp
+ $$PWD/util/qsgtexturematerial.cpp \
+ $$PWD/util/qsgvertexcolormaterial.cpp
+contains(QT_CONFIG, opengl(es1|es2)?) {
+ HEADERS += \
+ $$PWD/util/qsgdepthstencilbuffer_p.h \
+ $$PWD/util/qsgshadersourcebuilder_p.h \
+ $$PWD/util/qsgatlastexture_p.h
+ SOURCES += \
+ $$PWD/util/qsgdepthstencilbuffer.cpp \
+ $$PWD/util/qsgatlastexture.cpp \
+ $$PWD/util/qsgshadersourcebuilder.cpp
+}
+
# QML / Adaptations API
HEADERS += \
$$PWD/qsgadaptationlayer_p.h \
$$PWD/qsgcontext_p.h \
$$PWD/qsgcontextplugin_p.h \
- $$PWD/qsgdefaultglyphnode_p.h \
- $$PWD/qsgdefaultdistancefieldglyphcache_p.h \
- $$PWD/qsgdistancefieldglyphnode_p.h \
- $$PWD/qsgdistancefieldglyphnode_p_p.h \
- $$PWD/qsgdefaultglyphnode_p_p.h \
- $$PWD/qsgdefaultimagenode_p.h \
- $$PWD/qsgdefaultrectanglenode_p.h \
- $$PWD/qsgrenderloop_p.h \
- $$PWD/qsgthreadedrenderloop_p.h \
- $$PWD/qsgwindowsrenderloop_p.h \
- $$PWD/qsgdefaultlayer_p.h
+ $$PWD/qsgbasicrectanglenode_p.h \
+ $$PWD/qsgbasicimagenode_p.h \
+ $$PWD/qsgbasicglyphnode_p.h \
+ $$PWD/qsgrenderloop_p.h
SOURCES += \
$$PWD/qsgadaptationlayer.cpp \
$$PWD/qsgcontext.cpp \
$$PWD/qsgcontextplugin.cpp \
- $$PWD/qsgdefaultglyphnode.cpp \
- $$PWD/qsgdefaultglyphnode_p.cpp \
- $$PWD/qsgdefaultdistancefieldglyphcache.cpp \
- $$PWD/qsgdistancefieldglyphnode.cpp \
- $$PWD/qsgdistancefieldglyphnode_p.cpp \
- $$PWD/qsgdefaultimagenode.cpp \
- $$PWD/qsgdefaultrectanglenode.cpp \
- $$PWD/qsgrenderloop.cpp \
- $$PWD/qsgthreadedrenderloop.cpp \
- $$PWD/qsgwindowsrenderloop.cpp \
- $$PWD/qsgdefaultlayer.cpp
+ $$PWD/qsgbasicrectanglenode.cpp \
+ $$PWD/qsgbasicimagenode.cpp \
+ $$PWD/qsgbasicglyphnode.cpp \
+ $$PWD/qsgrenderloop.cpp
+
+contains(QT_CONFIG, opengl(es1|es2)?) {
+ SOURCES += \
+ $$PWD/qsgdefaultglyphnode.cpp \
+ $$PWD/qsgdefaultglyphnode_p.cpp \
+ $$PWD/qsgdefaultdistancefieldglyphcache.cpp \
+ $$PWD/qsgdistancefieldglyphnode.cpp \
+ $$PWD/qsgdistancefieldglyphnode_p.cpp \
+ $$PWD/qsgdefaultimagenode.cpp \
+ $$PWD/qsgdefaultrectanglenode.cpp \
+ $$PWD/qsgdefaultrendercontext.cpp \
+ $$PWD/qsgdefaultcontext.cpp \
+ $$PWD/util/qsgdefaultpainternode.cpp \
+ $$PWD/qsgdefaultlayer.cpp \
+ $$PWD/qsgthreadedrenderloop.cpp \
+ $$PWD/qsgwindowsrenderloop.cpp
+ HEADERS += \
+ $$PWD/qsgdefaultglyphnode_p.h \
+ $$PWD/qsgdefaultdistancefieldglyphcache_p.h \
+ $$PWD/qsgdistancefieldglyphnode_p.h \
+ $$PWD/qsgdistancefieldglyphnode_p_p.h \
+ $$PWD/qsgdefaultglyphnode_p_p.h \
+ $$PWD/qsgdefaultimagenode_p.h \
+ $$PWD/qsgdefaultrectanglenode_p.h \
+ $$PWD/qsgdefaultrendercontext_p.h \
+ $$PWD/qsgdefaultcontext_p.h \
+ $$PWD/util/qsgdefaultpainternode_p.h \
+ $$PWD/qsgdefaultlayer_p.h \
+ $$PWD/qsgthreadedrenderloop_p.h \
+ $$PWD/qsgwindowsrenderloop_p.h
+}
+
+# Built-in, non-plugin-based adaptations
+include(adaptations/adaptations.pri)
RESOURCES += \
$$PWD/scenegraph.qrc
-OTHER_FILES += \
- $$PWD/shaders/24bittextmask.frag \
- $$PWD/shaders/8bittextmask.frag \
- $$PWD/shaders/distancefieldoutlinetext.frag \
- $$PWD/shaders/distancefieldshiftedtext.frag \
- $$PWD/shaders/distancefieldshiftedtext.vert \
- $$PWD/shaders/distancefieldtext.frag \
- $$PWD/shaders/distancefieldtext.vert \
- $$PWD/shaders/flatcolor.frag \
- $$PWD/shaders/flatcolor.vert \
- $$PWD/shaders/hiqsubpixeldistancefieldtext.frag \
- $$PWD/shaders/hiqsubpixeldistancefieldtext.vert \
- $$PWD/shaders/loqsubpixeldistancefieldtext.frag \
- $$PWD/shaders/loqsubpixeldistancefieldtext.vert \
- $$PWD/shaders/opaquetexture.frag \
- $$PWD/shaders/opaquetexture.vert \
- $$PWD/shaders/outlinedtext.frag \
- $$PWD/shaders/outlinedtext.vert \
- $$PWD/shaders/rendernode.frag \
- $$PWD/shaders/rendernode.vert \
- $$PWD/shaders/smoothcolor.frag \
- $$PWD/shaders/smoothcolor.vert \
- $$PWD/shaders/smoothtexture.frag \
- $$PWD/shaders/smoothtexture.vert \
- $$PWD/shaders/stencilclip.frag \
- $$PWD/shaders/stencilclip.vert \
- $$PWD/shaders/styledtext.frag \
- $$PWD/shaders/styledtext.vert \
- $$PWD/shaders/textmask.frag \
- $$PWD/shaders/textmask.vert \
- $$PWD/shaders/texture.frag \
- $$PWD/shaders/vertexcolor.frag \
- $$PWD/shaders/vertexcolor.vert \
- $$PWD/shaders/24bittextmask_core.frag \
- $$PWD/shaders/8bittextmask_core.frag \
- $$PWD/shaders/distancefieldoutlinetext_core.frag \
- $$PWD/shaders/distancefieldshiftedtext_core.frag \
- $$PWD/shaders/distancefieldshiftedtext_core.vert \
- $$PWD/shaders/distancefieldtext_core.frag \
- $$PWD/shaders/distancefieldtext_core.vert \
- $$PWD/shaders/flatcolor_core.frag \
- $$PWD/shaders/flatcolor_core.vert \
- $$PWD/shaders/hiqsubpixeldistancefieldtext_core.frag \
- $$PWD/shaders/hiqsubpixeldistancefieldtext_core.vert \
- $$PWD/shaders/loqsubpixeldistancefieldtext_core.frag \
- $$PWD/shaders/loqsubpixeldistancefieldtext_core.vert \
- $$PWD/shaders/opaquetexture_core.frag \
- $$PWD/shaders/opaquetexture_core.vert \
- $$PWD/shaders/outlinedtext_core.frag \
- $$PWD/shaders/outlinedtext_core.vert \
- $$PWD/shaders/rendernode_core.frag \
- $$PWD/shaders/rendernode_core.vert \
- $$PWD/shaders/smoothcolor_core.frag \
- $$PWD/shaders/smoothcolor_core.vert \
- $$PWD/shaders/smoothtexture_core.frag \
- $$PWD/shaders/smoothtexture_core.vert \
- $$PWD/shaders/stencilclip_core.frag \
- $$PWD/shaders/stencilclip_core.vert \
- $$PWD/shaders/styledtext_core.frag \
- $$PWD/shaders/styledtext_core.vert \
- $$PWD/shaders/textmask_core.frag \
- $$PWD/shaders/textmask_core.vert \
- $$PWD/shaders/texture_core.frag \
- $$PWD/shaders/vertexcolor_core.frag \
- $$PWD/shaders/vertexcolor_core.vert \
- scenegraph/shaders/visualization.frag \
- scenegraph/shaders/visualization.vert
-
+# OpenGL Shaders
+contains(QT_CONFIG, opengl(es1|es2)?) {
+ OTHER_FILES += \
+ $$PWD/shaders/24bittextmask.frag \
+ $$PWD/shaders/8bittextmask.frag \
+ $$PWD/shaders/distancefieldoutlinetext.frag \
+ $$PWD/shaders/distancefieldshiftedtext.frag \
+ $$PWD/shaders/distancefieldshiftedtext.vert \
+ $$PWD/shaders/distancefieldtext.frag \
+ $$PWD/shaders/distancefieldtext.vert \
+ $$PWD/shaders/flatcolor.frag \
+ $$PWD/shaders/flatcolor.vert \
+ $$PWD/shaders/hiqsubpixeldistancefieldtext.frag \
+ $$PWD/shaders/hiqsubpixeldistancefieldtext.vert \
+ $$PWD/shaders/loqsubpixeldistancefieldtext.frag \
+ $$PWD/shaders/loqsubpixeldistancefieldtext.vert \
+ $$PWD/shaders/opaquetexture.frag \
+ $$PWD/shaders/opaquetexture.vert \
+ $$PWD/shaders/outlinedtext.frag \
+ $$PWD/shaders/outlinedtext.vert \
+ $$PWD/shaders/rendernode.frag \
+ $$PWD/shaders/rendernode.vert \
+ $$PWD/shaders/smoothcolor.frag \
+ $$PWD/shaders/smoothcolor.vert \
+ $$PWD/shaders/smoothtexture.frag \
+ $$PWD/shaders/smoothtexture.vert \
+ $$PWD/shaders/stencilclip.frag \
+ $$PWD/shaders/stencilclip.vert \
+ $$PWD/shaders/styledtext.frag \
+ $$PWD/shaders/styledtext.vert \
+ $$PWD/shaders/textmask.frag \
+ $$PWD/shaders/textmask.vert \
+ $$PWD/shaders/texture.frag \
+ $$PWD/shaders/vertexcolor.frag \
+ $$PWD/shaders/vertexcolor.vert \
+ $$PWD/shaders/24bittextmask_core.frag \
+ $$PWD/shaders/8bittextmask_core.frag \
+ $$PWD/shaders/distancefieldoutlinetext_core.frag \
+ $$PWD/shaders/distancefieldshiftedtext_core.frag \
+ $$PWD/shaders/distancefieldshiftedtext_core.vert \
+ $$PWD/shaders/distancefieldtext_core.frag \
+ $$PWD/shaders/distancefieldtext_core.vert \
+ $$PWD/shaders/flatcolor_core.frag \
+ $$PWD/shaders/flatcolor_core.vert \
+ $$PWD/shaders/hiqsubpixeldistancefieldtext_core.frag \
+ $$PWD/shaders/hiqsubpixeldistancefieldtext_core.vert \
+ $$PWD/shaders/loqsubpixeldistancefieldtext_core.frag \
+ $$PWD/shaders/loqsubpixeldistancefieldtext_core.vert \
+ $$PWD/shaders/opaquetexture_core.frag \
+ $$PWD/shaders/opaquetexture_core.vert \
+ $$PWD/shaders/outlinedtext_core.frag \
+ $$PWD/shaders/outlinedtext_core.vert \
+ $$PWD/shaders/rendernode_core.frag \
+ $$PWD/shaders/rendernode_core.vert \
+ $$PWD/shaders/smoothcolor_core.frag \
+ $$PWD/shaders/smoothcolor_core.vert \
+ $$PWD/shaders/smoothtexture_core.frag \
+ $$PWD/shaders/smoothtexture_core.vert \
+ $$PWD/shaders/stencilclip_core.frag \
+ $$PWD/shaders/stencilclip_core.vert \
+ $$PWD/shaders/styledtext_core.frag \
+ $$PWD/shaders/styledtext_core.vert \
+ $$PWD/shaders/textmask_core.frag \
+ $$PWD/shaders/textmask_core.vert \
+ $$PWD/shaders/texture_core.frag \
+ $$PWD/shaders/vertexcolor_core.frag \
+ $$PWD/shaders/vertexcolor_core.vert \
+ $$PWD/shaders/visualization.frag \
+ $$PWD/shaders/visualization.vert
+}
diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp
index a93e7bbd30..098a4a666b 100644
--- a/src/quick/scenegraph/util/qsgatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgatlastexture.cpp
@@ -44,6 +44,7 @@
#include <QtCore/QtMath>
#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFunctions>
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
#include <QtGui/QSurface>
diff --git a/src/quick/scenegraph/util/qsgatlastexture_p.h b/src/quick/scenegraph/util/qsgatlastexture_p.h
index d6c0109c98..cd24645fcf 100644
--- a/src/quick/scenegraph/util/qsgatlastexture_p.h
+++ b/src/quick/scenegraph/util/qsgatlastexture_p.h
@@ -104,17 +104,17 @@ public:
QSize size() const { return m_size; }
- GLuint internalFormat() const { return m_internalFormat; }
- GLuint externalFormat() const { return m_externalFormat; }
+ uint internalFormat() const { return m_internalFormat; }
+ uint externalFormat() const { return m_externalFormat; }
private:
QSGAreaAllocator m_allocator;
- GLuint m_texture_id;
+ unsigned int m_texture_id;
QSize m_size;
QList<Texture *> m_pending_uploads;
- GLuint m_internalFormat;
- GLuint m_externalFormat;
+ uint m_internalFormat;
+ uint m_externalFormat;
int m_atlas_transient_image_threshold;
diff --git a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
index e56f586c90..561eccdb0c 100644
--- a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
+++ b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
@@ -41,6 +41,7 @@
#include <QtQuick/private/qquickpainteditem_p.h>
+#include <QtQuick/private/qsgdefaultrendercontext_p.h>
#include <QtQuick/private/qsgcontext_p.h>
#include <private/qopenglextensions_p.h>
#include <qopenglframebufferobject.h>
@@ -96,7 +97,7 @@ QSGDefaultPainterNode::QSGDefaultPainterNode(QQuickPaintedItem *item)
, m_dirtyRenderTarget(false)
, m_dirtyTexture(false)
{
- m_context = static_cast<QQuickPaintedItemPrivate *>(QObjectPrivate::get(item))->sceneGraphRenderContext();
+ m_context = static_cast<QSGDefaultRenderContext *>(static_cast<QQuickPaintedItemPrivate *>(QObjectPrivate::get(item))->sceneGraphRenderContext());
setMaterial(&m_materialO);
setOpaqueMaterial(&m_material);
diff --git a/src/quick/scenegraph/util/qsgdefaultpainternode_p.h b/src/quick/scenegraph/util/qsgdefaultpainternode_p.h
index 3cabe01511..069ef155b1 100644
--- a/src/quick/scenegraph/util/qsgdefaultpainternode_p.h
+++ b/src/quick/scenegraph/util/qsgdefaultpainternode_p.h
@@ -63,6 +63,7 @@ QT_BEGIN_NAMESPACE
class QOpenGLFramebufferObject;
class QOpenGLPaintDevice;
+class QSGDefaultRenderContext;
class Q_QUICK_PRIVATE_EXPORT QSGPainterTexture : public QSGPlainTexture
{
@@ -127,7 +128,7 @@ private:
void updateRenderTarget();
void updateFBOSize();
- QSGRenderContext *m_context;
+ QSGDefaultRenderContext *m_context;
QQuickPaintedItem::RenderTarget m_preferredRenderTarget;
QQuickPaintedItem::RenderTarget m_actualRenderTarget;
diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp
index 5eb6a6f593..65a6bcd52c 100644
--- a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp
+++ b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp
@@ -40,7 +40,9 @@
#include "qsgdistancefieldutil_p.h"
#include <private/qsgadaptationlayer_p.h>
-#include <QtGui/private/qopenglengineshadersource_p.h>
+#ifndef QT_NO_OPENGL
+# include <QtGui/private/qopenglengineshadersource_p.h>
+#endif
#include <QtQuick/private/qsgcontext_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp
index 1ef98d222d..26a3d66077 100644
--- a/src/quick/scenegraph/util/qsgengine.cpp
+++ b/src/quick/scenegraph/util/qsgengine.cpp
@@ -44,6 +44,11 @@
#include <private/qsgrenderer_p.h>
#include <private/qsgtexture_p.h>
+#ifndef QT_NO_OPENGL
+# include <QtGui/QOpenGLContext>
+# include <private/qsgdefaultrendercontext_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
@@ -83,7 +88,7 @@ QT_BEGIN_NAMESPACE
QSGEnginePrivate::QSGEnginePrivate()
: sgContext(QSGContext::createDefaultContext())
- , sgRenderContext(new QSGRenderContext(sgContext.data()))
+ , sgRenderContext(sgContext.data()->createRenderContext())
{
}
@@ -110,17 +115,23 @@ QSGEngine::~QSGEngine()
*/
void QSGEngine::initialize(QOpenGLContext *context)
{
+#ifndef QT_NO_OPENGL
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);
+ auto openGLRenderContext = static_cast<QSGDefaultRenderContext *>(d->sgRenderContext.data());
+
+ if (openGLRenderContext != nullptr && !openGLRenderContext->isValid()) {
+ openGLRenderContext->setAttachToGLContext(false);
+ openGLRenderContext->initialize(context);
connect(context, &QOpenGLContext::aboutToBeDestroyed, this, &QSGEngine::invalidate);
}
+#else
+ Q_UNUSED(context)
+#endif
}
/*!
@@ -198,4 +209,18 @@ QSGTexture *QSGEngine::createTextureFromId(uint id, const QSize &size, CreateTex
return 0;
}
+/*!
+ Returns the current renderer interface if there is one. Otherwise null is returned.
+
+ \sa QSGRenderNode, QSGRendererInterface
+ \since 5.8
+ */
+QSGRendererInterface *QSGEngine::rendererInterface() const
+{
+ Q_D(const QSGEngine);
+ return d->sgRenderContext->isValid()
+ ? d->sgRenderContext->sceneGraphContext()->rendererInterface(d->sgRenderContext.data())
+ : nullptr;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h
index 89af71fb47..9d27fb5525 100644
--- a/src/quick/scenegraph/util/qsgengine.h
+++ b/src/quick/scenegraph/util/qsgengine.h
@@ -49,6 +49,7 @@ class QOpenGLContext;
class QSGAbstractRenderer;
class QSGEnginePrivate;
class QSGTexture;
+class QSGRendererInterface;
class Q_QUICK_EXPORT QSGEngine : public QObject
{
@@ -72,6 +73,7 @@ public:
QSGAbstractRenderer *createRenderer() const;
QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options = CreateTextureOption()) const;
QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption()) const;
+ QSGRendererInterface *rendererInterface() const;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
index 836b5759a2..5d7817163e 100644
--- a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
+++ b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
@@ -39,8 +39,9 @@
#include "qsgflatcolormaterial.h"
#include <private/qsgmaterialshader_p.h>
-
-#include <qopenglshaderprogram.h>
+#ifndef QT_NO_OPENGL
+# include <qopenglshaderprogram.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -66,14 +67,16 @@ QSGMaterialType FlatColorMaterialShader::type;
FlatColorMaterialShader::FlatColorMaterialShader()
: QSGMaterialShader(*new QSGMaterialShaderPrivate)
{
+#ifndef QT_NO_OPENGL
setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/flatcolor.vert"));
setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/flatcolor.frag"));
+#endif
}
void FlatColorMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
{
+#ifndef QT_NO_OPENGL
Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
-
QSGFlatColorMaterial *oldMaterial = static_cast<QSGFlatColorMaterial *>(oldEffect);
QSGFlatColorMaterial *newMaterial = static_cast<QSGFlatColorMaterial *>(newEffect);
@@ -90,6 +93,11 @@ void FlatColorMaterialShader::updateState(const RenderState &state, QSGMaterial
if (state.isMatrixDirty())
program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+#else
+ Q_UNUSED(state)
+ Q_UNUSED(newEffect)
+ Q_UNUSED(oldEffect)
+#endif
}
char const *const *FlatColorMaterialShader::attributeNames() const
@@ -100,8 +108,10 @@ char const *const *FlatColorMaterialShader::attributeNames() const
void FlatColorMaterialShader::initialize()
{
+#ifndef QT_NO_OPENGL
m_matrix_id = program()->uniformLocation("matrix");
m_color_id = program()->uniformLocation("color");
+#endif
}
@@ -115,6 +125,9 @@ void FlatColorMaterialShader::initialize()
\inmodule QtQuick
\ingroup qtquick-scenegraph-materials
+ \warning This utility class is only functional when running with the OpenGL
+ backend of the Qt Quick scenegraph.
+
The flat color material will fill every pixel in a geometry using
a solid color. The color can contain transparency.
diff --git a/src/quick/scenegraph/util/qsgsimplematerial.cpp b/src/quick/scenegraph/util/qsgsimplematerial.cpp
index 923179071b..7214a255df 100644
--- a/src/quick/scenegraph/util/qsgsimplematerial.cpp
+++ b/src/quick/scenegraph/util/qsgsimplematerial.cpp
@@ -41,11 +41,14 @@
\class QSGSimpleMaterialShader
\brief The QSGSimpleMaterialShader class provides a convenient way of
- building custom materials for the scene graph.
+ building custom OpenGL-based materials for the scene graph.
\inmodule QtQuick
\ingroup qtquick-scenegraph-materials
+ \warning This utility class is only functional when running with the OpenGL
+ backend of the Qt Quick scenegraph.
+
Where the QSGMaterial and QSGMaterialShader API requires a bit of
boilerplate code to create a functioning material, the
QSGSimpleMaterialShader tries to hide some of this through the use
diff --git a/src/quick/scenegraph/util/qsgsimplematerial.h b/src/quick/scenegraph/util/qsgsimplematerial.h
index 9ebfc1f8d2..d07a68e850 100644
--- a/src/quick/scenegraph/util/qsgsimplematerial.h
+++ b/src/quick/scenegraph/util/qsgsimplematerial.h
@@ -50,7 +50,7 @@ class QSGSimpleMaterialShader : public QSGMaterialShader
public:
void initialize() {
QSGMaterialShader::initialize();
-
+#ifndef QT_NO_OPENGL
m_id_matrix = program()->uniformLocation(uniformMatrixName());
if (m_id_matrix < 0) {
qFatal("QSGSimpleMaterialShader does not implement 'uniform highp mat4 %s;' in its vertex shader",
@@ -67,7 +67,7 @@ public:
} else {
m_id_opacity = -1;
}
-
+#endif
resolveUniforms();
}
@@ -197,11 +197,14 @@ QSGMaterialType QSGSimpleMaterial<State>::m_type;
template <typename State>
Q_INLINE_TEMPLATE void QSGSimpleMaterialShader<State>::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
{
+#ifndef QT_NO_OPENGL
if (state.isMatrixDirty())
program()->setUniformValue(m_id_matrix, state.combinedMatrix());
if (state.isOpacityDirty() && m_id_opacity >= 0)
program()->setUniformValue(m_id_opacity, state.opacity());
-
+#else
+ Q_UNUSED(state)
+#endif
State *ns = static_cast<QSGSimpleMaterial<State> *>(newMaterial)->state();
State *old = 0;
if (oldMaterial)
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index 9b9c77dce4..19403deb73 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -38,7 +38,6 @@
****************************************************************************/
#include "qsgtexture_p.h"
-#include <qopenglfunctions.h>
#include <QtQuick/private/qsgcontext_p.h>
#include <qthread.h>
#include <qmath.h>
@@ -46,9 +45,12 @@
#include <private/qqmlglobal_p.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qpa/qplatformnativeinterface.h>
-#include <QtGui/qopenglcontext.h>
-#include <QtGui/qopenglfunctions.h>
-
+#ifndef QT_NO_OPENGL
+# include <qopenglfunctions.h>
+# include <QtGui/qopenglcontext.h>
+# include <QtGui/qopenglfunctions.h>
+# include <private/qsgdefaultrendercontext_p.h>
+#endif
#include <private/qsgmaterialshader_p.h>
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && !defined(__UCLIBC__)
@@ -278,6 +280,7 @@ Q_GLOBAL_STATIC(QMutex, qsg_valid_texture_mutex)
bool qsg_safeguard_texture(QSGTexture *texture)
{
+#ifndef QT_NO_OPENGL
QMutexLocker locker(qsg_valid_texture_mutex());
if (!qsg_valid_texture_set()->contains(texture)) {
qWarning() << "Invalid texture accessed:" << (void *) texture;
@@ -285,6 +288,9 @@ bool qsg_safeguard_texture(QSGTexture *texture)
QOpenGLContext::currentContext()->functions()->glBindTexture(GL_TEXTURE_2D, 0);
return false;
}
+#else
+ Q_UNUSED(texture)
+#endif
return true;
}
#endif
@@ -517,6 +523,7 @@ QSGTexture::WrapMode QSGTexture::verticalWrapMode() const
*/
void QSGTexture::updateBindOptions(bool force)
{
+#ifndef QT_NO_OPENGL
Q_D(QSGTexture);
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
force |= isAtlasTexture();
@@ -551,6 +558,9 @@ void QSGTexture::updateBindOptions(bool force)
funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, d->verticalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
d->wrapChanged = false;
}
+#else
+ Q_UNUSED(force)
+#endif
}
QSGPlainTexture::QSGPlainTexture()
@@ -568,8 +578,10 @@ QSGPlainTexture::QSGPlainTexture()
QSGPlainTexture::~QSGPlainTexture()
{
+#ifndef QT_NO_OPENGL
if (m_texture_id && m_owns_texture && QOpenGLContext::currentContext())
QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id);
+#endif
}
void qsg_swizzleBGRAToRGBA(QImage *image)
@@ -601,8 +613,10 @@ int QSGPlainTexture::textureId() const
// or ~QSGPlainTexture so just keep it minimal here.
return 0;
} else if (m_texture_id == 0){
+#ifndef QT_NO_OPENGL
// Generate a texture id for use later and return it.
QOpenGLContext::currentContext()->functions()->glGenTextures(1, &const_cast<QSGPlainTexture *>(this)->m_texture_id);
+#endif
return m_texture_id;
}
}
@@ -611,8 +625,10 @@ int QSGPlainTexture::textureId() const
void QSGPlainTexture::setTextureId(int id)
{
+#ifndef QT_NO_OPENGL
if (m_texture_id && m_owns_texture)
QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id);
+#endif
m_texture_id = id;
m_dirty_texture = false;
@@ -623,6 +639,7 @@ void QSGPlainTexture::setTextureId(int id)
void QSGPlainTexture::bind()
{
+#ifndef QT_NO_OPENGL
QOpenGLContext *context = QOpenGLContext::currentContext();
QOpenGLFunctions *funcs = context->functions();
if (!m_dirty_texture) {
@@ -684,7 +701,7 @@ void QSGPlainTexture::bind()
// based on QSGTexture::textureSize which is updated after this, so that
// should be ok.
int max;
- if (QSGRenderContext *rc = QSGRenderContext::from(context))
+ if (auto rc = QSGDefaultRenderContext::from(context))
max = rc->maxTextureSize();
else
funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
@@ -789,6 +806,7 @@ void QSGPlainTexture::bind()
m_dirty_bind_options = false;
if (!m_retain_image)
m_image = QImage();
+#endif
}
diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgtexture_p.h
index 5c358aecc3..a0d7eb41e3 100644
--- a/src/quick/scenegraph/util/qsgtexture_p.h
+++ b/src/quick/scenegraph/util/qsgtexture_p.h
@@ -53,9 +53,9 @@
#include <QtQuick/qtquickglobal.h>
#include <private/qobject_p.h>
-
-#include <QtGui/qopengl.h>
-
+#ifndef QT_NO_OPENGL
+# include <QtGui/qopengl.h>
+#endif
#include "qsgtexture.h"
#include <QtQuick/private/qsgcontext_p.h>
@@ -110,7 +110,7 @@ public:
protected:
QImage m_image;
- GLuint m_texture_id;
+ uint m_texture_id;
QSize m_texture_size;
QRectF m_texture_rect;
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp
index 66e87a77a8..3db8163376 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.cpp
+++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp
@@ -39,9 +39,10 @@
#include "qsgtexturematerial_p.h"
#include "qsgtexture_p.h"
-
-#include <QtGui/qopenglshaderprogram.h>
-#include <QtGui/qopenglfunctions.h>
+#ifndef QT_NO_OPENGL
+# include <QtGui/qopenglshaderprogram.h>
+# include <QtGui/qopenglfunctions.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -56,8 +57,10 @@ QSGMaterialType QSGOpaqueTextureMaterialShader::type;
QSGOpaqueTextureMaterialShader::QSGOpaqueTextureMaterialShader()
: QSGMaterialShader()
{
+#ifndef QT_NO_OPENGL
setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/opaquetexture.vert"));
setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/opaquetexture.frag"));
+#endif
}
char const *const *QSGOpaqueTextureMaterialShader::attributeNames() const
@@ -68,7 +71,9 @@ char const *const *QSGOpaqueTextureMaterialShader::attributeNames() const
void QSGOpaqueTextureMaterialShader::initialize()
{
+#ifndef QT_NO_OPENGL
m_matrix_id = program()->uniformLocation("qt_Matrix");
+#endif
}
void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
@@ -88,6 +93,7 @@ void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMa
t->setHorizontalWrapMode(tx->horizontalWrapMode());
t->setVerticalWrapMode(tx->verticalWrapMode());
+#ifndef QT_NO_OPENGL
bool npotSupported = const_cast<QOpenGLContext *>(state.context())
->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat);
if (!npotSupported) {
@@ -98,16 +104,19 @@ void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMa
t->setVerticalWrapMode(QSGTexture::ClampToEdge);
}
}
-
+#else
+ Q_UNUSED(state)
+#endif
t->setMipmapFiltering(tx->mipmapFiltering());
if (oldTx == 0 || oldTx->texture()->textureId() != t->textureId())
t->bind();
else
t->updateBindOptions();
-
+#ifndef QT_NO_OPENGL
if (state.isMatrixDirty())
program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+#endif
}
@@ -118,6 +127,9 @@ void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMa
\inmodule QtQuick
\ingroup qtquick-scenegraph-materials
+ \warning This utility class is only functional when running with the OpenGL
+ backend of the Qt Quick scenegraph.
+
The opaque textured material will fill every pixel in a geometry with
the supplied texture. The material does not respect the opacity of the
QSGMaterialShader::RenderState, so opacity nodes in the parent chain
@@ -312,6 +324,9 @@ int QSGOpaqueTextureMaterial::compare(const QSGMaterial *o) const
\inmodule QtQuick
\ingroup qtquick-scenegraph-materials
+ \warning This utility class is only functional when running with the OpenGL
+ backend of the Qt Quick scenegraph.
+
The textured material will fill every pixel in a geometry with
the supplied texture.
@@ -362,22 +377,27 @@ QSGMaterialShader *QSGTextureMaterial::createShader() const
QSGTextureMaterialShader::QSGTextureMaterialShader()
: QSGOpaqueTextureMaterialShader()
{
+#ifndef QT_NO_OPENGL
setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/texture.frag"));
+#endif
}
void QSGTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
{
Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+#ifndef QT_NO_OPENGL
if (state.isOpacityDirty())
program()->setUniformValue(m_opacity_id, state.opacity());
-
+#endif
QSGOpaqueTextureMaterialShader::updateState(state, newEffect, oldEffect);
}
void QSGTextureMaterialShader::initialize()
{
QSGOpaqueTextureMaterialShader::initialize();
+#ifndef QT_NO_OPENGL
m_opacity_id = program()->uniformLocation("opacity");
+#endif
}
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
index 8e86b3906f..dedbc86385 100644
--- a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
+++ b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
@@ -38,9 +38,9 @@
****************************************************************************/
#include "qsgvertexcolormaterial.h"
-
-#include <qopenglshaderprogram.h>
-
+#ifndef QT_NO_OPENGL
+# include <qopenglshaderprogram.h>
+#endif
QT_BEGIN_NAMESPACE
class QSGVertexColorMaterialShader : public QSGMaterialShader
@@ -65,17 +65,23 @@ QSGMaterialType QSGVertexColorMaterialShader::type;
QSGVertexColorMaterialShader::QSGVertexColorMaterialShader()
: QSGMaterialShader()
{
+#ifndef QT_NO_OPENGL
setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/vertexcolor.vert"));
setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/vertexcolor.frag"));
+#endif
}
void QSGVertexColorMaterialShader::updateState(const RenderState &state, QSGMaterial * /*newEffect*/, QSGMaterial *)
{
+#ifndef QT_NO_OPENGL
if (state.isOpacityDirty())
program()->setUniformValue(m_opacity_id, state.opacity());
if (state.isMatrixDirty())
program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+#else
+ Q_UNUSED(state)
+#endif
}
char const *const *QSGVertexColorMaterialShader::attributeNames() const
@@ -86,8 +92,10 @@ char const *const *QSGVertexColorMaterialShader::attributeNames() const
void QSGVertexColorMaterialShader::initialize()
{
+#ifndef QT_NO_OPENGL
m_matrix_id = program()->uniformLocation("matrix");
m_opacity_id = program()->uniformLocation("opacity");
+#endif
}
@@ -99,6 +107,9 @@ void QSGVertexColorMaterialShader::initialize()
\inmodule QtQuick
\ingroup qtquick-scenegraph-materials
+ \warning This utility class is only functional when running with the OpenGL
+ backend of the Qt Quick scenegraph.
+
The vertex color material will give each vertex in a geometry a color. Pixels between
vertices will be linearly interpolated. The colors can contain transparency.