aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp')
-rw-r--r--src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp365
1 files changed, 365 insertions, 0 deletions
diff --git a/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp b/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp
new file mode 100644
index 0000000000..6c2ff0b176
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp
@@ -0,0 +1,365 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+** Copyright (C) 2016 Robin Burchell <robin.burchell@viroteck.net>
+** 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 "qsgopenglvisualizer_p.h"
+#include <qmath.h>
+#include <private/qsgshadersourcebuilder_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QSGBatchRenderer
+{
+
+#define QSGNODE_TRAVERSE(NODE) for (QSGNode *child = NODE->firstChild(); child; child = child->nextSibling())
+#define SHADOWNODE_TRAVERSE(NODE) for (Node *child = NODE->firstChild(); child; child = child->sibling())
+#define QSGNODE_DIRTY_PARENT (QSGNode::DirtyNodeAdded \
+ | QSGNode::DirtyOpacity \
+ | QSGNode::DirtyMatrix \
+ | QSGNode::DirtyNodeRemoved)
+
+QMatrix4x4 qsg_matrixForRoot(Node *node);
+
+class VisualizeShader : public QOpenGLShaderProgram
+{
+public:
+ int color;
+ int matrix;
+ int rotation;
+ int pattern;
+ int projection;
+};
+
+OpenGLVisualizer::OpenGLVisualizer(Renderer *renderer)
+ : Visualizer(renderer),
+ m_funcs(QOpenGLContext::currentContext()->functions()),
+ m_visualizeProgram(nullptr)
+{
+}
+
+OpenGLVisualizer::~OpenGLVisualizer()
+{
+ releaseResources();
+}
+
+void OpenGLVisualizer::releaseResources()
+{
+ delete m_visualizeProgram;
+ m_visualizeProgram = nullptr;
+}
+
+void OpenGLVisualizer::prepareVisualize()
+{
+ // nothing to do here
+}
+
+void OpenGLVisualizer::visualizeDrawGeometry(const QSGGeometry *g)
+{
+ if (g->attributeCount() < 1)
+ return;
+ const QSGGeometry::Attribute *a = g->attributes();
+ m_funcs->glVertexAttribPointer(0, a->tupleSize, a->type, false, g->sizeOfVertex(), g->vertexData());
+ if (g->indexCount())
+ m_funcs->glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData());
+ else
+ m_funcs->glDrawArrays(g->drawingMode(), 0, g->vertexCount());
+
+}
+
+void OpenGLVisualizer::visualizeBatch(Batch *b)
+{
+ VisualizeShader *shader = static_cast<VisualizeShader *>(m_visualizeProgram);
+
+ if (b->positionAttribute != 0)
+ return;
+
+ QSGGeometryNode *gn = b->first->node;
+ QSGGeometry *g = gn->geometry();
+ const QSGGeometry::Attribute &a = g->attributes()[b->positionAttribute];
+
+ m_funcs->glBindBuffer(GL_ARRAY_BUFFER, b->vbo.id);
+
+ QMatrix4x4 matrix(m_renderer->m_current_projection_matrix);
+ if (b->root)
+ matrix = matrix * qsg_matrixForRoot(b->root);
+
+ shader->setUniformValue(shader->pattern, float(b->merged ? 0 : 1));
+
+ QColor color = QColor::fromHsvF((rand() & 1023) / 1023.0, 1.0, 1.0);
+ float cr = color.redF();
+ float cg = color.greenF();
+ float cb = color.blueF();
+ shader->setUniformValue(shader->color, cr, cg, cb, 1.0);
+
+ if (b->merged) {
+ shader->setUniformValue(shader->matrix, matrix);
+ const char *dataStart = m_renderer->m_context->separateIndexBuffer() ? b->ibo.data : b->vbo.data;
+ for (int ds=0; ds<b->drawSets.size(); ++ds) {
+ const DrawSet &set = b->drawSets.at(ds);
+ m_funcs->glVertexAttribPointer(a.position, 2, a.type, false, g->sizeOfVertex(),
+ (void *) (qintptr) (set.vertices));
+ m_funcs->glDrawElements(g->drawingMode(), set.indexCount, GL_UNSIGNED_SHORT,
+ (void *)(qintptr)(dataStart + set.indices));
+ }
+ } else {
+ Element *e = b->first;
+ int offset = 0;
+ while (e) {
+ gn = e->node;
+ g = gn->geometry();
+ shader->setUniformValue(shader->matrix, matrix * *gn->matrix());
+ m_funcs->glVertexAttribPointer(a.position, a.tupleSize, a.type, false, g->sizeOfVertex(),
+ (void *) (qintptr) offset);
+ if (g->indexCount())
+ m_funcs->glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData());
+ else
+ m_funcs->glDrawArrays(g->drawingMode(), 0, g->vertexCount());
+ offset += g->sizeOfVertex() * g->vertexCount();
+ e = e->nextInBatch;
+ }
+ }
+}
+
+void OpenGLVisualizer::visualizeClipping(QSGNode *node)
+{
+ if (node->type() == QSGNode::ClipNodeType) {
+ VisualizeShader *shader = static_cast<VisualizeShader *>(m_visualizeProgram);
+ QSGClipNode *clipNode = static_cast<QSGClipNode *>(node);
+ QMatrix4x4 matrix = m_renderer->m_current_projection_matrix;
+ if (clipNode->matrix())
+ matrix = matrix * *clipNode->matrix();
+ shader->setUniformValue(shader->matrix, matrix);
+ visualizeDrawGeometry(clipNode->geometry());
+ }
+
+ QSGNODE_TRAVERSE(node) {
+ visualizeClipping(child);
+ }
+}
+
+void OpenGLVisualizer::visualizeChanges(Node *n)
+{
+
+ if (n->type() == QSGNode::GeometryNodeType && n->element()->batch && m_visualizeChangeSet.contains(n)) {
+ uint dirty = m_visualizeChangeSet.value(n);
+ bool tinted = (dirty & QSGNODE_DIRTY_PARENT) != 0;
+
+ VisualizeShader *shader = static_cast<VisualizeShader *>(m_visualizeProgram);
+ QColor color = QColor::fromHsvF((rand() & 1023) / 1023.0, 0.3, 1.0);
+ float ca = 0.5;
+ float cr = color.redF() * ca;
+ float cg = color.greenF() * ca;
+ float cb = color.blueF() * ca;
+ shader->setUniformValue(shader->color, cr, cg, cb, ca);
+ shader->setUniformValue(shader->pattern, float(tinted ? 0.5 : 0));
+
+ QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(n->sgNode);
+
+ QMatrix4x4 matrix = m_renderer->m_current_projection_matrix;
+ if (n->element()->batch->root)
+ matrix = matrix * qsg_matrixForRoot(n->element()->batch->root);
+ matrix = matrix * *gn->matrix();
+ shader->setUniformValue(shader->matrix, matrix);
+ visualizeDrawGeometry(gn->geometry());
+
+ // This is because many changes don't propegate their dirty state to the
+ // parent so the node updater will not unset these states. They are
+ // not used for anything so, unsetting it should have no side effects.
+ n->dirtyState = nullptr;
+ }
+
+ SHADOWNODE_TRAVERSE(n) {
+ visualizeChanges(child);
+ }
+}
+
+void OpenGLVisualizer::visualizeOverdraw_helper(Node *node)
+{
+ if (node->type() == QSGNode::GeometryNodeType && node->element()->batch) {
+ VisualizeShader *shader = static_cast<VisualizeShader *>(m_visualizeProgram);
+ QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(node->sgNode);
+
+ QMatrix4x4 matrix = m_renderer->m_current_projection_matrix;
+ matrix(2, 2) = m_renderer->m_zRange;
+ matrix(2, 3) = 1.0f - node->element()->order * m_renderer->m_zRange;
+
+ if (node->element()->batch->root)
+ matrix = matrix * qsg_matrixForRoot(node->element()->batch->root);
+ matrix = matrix * *gn->matrix();
+ shader->setUniformValue(shader->matrix, matrix);
+
+ QColor color = node->element()->batch->isOpaque ? QColor::fromRgbF(0.3, 1.0, 0.3) : QColor::fromRgbF(1.0, 0.3, 0.3);
+ float ca = 0.33f;
+ shader->setUniformValue(shader->color, color.redF() * ca, color.greenF() * ca, color.blueF() * ca, ca);
+
+ visualizeDrawGeometry(gn->geometry());
+ }
+
+ SHADOWNODE_TRAVERSE(node) {
+ visualizeOverdraw_helper(child);
+ }
+}
+
+void OpenGLVisualizer::visualizeOverdraw()
+{
+ VisualizeShader *shader = static_cast<VisualizeShader *>(m_visualizeProgram);
+ shader->setUniformValue(shader->color, 0.5f, 0.5f, 1.0f, 1.0f);
+ shader->setUniformValue(shader->projection, 1);
+
+ m_funcs->glBlendFunc(GL_ONE, GL_ONE);
+
+ static float step = 0;
+ step += static_cast<float>(M_PI * 2 / 1000.);
+ if (step > M_PI * 2)
+ step = 0;
+ float angle = 80.0 * std::sin(step);
+
+ QMatrix4x4 xrot; xrot.rotate(20, 1, 0, 0);
+ QMatrix4x4 zrot; zrot.rotate(angle, 0, 0, 1);
+ QMatrix4x4 tx; tx.translate(0, 0, 1);
+
+ QMatrix4x4 m;
+
+// m.rotate(180, 0, 1, 0);
+
+ m.translate(0, 0.5, 4);
+ m.scale(2, 2, 1);
+
+ m.rotate(-30, 1, 0, 0);
+ m.rotate(angle, 0, 1, 0);
+ m.translate(0, 0, -1);
+
+ shader->setUniformValue(shader->rotation, m);
+
+ float box[] = {
+ // lower
+ -1, 1, 0, 1, 1, 0,
+ -1, 1, 0, -1, -1, 0,
+ 1, 1, 0, 1, -1, 0,
+ -1, -1, 0, 1, -1, 0,
+
+ // upper
+ -1, 1, 1, 1, 1, 1,
+ -1, 1, 1, -1, -1, 1,
+ 1, 1, 1, 1, -1, 1,
+ -1, -1, 1, 1, -1, 1,
+
+ // sides
+ -1, -1, 0, -1, -1, 1,
+ 1, -1, 0, 1, -1, 1,
+ -1, 1, 0, -1, 1, 1,
+ 1, 1, 0, 1, 1, 1
+ };
+ m_funcs->glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, box);
+ m_funcs->glLineWidth(2);
+ m_funcs->glDrawArrays(GL_LINES, 0, 24);
+
+ visualizeOverdraw_helper(m_renderer->m_nodes.value(m_renderer->rootNode()));
+}
+
+void OpenGLVisualizer::visualize()
+{
+ if (m_visualizeMode == VisualizeNothing)
+ return;
+
+ if (!m_visualizeProgram) {
+ VisualizeShader *prog = new VisualizeShader();
+ QSGShaderSourceBuilder::initializeProgramFromFiles(
+ prog,
+ QStringLiteral(":/qt-project.org/scenegraph/shaders/visualization.vert"),
+ QStringLiteral(":/qt-project.org/scenegraph/shaders/visualization.frag"));
+ prog->bindAttributeLocation("v", 0);
+ prog->link();
+ prog->bind();
+ prog->color = prog->uniformLocation("color");
+ prog->pattern = prog->uniformLocation("pattern");
+ prog->projection = prog->uniformLocation("projection");
+ prog->matrix = prog->uniformLocation("matrix");
+ prog->rotation = prog->uniformLocation("rotation");
+ m_visualizeProgram = prog;
+ } else {
+ m_visualizeProgram->bind();
+ }
+ VisualizeShader *shader = static_cast<VisualizeShader *>(m_visualizeProgram);
+
+ m_funcs->glDisable(GL_DEPTH_TEST);
+ m_funcs->glEnable(GL_BLEND);
+ m_funcs->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ m_funcs->glEnableVertexAttribArray(0);
+
+ // Blacken out the actual rendered content...
+ float bgOpacity = 0.8f;
+ if (m_visualizeMode == VisualizeBatches)
+ bgOpacity = 1.0;
+ float v[] = { -1, 1, 1, 1, -1, -1, 1, -1 };
+ shader->setUniformValue(shader->color, 0.0f, 0.0f, 0.0f, bgOpacity);
+ shader->setUniformValue(shader->matrix, QMatrix4x4());
+ shader->setUniformValue(shader->rotation, QMatrix4x4());
+ shader->setUniformValue(shader->pattern, 0.0f);
+ shader->setUniformValue(shader->projection, false);
+ m_funcs->glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, v);
+ m_funcs->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ if (m_visualizeMode == VisualizeBatches) {
+ srand(0); // To force random colors to be roughly the same every time..
+ for (int i = 0; i < m_renderer->m_opaqueBatches.size(); ++i)
+ visualizeBatch(m_renderer->m_opaqueBatches.at(i));
+ for (int i = 0; i < m_renderer->m_alphaBatches.size(); ++i)
+ visualizeBatch(m_renderer->m_alphaBatches.at(i));
+ } else if (m_visualizeMode == VisualizeClipping) {
+ shader->setUniformValue(shader->pattern, 0.5f);
+ shader->setUniformValue(shader->color, 0.2f, 0.0f, 0.0f, 0.2f);
+ visualizeClipping(m_renderer->rootNode());
+ } else if (m_visualizeMode == VisualizeChanges) {
+ visualizeChanges(m_renderer->m_nodes.value(m_renderer->rootNode()));
+ m_visualizeChangeSet.clear();
+ } else if (m_visualizeMode == VisualizeOverdraw) {
+ visualizeOverdraw();
+ }
+
+ // Reset state back to defaults..
+ m_funcs->glDisable(GL_BLEND);
+ m_funcs->glDisableVertexAttribArray(0);
+ shader->release();
+}
+
+}
+
+QT_END_NAMESPACE