diff options
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 2 | ||||
-rw-r--r-- | src/quick/items/qquickwindow_p.h | 2 | ||||
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 326 | ||||
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h | 24 | ||||
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgrenderer_p.h | 2 | ||||
-rw-r--r-- | src/quick/scenegraph/scenegraph.pri | 4 | ||||
-rw-r--r-- | src/quick/scenegraph/scenegraph.qrc | 2 | ||||
-rw-r--r-- | src/quick/scenegraph/shaders/visualization.frag | 11 | ||||
-rw-r--r-- | src/quick/scenegraph/shaders/visualization.vert | 22 |
9 files changed, 388 insertions, 7 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index a311971266..6778cf13e9 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -344,6 +344,7 @@ void QQuickWindowPrivate::syncSceneGraph() mode |= QSGRenderer::ClearColorBuffer; renderer->setClearMode(mode); + renderer->setCustomRenderMode(customRenderMode); context->endSync(); } @@ -418,6 +419,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c) contentItemPrivate->windowRefCount = 1; contentItemPrivate->flags |= QQuickItem::ItemIsFocusScope; + customRenderMode = qgetenv("QSG_VISUALIZE"); windowManager = QSGRenderLoop::instance(); QSGContext *sg = windowManager->sceneGraphContext(); context = windowManager->createRenderContext(sg); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index d5c7b5d64c..944a320dce 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -57,6 +57,7 @@ #include "qquickwindow.h" #include <QtQuick/private/qsgcontext_p.h> +#include <private/qsgbatchrenderer_p.h> #include <QtCore/qthread.h> #include <QtCore/qmutex.h> @@ -200,6 +201,7 @@ public: QSGRenderContext *context; QSGRenderer *renderer; + QByteArray customRenderMode; // Default renderer supports "clip", "overdraw", "changes", "batches" and blank. QSGRenderLoop *windowManager; QQuickAnimatorController *animationController; diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 1a9669f9ab..9fbf6d8d00 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -42,6 +42,10 @@ #include "qsgbatchrenderer_p.h" #include <private/qsgshadersourcebuilder_p.h> +#include <QQuickWindow> + +#include <qmath.h> + #include <QtCore/QElapsedTimer> #include <QtGui/QGuiApplication> @@ -305,6 +309,9 @@ void Updater::updateStates(QSGNode *n) qDebug() << " - forceupdate"; } + if (Q_UNLIKELY(renderer->m_visualizeMode == Renderer::VisualizeChanges)) + renderer->visualizeChangesPrepare(sn); + visitNode(sn); } @@ -760,6 +767,7 @@ Renderer::Renderer(QSGRenderContext *ctx) , m_currentClip(0) , m_currentClipType(NoClip) , m_vao(0) + , m_visualizeMode(VisualizeNothing) { setNodeUpdater(new Updater(this)); @@ -1668,7 +1676,7 @@ void Renderer::uploadMergedElement(Element *e, int vaOffset, char **vertexData, *indexCount += iCount; } -const QMatrix4x4 &Renderer::matrixForRoot(Node *node) +static QMatrix4x4 qsg_matrixForRoot(Node *node) { if (node->type() == QSGNode::TransformNodeType) return static_cast<QSGTransformNode *>(node->sgNode)->combinedMatrix(); @@ -2004,7 +2012,7 @@ void Renderer::renderMergedBatch(const Batch *batch) // We always have dirty matrix as all batches are at a unique z range. QSGMaterialShader::RenderState::DirtyStates dirty = QSGMaterialShader::RenderState::DirtyMatrix; if (batch->root) - m_current_model_view_matrix = matrixForRoot(batch->root); + m_current_model_view_matrix = qsg_matrixForRoot(batch->root); else m_current_model_view_matrix.setToIdentity(); m_current_determinant = m_current_model_view_matrix.determinant(); @@ -2133,7 +2141,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch) char *iOffset = indexBase + batch->vertexCount * gn->geometry()->sizeOfVertex(); #endif - QMatrix4x4 rootMatrix = batch->root ? matrixForRoot(batch->root) : QMatrix4x4(); + QMatrix4x4 rootMatrix = batch->root ? qsg_matrixForRoot(batch->root) : QMatrix4x4(); while (e) { gn = e->node; @@ -2358,7 +2366,6 @@ void Renderer::render() cleanupBatches(&m_opaqueBatches); cleanupBatches(&m_alphaBatches); - if (m_rebuild & BuildBatches) { prepareOpaqueBatches(); prepareAlphaBatches(); @@ -2408,6 +2415,9 @@ void Renderer::render() m_rebuild = 0; + if (m_visualizeMode != VisualizeNothing) + visualize(); + if (m_vao) m_vao->release(); } @@ -2446,7 +2456,7 @@ void Renderer::renderRenderNode(Batch *batch) QMatrix4x4 matrix; while (xform != rootNode()) { if (xform->type() == QSGNode::TransformNodeType) { - matrix = matrixForRoot(e->root) * static_cast<QSGTransformNode *>(xform)->combinedMatrix(); + matrix = qsg_matrixForRoot(e->root) * static_cast<QSGTransformNode *>(xform)->combinedMatrix(); break; } xform = xform->parent(); @@ -2510,6 +2520,312 @@ void Renderer::renderRenderNode(Batch *batch) } +class VisualizeShader : public QOpenGLShaderProgram +{ +public: + int color; + int matrix; + int rotation; + int tweak; +}; + +void Renderer::visualizeDrawGeometry(const QSGGeometry *g) +{ + if (g->attributeCount() < 1) + return; + const QSGGeometry::Attribute *a = g->attributes(); + glVertexAttribPointer(0, a->tupleSize, a->type, false, g->sizeOfVertex(), g->vertexData()); + if (g->indexCount()) + glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData()); + else + glDrawArrays(g->drawingMode(), 0, g->vertexCount()); + +} + +void Renderer::visualizeBatch(Batch *b) +{ + VisualizeShader *shader = static_cast<VisualizeShader *>(m_shaderManager->visualizeProgram); + + if (b->positionAttribute != 0) + return; + + QSGGeometryNode *gn = b->first->node; + QSGGeometry *g = gn->geometry(); + const QSGGeometry::Attribute &a = g->attributes()[b->positionAttribute]; + + glBindBuffer(GL_ARRAY_BUFFER, b->vbo.id); + + QMatrix4x4 matrix(m_current_projection_matrix); + if (b->root) + matrix = matrix * qsg_matrixForRoot(b->root); + + QRect viewport = viewportRect(); + shader->setUniformValue(shader->tweak, viewport.width(), viewport.height(), b->merged ? 0 : 1, 0); + + 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); + for (int ds=0; ds<b->drawSets.size(); ++ds) { + const DrawSet &set = b->drawSets.at(ds); + glVertexAttribPointer(a.position, 2, a.type, false, g->sizeOfVertex(), (void *) (qintptr) (set.vertices)); + glDrawElements(g->drawingMode(), set.indexCount, GL_UNSIGNED_SHORT, (void *) (qintptr) (b->vbo.data + 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()); + glVertexAttribPointer(a.position, a.tupleSize, a.type, false, g->sizeOfVertex(), (void *) (qintptr) offset); + glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData()); + offset += g->sizeOfVertex() * g->vertexCount(); + e = e->nextInBatch; + } + } +} + + + + +void Renderer::visualizeClipping(QSGNode *node) +{ + if (node->type() == QSGNode::ClipNodeType) { + VisualizeShader *shader = static_cast<VisualizeShader *>(m_shaderManager->visualizeProgram); + QSGClipNode *clipNode = static_cast<QSGClipNode *>(node); + QMatrix4x4 matrix = m_current_projection_matrix; + if (clipNode->matrix()) + matrix = matrix * *clipNode->matrix(); + shader->setUniformValue(shader->matrix, matrix); + visualizeDrawGeometry(clipNode->geometry()); + } + + QSGNODE_TRAVERSE(node) { + visualizeClipping(child); + } +} + +#define QSGNODE_DIRTY_PARENT (QSGNode::DirtyNodeAdded \ + | QSGNode::DirtyOpacity \ + | QSGNode::DirtyMatrix \ + | QSGNode::DirtyNodeRemoved) + +void Renderer::visualizeChangesPrepare(Node *n, uint parentChanges) +{ + uint childDirty = (parentChanges | n->dirtyState) & QSGNODE_DIRTY_PARENT; + uint selfDirty = n->dirtyState | parentChanges; + if (n->type() == QSGNode::GeometryNodeType && selfDirty != 0) + m_visualizeChanceSet.insert(n, selfDirty); + SHADOWNODE_TRAVERSE(n) { + visualizeChangesPrepare(*child, childDirty); + } +} + +void Renderer::visualizeChanges(Node *n) +{ + + if (n->type() == QSGNode::GeometryNodeType && m_visualizeChanceSet.contains(n)) { + uint dirty = m_visualizeChanceSet.value(n); + bool tinted = (dirty & QSGNODE_DIRTY_PARENT) != 0; + + VisualizeShader *shader = static_cast<VisualizeShader *>(m_shaderManager->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); + + QRect viewport = viewportRect(); + shader->setUniformValue(shader->tweak, viewport.width(), viewport.height(), tinted ? 0.5 : 0, 0); + + QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(n->sgNode); + + QMatrix4x4 matrix = 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 = 0; + } + + SHADOWNODE_TRAVERSE(n) { + visualizeChanges(*child); + } +} + +void Renderer::visualizeOverdraw_helper(Node *node) +{ + if (node->type() == QSGNode::GeometryNodeType) { + VisualizeShader *shader = static_cast<VisualizeShader *>(m_shaderManager->visualizeProgram); + QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(node->sgNode); + + QMatrix4x4 matrix = m_current_projection_matrix; + matrix(2, 2) = m_zRange; + matrix(2, 3) = 1.0f - node->element()->order * 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.33; + shader->setUniformValue(shader->color, color.redF() * ca, color.greenF() * ca, color.blueF() * ca, ca); + + visualizeDrawGeometry(gn->geometry()); + } + + SHADOWNODE_TRAVERSE(node) { + visualizeOverdraw_helper(*child); + } +} + +void Renderer::visualizeOverdraw() +{ + VisualizeShader *shader = static_cast<VisualizeShader *>(m_shaderManager->visualizeProgram); + shader->setUniformValue(shader->color, 0.5, 0.5, 1, 1); + + QRect viewport = viewportRect(); + shader->setUniformValue(shader->tweak, viewport.width(), viewport.height(), 0, 1); + + glBlendFunc(GL_ONE, GL_ONE); + + static float step = 0; + step += M_PI * 2 / 1000.; + if (step > M_PI * 2) + step = 0; + float angle = 80.0 * 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 + }; + glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, box); + glLineWidth(2); + glDrawArrays(GL_LINES, 0, 24); + + visualizeOverdraw_helper(m_nodes.value(rootNode())); + + // Animate the view... + QSurface *surface = QOpenGLContext::currentContext()->surface(); + if (surface->surfaceClass() == QSurface::Window) + if (QQuickWindow *window = qobject_cast<QQuickWindow *>(static_cast<QWindow *>(surface))) + window->update(); +} + +void Renderer::setCustomRenderMode(const QByteArray &mode) +{ + if (mode.isEmpty()) m_visualizeMode = VisualizeNothing; + else if (mode == "clip") m_visualizeMode = VisualizeClipping; + else if (mode == "overdraw") m_visualizeMode = VisualizeOverdraw; + else if (mode == "batches") m_visualizeMode = VisualizeBatches; + else if (mode == "changes") m_visualizeMode = VisualizeChanges; +} + +void Renderer::visualize() +{ + if (!m_shaderManager->visualizeProgram) { + VisualizeShader *prog = new VisualizeShader(); + QSGShaderSourceBuilder::initializeProgramFromFiles( + prog, + QStringLiteral(":/scenegraph/shaders/visualization.vert"), + QStringLiteral(":/scenegraph/shaders/visualization.frag")); + prog->bindAttributeLocation("v", 0); + prog->link(); + prog->bind(); + prog->color = prog->uniformLocation("color"); + prog->tweak = prog->uniformLocation("tweak"); + prog->matrix = prog->uniformLocation("matrix"); + prog->rotation = prog->uniformLocation("rotation"); + m_shaderManager->visualizeProgram = prog; + } else { + m_shaderManager->visualizeProgram->bind(); + } + VisualizeShader *shader = static_cast<VisualizeShader *>(m_shaderManager->visualizeProgram); + + glDisable(GL_DEPTH_TEST); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glEnableVertexAttribArray(0); + + // Blacken out the actual rendered content... + float bgOpacity = 0.8; + if (m_visualizeMode == VisualizeBatches) + bgOpacity = 1.0; + float v[] = { -1, 1, 1, 1, -1, -1, 1, -1 }; + shader->setUniformValue(shader->color, 0, 0, 0, bgOpacity); + shader->setUniformValue(shader->matrix, QMatrix4x4()); + shader->setUniformValue(shader->rotation, QMatrix4x4()); + shader->setUniformValue(shader->tweak, 0, 0, 0, 0); + glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, v); + 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_opaqueBatches.size(); ++i) visualizeBatch(m_opaqueBatches.at(i)); + for (int i=0; i<m_alphaBatches.size(); ++i) visualizeBatch(m_alphaBatches.at(i)); + } else if (m_visualizeMode == VisualizeClipping) { + QRect viewport = viewportRect(); + shader->setUniformValue(shader->tweak, viewport.width(), viewport.height(), 0.5, 0); + shader->setUniformValue(shader->color, 0.2, 0, 0, 0.2); + visualizeClipping(rootNode()); + } else if (m_visualizeMode == VisualizeChanges) { + visualizeChanges(m_nodes.value(rootNode())); + m_visualizeChanceSet.clear(); + } else if (m_visualizeMode == VisualizeOverdraw) { + visualizeOverdraw(); + } + + // Reset state back to defaults.. + glDisable(GL_BLEND); + glDisableVertexAttribArray(0); + shader->release(); +} + QT_END_NAMESPACE } diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 0aa84da185..d22ab4069e 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -368,7 +368,7 @@ public: float lastOpacity; }; - ShaderManager() : blitProgram(0) { } + ShaderManager() : blitProgram(0), visualizeProgram(0) { } ~ShaderManager() { qDeleteAll(rewrittenShaders.values()); qDeleteAll(stockShaders.values()); @@ -385,6 +385,7 @@ public: QHash<QSGMaterialType *, Shader *> stockShaders; QOpenGLShaderProgram *blitProgram; + QOpenGLShaderProgram *visualizeProgram; }; class Q_QUICK_PRIVATE_EXPORT Renderer : public QSGRenderer @@ -393,6 +394,14 @@ public: Renderer(QSGRenderContext *); ~Renderer(); + enum VisualizeMode { + VisualizeNothing, + VisualizeBatches, + VisualizeClipping, + VisualizeChanges, + VisualizeOverdraw + }; + protected: void nodeChanged(QSGNode *node, QSGNode::DirtyState state); void preprocess() Q_DECL_OVERRIDE; @@ -448,6 +457,16 @@ private: inline Batch *newBatch(); void invalidateAndRecycleBatch(Batch *b); + void visualize(); + void visualizeBatch(Batch *b); + void visualizeClipping(QSGNode *node); + void visualizeChangesPrepare(Node *n, uint parentChanges = 0); + void visualizeChanges(Node *n); + void visualizeOverdraw(); + void visualizeOverdraw_helper(Node *node); + void visualizeDrawGeometry(const QSGGeometry *g); + void setCustomRenderMode(const QByteArray &mode); + QSet<Node *> m_taggedRoots; QDataBuffer<Element *> m_opaqueRenderList; QDataBuffer<Element *> m_alphaRenderList; @@ -484,6 +503,9 @@ private: // For minimal OpenGL core profile support QOpenGLVertexArrayObject *m_vao; + + QHash<Node *, uint> m_visualizeChanceSet; + VisualizeMode m_visualizeMode; }; Batch *Renderer::newBatch() diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h index 43811e6d5e..296d6e2cfd 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h @@ -132,6 +132,8 @@ public: void setClearMode(ClearMode mode) { m_clear_mode = mode; } ClearMode clearMode() const { return m_clear_mode; } + virtual void setCustomRenderMode(const QByteArray &) { }; + Q_SIGNALS: void sceneGraphChanged(); // Add, remove, ChangeFlags changes... diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri index 6868e10b90..570d6b92b5 100644 --- a/src/quick/scenegraph/scenegraph.pri +++ b/src/quick/scenegraph/scenegraph.pri @@ -160,5 +160,7 @@ OTHER_FILES += \ $$PWD/shaders/textmask_core.vert \ $$PWD/shaders/texture_core.frag \ $$PWD/shaders/vertexcolor_core.frag \ - $$PWD/shaders/vertexcolor_core.vert + $$PWD/shaders/vertexcolor_core.vert \ + scenegraph/shaders/visualization.frag \ + scenegraph/shaders/visualization.vert diff --git a/src/quick/scenegraph/scenegraph.qrc b/src/quick/scenegraph/scenegraph.qrc index 2be8b246d3..e6a90c9120 100644 --- a/src/quick/scenegraph/scenegraph.qrc +++ b/src/quick/scenegraph/scenegraph.qrc @@ -64,5 +64,7 @@ <file>shaders/texture_core.frag</file> <file>shaders/vertexcolor_core.frag</file> <file>shaders/vertexcolor_core.vert</file> + <file>shaders/visualization.vert</file> + <file>shaders/visualization.frag</file> </qresource> </RCC> diff --git a/src/quick/scenegraph/shaders/visualization.frag b/src/quick/scenegraph/shaders/visualization.frag new file mode 100644 index 0000000000..205b726c03 --- /dev/null +++ b/src/quick/scenegraph/shaders/visualization.frag @@ -0,0 +1,11 @@ +uniform lowp vec4 color; +uniform mediump vec4 tweak; // x,y -> width, height; z -> intensity of ; + +varying mediump vec2 pos; + +void main(void) +{ + lowp vec4 c = color; + c.xyz += pow(max(sin(pos.x + pos.y), 0.0), 2.0) * tweak.z * 0.1; + gl_FragColor = c; +} diff --git a/src/quick/scenegraph/shaders/visualization.vert b/src/quick/scenegraph/shaders/visualization.vert new file mode 100644 index 0000000000..f1892b71da --- /dev/null +++ b/src/quick/scenegraph/shaders/visualization.vert @@ -0,0 +1,22 @@ +attribute highp vec4 v; +uniform highp mat4 matrix; +uniform highp mat4 rotation; + +// w -> apply 3d rotation and projection +uniform lowp vec4 tweak; + +varying mediump vec2 pos; + +void main() +{ + vec4 p = matrix * v; + + if (tweak.w > 0.0) { + vec4 proj = rotation * p; + gl_Position = vec4(proj.x, proj.y, 0, proj.z); + } else { + gl_Position = p; + } + + pos = v.xy * 1.37; +} |