diff --git a/playground/parrots/Overlay.cpp b/playground/parrots/Overlay.cpp index ff1250d0..5a7e19b3 100644 --- a/playground/parrots/Overlay.cpp +++ b/playground/parrots/Overlay.cpp @@ -7,6 +7,8 @@ #include "BlurringNode.h" #include "SceneTexture.h" +#include + #include #include #include @@ -14,29 +16,9 @@ #include -namespace -{ - class TransformNode final : public QSGTransformNode - { - public: - bool isSubtreeBlocked() const override - { - return isBlocked || QSGTransformNode::isSubtreeBlocked(); - } - - bool isBlocked = false;; - }; -} - class OverlayPrivate final : public QQuickItemPrivate, public QQuickItemChangeListener { public: - - QSGTransformNode* createTransformNode() override - { - return new TransformNode(); - } - void itemGeometryChanged( QQuickItem*, QQuickGeometryChange change, const QRectF& ) { @@ -77,6 +59,11 @@ class OverlayPrivate final : public QQuickItemPrivate, public QQuickItemChangeLi return nullptr; } + QSGTransformNode* createTransformNode() override + { + return new QskItemNode(); + } + QPointer< QQuickItem > grabbedItem; Q_DECLARE_PUBLIC(Overlay) @@ -146,19 +133,15 @@ QSGNode* Overlay::updatePaintNode( QSGNode* oldNode, UpdatePaintNodeData* ) node->setTexture( texture ); } - auto itemNode = static_cast< TransformNode* >( d->itemNode() ); + auto texture = static_cast< SceneTexture* >( node->texture() ); - if ( !itemNode->isBlocked ) + if ( !texture->isRendering() ) { - itemNode->isBlocked = true; - - auto texture = static_cast< SceneTexture* >( node->texture() ); texture->setFiltering( smooth() ? QSGTexture::Linear : QSGTexture::Nearest ); - texture->render( grabbedNode, itemNode, + texture->render( grabbedNode, d->itemNode(), QRectF( x(), y(), width(), height() ) ); - itemNode->isBlocked = false; QMetaObject::invokeMethod( this, &QQuickItem::update ); } diff --git a/playground/parrots/SceneTexture.cpp b/playground/parrots/SceneTexture.cpp index 24270639..e07a4cea 100644 --- a/playground/parrots/SceneTexture.cpp +++ b/playground/parrots/SceneTexture.cpp @@ -4,6 +4,8 @@ *****************************************************************************/ #include "SceneTexture.h" + +#include #include namespace @@ -29,7 +31,6 @@ namespace if ( node != m_finalNode ) { m_finalNode = node; - m_renderPassData.setDirty(); } } @@ -71,21 +72,47 @@ namespace void render() override { - prepareRenderPass( &m_renderPassData ); - m_renderPassData.postPrepare( rootNode(), m_finalNode ); - - beginRenderPass( &m_renderPassData ); - recordRenderPass( &m_renderPassData ); - endRenderPass( &m_renderPassData ); + setNodesBlocked( m_finalNode, true ); +#if 0 + qDebug() << "==================="; + QSGNodeDumper::dump( rootNode() ); +#endif + Inherited::render(); + setNodesBlocked( m_finalNode, false ); } private: - void nodeChanged( QSGNode* node, QSGNode::DirtyState state ) override + void setNodesBlocked( QSGNode* node, bool on ) { - if ( state & ( QSGNode::DirtyNodeAdded | QSGNode::DirtyNodeRemoved ) ) - m_renderPassData.setDirty(); + setSubtreeBlocked( node, on ); - Inherited::nodeChanged( node, state ); + for ( auto sibling = node->nextSibling(); + sibling != nullptr; sibling = sibling->nextSibling() ) + { + setSubtreeBlocked( sibling, on ); + } + + if ( node != rootNode() ) + { + if ( auto upperNode = node->parent() ) + { + upperNode = upperNode->nextSibling(); + if ( upperNode ) + setNodesBlocked( upperNode, on ); + } + } + } + + void setSubtreeBlocked( QSGNode* node, bool on ) + { + if ( qskTrySubtreeBlocked( node, on, false ) ) + return; + + for ( auto child = node->firstChild(); + child != nullptr; child = child->nextSibling() ) + { + setSubtreeBlocked( child, on ); + } } void createTarget( const QSize& size ) @@ -135,83 +162,6 @@ namespace QRhiTexture* m_rhiTexture = nullptr; QSGTransformNode* m_finalNode = nullptr; - - class RenderPassData : public RenderPassContext - { - public: - void setDirty() - { - m_nodesDirty = true; - } - - void postPrepare( const QSGNode* rootNode, const QSGNode* finalNode ) - { - using namespace QSGBatchRenderer;; - - if ( m_nodesDirty ) - { - m_blockedNodes.clear(); - - for ( auto node = finalNode; - node && node != rootNode; node = node->parent() ) - { - for ( auto sibling = node->nextSibling(); - sibling != nullptr; sibling = sibling->nextSibling() ) - { - markNodesAsBlocked( sibling ); - } - } - - m_nodesDirty = false; - } - - for ( const auto& renderBatch : opaqueRenderBatches ) - { - auto batch = const_cast< Batch* >( renderBatch.batch ); - removeBlockedNodes( batch ); - } - - for ( auto& renderBatch : alphaRenderBatches ) - { - auto batch = const_cast< Batch* >( renderBatch.batch ); - removeBlockedNodes( batch ); - } - } - - private: - void markNodesAsBlocked( const QSGNode* node ) - { - if ( node->type() == QSGNode::GeometryNodeType ) - { - auto n = static_cast< const QSGGeometryNode* >( node ); - m_blockedNodes.insert( n ); - } - - for ( auto child = node->firstChild(); - child != nullptr; child = child->nextSibling() ) - { - markNodesAsBlocked( child ); - } - } - - void removeBlockedNodes( QSGBatchRenderer::Batch* batch ) - { - QSGBatchRenderer::Element** elementRef = &batch->first; - - while( auto element = *elementRef ) - { - if ( m_blockedNodes.contains( element->node ) ) - *elementRef = element->nextInBatch; - else - elementRef = &element->nextInBatch; - } - } - - bool m_nodesDirty = true; - QSet< const QSGGeometryNode* > m_blockedNodes; - }; - - RenderPassData m_renderPassData; }; }; @@ -228,6 +178,8 @@ class SceneTexturePrivate final : public QSGTexturePrivate Renderer* renderer = nullptr; QSGDefaultRenderContext* context = nullptr; + + bool isRendering = false; }; SceneTexture::SceneTexture( QSGRenderContext* context ) @@ -289,7 +241,15 @@ void SceneTexture::render( QSGRootNode* rootNode, d->renderer->setFinalNode( finalNode ); d->renderer->setProjection( d->rect ); d->renderer->setTextureSize( pixelSize ); + + d->isRendering = true; d->renderer->renderScene(); + d->isRendering = false; +} + +bool SceneTexture::isRendering() const +{ + return d_func()->isRendering; } void SceneTexture::setDevicePixelRatio( qreal ratio ) diff --git a/playground/parrots/SceneTexture.h b/playground/parrots/SceneTexture.h index b46925b8..943c4283 100644 --- a/playground/parrots/SceneTexture.h +++ b/playground/parrots/SceneTexture.h @@ -31,6 +31,8 @@ class SceneTexture : public QSGTexture QRectF normalizedTextureSubRect() const override; + bool isRendering() const; + private: // satisfy the QSGTexture API bool hasAlphaChannel() const override { return false; } diff --git a/playground/parrots/main.cpp b/playground/parrots/main.cpp index c3c42d54..644dbcb8 100644 --- a/playground/parrots/main.cpp +++ b/playground/parrots/main.cpp @@ -30,17 +30,19 @@ class ForegroundItem : public QskLinearBox { setMargins( 20 ); +#if 1 auto label = new QskGraphicLabel( this ); const QImage image( ":/images/parrots.jpg" ); label->setGraphic( QskGraphic::fromImage( image ) ); label->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed ); label->setLayoutAlignmentHint( Qt::AlignCenter ); + label->setObjectName( "miniParrots" ); +#endif auto button = new QskPushButton( "Button", this ); button->setLayoutAlignmentHint( Qt::AlignHCenter | Qt::AlignBottom ); - label->setObjectName( "miniParrots" ); button->setObjectName( "button" ); setObjectName( "foreground" ); } @@ -141,15 +143,24 @@ class MainView : public QskControl setPolishOnResize( true ); m_background = new BackgroundItem( this ); - +#if 0 + { + auto box = new QskBox( m_background ); + box->setGeometry( 0, 0, 600, 400 ); + box->setFillGradient( Qt::darkRed ); + box->setObjectName( "redBox" ); + } +#endif m_overlay = new OverlayBox( m_background ); (void )new ForegroundItem( m_overlay ); #if 0 - auto box = new QskBox( m_background ); - box->setGeometry( 50, 50, 400, 200 ); - box->setFillGradient( Qt::darkBlue ); - box->setObjectName( "blueBox" ); + { + auto box = new QskBox( m_background ); + box->setGeometry( 50, 50, 400, 200 ); + box->setFillGradient( Qt::darkBlue ); + box->setObjectName( "blueBox" ); + } #endif setObjectName( "mainView" ); } @@ -157,17 +168,19 @@ class MainView : public QskControl protected: void updateLayout() { - m_background->setGeometry( rect() ); + if ( m_background ) + m_background->setGeometry( rect() ); QRectF blurredRect( QPointF(), 0.7 * size() ); blurredRect.moveCenter( rect().center() ); - qskSetItemGeometry( m_overlay, blurredRect ); + if ( m_overlay ) + qskSetItemGeometry( m_overlay, blurredRect ); } private: - BackgroundItem* m_background; - Overlay* m_overlay; + BackgroundItem* m_background = nullptr; + Overlay* m_overlay = nullptr; }; int main( int argc, char** argv ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 59ba35fa..76df8470 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -115,6 +115,7 @@ list(APPEND HEADERS nodes/QskGraduationNode.h nodes/QskGraduationRenderer.h nodes/QskGraphicNode.h + nodes/QskTreeNode.h nodes/QskLinesNode.h nodes/QskPaintedNode.h nodes/QskPlainTextRenderer.h @@ -123,6 +124,7 @@ list(APPEND HEADERS nodes/QskStrokeNode.h nodes/QskStippledLineRenderer.h nodes/QskShapeNode.h + nodes/QskTreeNode.h nodes/QskGradientMaterial.h nodes/QskTextNode.h nodes/QskTextRenderer.h @@ -160,6 +162,7 @@ list(APPEND SOURCES nodes/QskStrokeNode.cpp nodes/QskStippledLineRenderer.cpp nodes/QskShapeNode.cpp + nodes/QskTreeNode.cpp nodes/QskGradientMaterial.cpp nodes/QskTextNode.cpp nodes/QskTextRenderer.cpp diff --git a/src/controls/QskControl.cpp b/src/controls/QskControl.cpp index 9b3d5113..6867d6e7 100644 --- a/src/controls/QskControl.cpp +++ b/src/controls/QskControl.cpp @@ -15,6 +15,7 @@ #include "QskSkinlet.h" #include "QskSkinHintTable.h" #include "QskMargins.h" +#include "QskTreeNode.h" #include #include @@ -977,7 +978,7 @@ void QskControl::updateItemPolish() QSGNode* QskControl::updateItemPaintNode( QSGNode* node ) { if ( node == nullptr ) - node = new QSGNode; + node = new QskTreeNode(); updateNode( node ); return node; diff --git a/src/controls/QskQuickItemPrivate.cpp b/src/controls/QskQuickItemPrivate.cpp index 6f9fc3a2..52e86b6f 100644 --- a/src/controls/QskQuickItemPrivate.cpp +++ b/src/controls/QskQuickItemPrivate.cpp @@ -4,6 +4,7 @@ *****************************************************************************/ #include "QskQuickItemPrivate.h" +#include "QskTreeNode.h" #include "QskSetup.h" static inline void qskSendEventTo( QObject* object, QEvent::Type type ) @@ -240,11 +241,13 @@ void QskQuickItemPrivate::cleanupNodes() } } +QSGTransformNode* QskQuickItemPrivate::createTransformNode() +{ + return new QskItemNode(); +} + /* Can we do something useful with overloading: - - QQuickItemPrivate::createTransformNode - QQuickItemPrivate::transformChanged - - TODO ... */ diff --git a/src/controls/QskQuickItemPrivate.h b/src/controls/QskQuickItemPrivate.h index 0d7f41e6..150f4b93 100644 --- a/src/controls/QskQuickItemPrivate.h +++ b/src/controls/QskQuickItemPrivate.h @@ -23,13 +23,13 @@ class QskQuickItemPrivate : public QQuickItemPrivate public: void applyUpdateFlags( QskQuickItem::UpdateFlags ); + QSGTransformNode* createTransformNode() override; protected: virtual void layoutConstraintChanged(); virtual void implicitSizeChanged(); private: - void cleanupNodes(); void mirrorChange() override; diff --git a/src/nodes/QskTreeNode.cpp b/src/nodes/QskTreeNode.cpp new file mode 100644 index 00000000..b5c8386c --- /dev/null +++ b/src/nodes/QskTreeNode.cpp @@ -0,0 +1,131 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "QskTreeNode.h" + +static constexpr auto extraFlag = + static_cast< QSGNode::Flag >( QSGNode::IsVisitableNode << 1 ); + +static inline QSGNode* qskCheckedNode( const QSGNode* node, QSGNode::NodeType type ) +{ + return node && ( node->type() == type ) && ( node->flags() & extraFlag ) + ? const_cast< QSGNode* >( node ) : nullptr; +} + +QskTreeNode::QskTreeNode() +{ + setFlag( extraFlag, true ); +} + +QskTreeNode::QskTreeNode( QSGNodePrivate& d ) + : QSGNode( d, QSGNode::BasicNodeType ) +{ + setFlag( extraFlag, true ); +} + +QskTreeNode::~QskTreeNode() +{ +} + +void QskTreeNode::setSubtreeBlocked( bool on, bool notify ) +{ + if ( on == m_isBlocked ) + return; + + m_isBlocked = on; + + if ( notify ) + markDirty( DirtySubtreeBlocked ); +} + +bool QskTreeNode::isSubtreeBlocked() const +{ + return m_isBlocked; +} + +QskTreeNode* qskTreeNodeCast( QSGNode* node ) +{ + return static_cast< QskTreeNode* >( + qskCheckedNode( node, QSGNode::BasicNodeType ) ); +} + +const QskTreeNode* qskTreeNodeCast( const QSGNode* node ) +{ + return static_cast< QskTreeNode* >( + qskCheckedNode( node, QSGNode::BasicNodeType ) ); +} + + +// == QskItemNode + +QskItemNode::QskItemNode() +{ + setFlag( extraFlag, true ); +} + +QskItemNode::~QskItemNode() +{ +} + +void QskItemNode::setSubtreeBlocked( bool on, bool notify ) +{ + if ( on == m_isBlocked ) + return; + + m_isBlocked = on; + + if ( notify ) + markDirty( DirtySubtreeBlocked ); +} + +bool QskItemNode::isSubtreeBlocked() const +{ + return m_isBlocked; +} + +QskItemNode* qskItemNodeCast( QSGNode* node ) +{ + return static_cast< QskItemNode* >( + qskCheckedNode( node, QSGNode::TransformNodeType ) ); +} + +const QskItemNode* qskItemNodeCast( const QSGNode* node ) +{ + return static_cast< QskItemNode* >( + qskCheckedNode( node, QSGNode::TransformNodeType ) ); +} + +bool qskIsNodeBlockable( const QSGNode* node ) +{ + switch( node->type() ) + { + case QSGNode::BasicNodeType: + case QSGNode::TransformNodeType: + return node->flags() & extraFlag; + + default: + return false; + } +} + +bool qskTrySubtreeBlocked( QSGNode* node, bool on, bool notify ) +{ + if ( node && ( node->flags() & extraFlag ) ) + { + if ( node->type() == QSGNode::BasicNodeType ) + { + static_cast< QskTreeNode* >( node )->setSubtreeBlocked( on, notify ); + return true; + } + + if ( node->type() == QSGNode::TransformNodeType ) + { + static_cast< QskItemNode* >( node )->setSubtreeBlocked( on, notify ); + return true; + } + } + + return false; +} diff --git a/src/nodes/QskTreeNode.h b/src/nodes/QskTreeNode.h new file mode 100644 index 00000000..2d0cd09e --- /dev/null +++ b/src/nodes/QskTreeNode.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#ifndef QSK_TREE_NODE_H +#define QSK_TREE_NODE_H + +#include "QskGlobal.h" +#include + +/* + Used as paintNode in all QskControls ( see QskControl::updateItemPaintNode ) + */ +class QSK_EXPORT QskTreeNode final : public QSGNode +{ + public: + QskTreeNode(); + virtual ~QskTreeNode(); + + void setSubtreeBlocked( bool on, bool notify = true ); + bool isSubtreeBlocked() const override; + + protected: + QskTreeNode( QSGNodePrivate& ); + + private: + bool m_isBlocked = false;; +}; + +QSK_EXPORT QskTreeNode* qskTreeNodeCast( QSGNode* ); +QSK_EXPORT const QskTreeNode* qskTreeNodeCast( const QSGNode* ); + +/* + Used by all QskQuickItem as root node ( = itemNode ) of its subtree + ( see qskItemNode in QskQuick.h ) + */ +class QSK_EXPORT QskItemNode final : public QSGTransformNode +{ + public: + QskItemNode(); + virtual ~QskItemNode(); + + void setSubtreeBlocked( bool on, bool notify = true ); + bool isSubtreeBlocked() const override; + + private: + bool m_isBlocked = false;; +}; + +QSK_EXPORT QskItemNode* qskItemNodeCast( QSGNode* ); +QSK_EXPORT const QskItemNode* qskItemNodeCast( const QSGNode* ); + +QSK_EXPORT bool qskIsNodeBlockable( const QSGNode* ); +QSK_EXPORT bool qskTrySubtreeBlocked( QSGNode*, bool on, bool notify = true ); + +#endif