From ef5a68dfa19bbdb588e9061ed788b805fc3155e1 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Fri, 25 Apr 2014 16:21:00 +0200 Subject: [PATCH] Make sure we rebuild batches properly after a Blending material change. If a node sent DirtyGeometry and DirtyMaterial in the same round and DirtyGeometry triggered its batch to be invalidated, we would take the no-batch code path which did set the rebuild state to BuildBatches. This looks ok on screen, but if the node changed from alpha to opaque, it would not be put into an opaque batch. For things like full screen rectangles, this can potentially hurt performance. To prevent doing a full rebuild on any material change on batchless items (aka all Rectangle nodes), we store the blend state of the material in the element and do a full rebuild only when blend state changes. Change-Id: Ifdf06fb72ef02ca47a135c821ddbcbe0d164ca29 Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 17 +++++++---------- src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h | 9 ++++++++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 791e06e..254f32a77 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -606,11 +606,6 @@ void Element::computeBounds() BatchCompatibility Batch::isMaterialCompatible(Element *e) const { - // If material has changed between opaque and translucent, it is not compatible - QSGMaterial *m = e->node->activeMaterial(); - if (isOpaque != ((m->flags() & QSGMaterial::Blending) == 0)) - return BatchBreaksOnBlending; - Element *n = first; // Skip to the first node other than e which has not been removed while (n && (n == e || n->removed)) @@ -621,6 +616,7 @@ BatchCompatibility Batch::isMaterialCompatible(Element *e) const if (!n) return BatchIsCompatible; + QSGMaterial *m = e->node->activeMaterial(); QSGMaterial *nm = n->node->activeMaterial(); return (nm->type() == m->type() && nm->compare(m) == 0) ? BatchIsCompatible @@ -1185,11 +1181,12 @@ void Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state) if (state & QSGNode::DirtyMaterial && node->type() == QSGNode::GeometryNodeType) { Element *e = shadowNode->element(); if (e) { - if (e->batch) { - BatchCompatibility compat = e->batch->isMaterialCompatible(e); - if (compat == BatchBreaksOnBlending) - m_rebuild |= Renderer::FullRebuild; - else if (compat == BatchBreaksOnCompare) + bool blended = hasMaterialWithBlending(static_cast(node)); + if (e->isMaterialBlended != blended) { + m_rebuild |= Renderer::FullRebuild; + e->isMaterialBlended = blended; + } else if (e->batch) { + if (e->batch->isMaterialCompatible(e) == BatchBreaksOnCompare) invalidateBatchAndOverlappingRenderOrders(e->batch); } else { m_rebuild |= Renderer::BuildBatches; diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 3972a98..96b99a2 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -67,6 +67,12 @@ class Updater; class Renderer; class ShaderManager; +inline bool hasMaterialWithBlending(QSGGeometryNode *n) +{ + return (n->opaqueMaterial() ? n->opaqueMaterial()->flags() & QSGMaterial::Blending + : n->material()->flags() & QSGMaterial::Blending); +} + struct Pt { float x, y; @@ -163,6 +169,7 @@ struct Element { , removed(false) , orphaned(false) , isRenderNode(false) + , isMaterialBlended(n ? hasMaterialWithBlending(n) : false) { } @@ -187,6 +194,7 @@ struct Element { uint removed : 1; uint orphaned : 1; uint isRenderNode : 1; + uint isMaterialBlended : 1; }; struct RenderNodeElement : public Element { @@ -233,7 +241,6 @@ struct DrawSet enum BatchCompatibility { - BatchBreaksOnBlending, BatchBreaksOnCompare, BatchIsCompatible }; -- 2.7.4