diff options
Diffstat (limited to 'src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp')
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgopenglvisualizer.cpp | 365 |
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 |