diff --git a/playground/CMakeLists.txt b/playground/CMakeLists.txt index 8bab46b2..86b15fb9 100644 --- a/playground/CMakeLists.txt +++ b/playground/CMakeLists.txt @@ -6,7 +6,10 @@ add_subdirectory(invoker) add_subdirectory(shadows) add_subdirectory(shapes) add_subdirectory(charts) -add_subdirectory(parrots) + +if (QT_VERSION_MAJOR VERSION_GREATER 5) + add_subdirectory(parrots) +endif() if (BUILD_INPUTCONTEXT) add_subdirectory(inputpanel) diff --git a/playground/parrots/BlurredOverlay.cpp b/playground/parrots/BlurredOverlay.cpp new file mode 100644 index 00000000..32aa1f45 --- /dev/null +++ b/playground/parrots/BlurredOverlay.cpp @@ -0,0 +1,223 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "BlurredOverlay.h" +#include "BlurredTextureNode.h" + +#include +#include +#include +#include + +#include + +class BlurredOverlayPrivate : public QQuickItemPrivate, public QQuickItemChangeListener +{ + public: + + void itemGeometryChanged( QQuickItem*, + QQuickGeometryChange change, const QRectF& ) + { + if ( change.sizeChange() ) + q_func()->update(); + } + + void setCovering( bool on ) + { + if ( on == covering ) + return; + + if ( grabbedItem ) + { + auto sd = QQuickItemPrivate::get( grabbedItem ); + + sd->refFromEffectItem( on ); + sd->derefFromEffectItem( covering ); + } + + covering = on; + } + + void setAttached( bool on ) + { + if ( grabbedItem ) + { + auto d = QQuickItemPrivate::get( grabbedItem ); + + if ( on ) + { + d->refFromEffectItem( covering ); + d->addItemChangeListener( this, Geometry ); + } + else + { + d->removeItemChangeListener( this, Geometry ); + d->derefFromEffectItem( covering ); + } + } + } + + QSGLayer* createTexture() + { + auto renderContext = sceneGraphRenderContext(); + + auto layer = renderContext->sceneGraphContext()->createLayer( renderContext ); + + layer->setMipmapFiltering( QSGTexture::None ); + layer->setHorizontalWrapMode( QSGTexture::ClampToEdge ); + layer->setVerticalWrapMode( QSGTexture::ClampToEdge ); + layer->setFormat( QSGLayer::RGBA8 ); + layer->setHasMipmaps( false ); + layer->setMirrorHorizontal( false ); + layer->setMirrorVertical( true ); + layer->setSamples( 0 ); + + return layer; + } + + void updateTexture( QSGLayer* layer ) + { + Q_Q( BlurredOverlay ); + + layer->setLive( live ); + layer->setItem( QQuickItemPrivate::get( grabbedItem )->itemNode() ); + + auto r = grabRect; + if ( r.isEmpty() ) + r = QRectF(0, 0, grabbedItem->width(), grabbedItem->height() ); + + layer->setRect( r ); + + QSize textureSize( qCeil( qAbs( r.width() ) ), + qCeil( qAbs( r.height() ) ) ); + + const auto pixelRatio = q->window()->effectiveDevicePixelRatio(); + textureSize *= pixelRatio; + + const QSize minTextureSize = sceneGraphContext()->minimumFBOSize(); + + while ( textureSize.width() < minTextureSize.width() ) + textureSize.rwidth() *= 2; + + while ( textureSize.height() < minTextureSize.height() ) + textureSize.rheight() *= 2; + + layer->setDevicePixelRatio( pixelRatio ); + layer->setSize( textureSize ); + layer->setRecursive( false ); + layer->setFiltering( q->smooth() ? QSGTexture::Linear : QSGTexture::Nearest ); + } + + QPointer< QQuickItem > grabbedItem; + QRectF grabRect; + + const bool live = true; + bool covering = true; + + Q_DECLARE_PUBLIC(BlurredOverlay) +}; + +BlurredOverlay::BlurredOverlay( QQuickItem* parent ) + : QQuickItem( *new BlurredOverlayPrivate(), parent ) +{ + setFlag( ItemHasContents ); +} + +BlurredOverlay::~BlurredOverlay() +{ + Q_D( BlurredOverlay ); + d->setAttached( false ); +} + +QQuickItem*BlurredOverlay::grabbedItem() const +{ + return d_func()->grabbedItem; +} + +void BlurredOverlay::setGrabbedItem( QQuickItem* item ) +{ + Q_D( BlurredOverlay ); + + if ( item == d->grabbedItem ) + return; + + d->setAttached( false ); + d->grabbedItem = item; + d->setAttached( true ); + + update(); +} + +QRectF BlurredOverlay::grabRect() const +{ + return d_func()->grabRect; +} + +void BlurredOverlay::setGrabRect( const QRectF& rect ) +{ + Q_D( BlurredOverlay ); + + QRectF r; + if ( !rect.isEmpty() ) + r = rect; + + if ( r == d->grabRect ) + return; + + if ( r.isEmpty() != d->grabRect.isEmpty() ) + d->setCovering( r.isEmpty() ); + + d->grabRect = r; + + if ( d->grabbedItem ) + update(); +} + +void BlurredOverlay::resetGrabRect() +{ + setGrabRect( QRectF() ); +} + +void BlurredOverlay::geometryChange( + const QRectF& newGeometry, const QRectF& oldGeometry ) +{ + update(); + Inherited::geometryChange( newGeometry, oldGeometry ); +} + +QSGNode* BlurredOverlay::updatePaintNode( QSGNode* oldNode, UpdatePaintNodeData* ) +{ + if ( size().isEmpty() ) + { + delete oldNode; + return nullptr; + } + + Q_D( BlurredOverlay ); + + auto node = static_cast< BlurredTextureNode* >( oldNode ); + + if ( node == nullptr ) + { + node = new BlurredTextureNode(); + + auto layer = d->createTexture(); + node->setTexture( layer ); + + connect( layer, &QSGLayer::updateRequested, + this, &QQuickItem::update ); + } + + auto layer = static_cast< QSGLayer* >( node->texture() ); + + d->updateTexture( layer ); + + layer->updateTexture(); + node->setRect( QRectF( 0, 0, width(), height() ) ); + + return node; +} + +#include "moc_BlurredOverlay.cpp" diff --git a/playground/parrots/BlurredOverlay.h b/playground/parrots/BlurredOverlay.h new file mode 100644 index 00000000..f0a9a7cd --- /dev/null +++ b/playground/parrots/BlurredOverlay.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#pragma once + +#include + +class BlurredOverlayPrivate; + +class BlurredOverlay : public QQuickItem +{ + Q_OBJECT + + using Inherited = QQuickItem; + + public: + BlurredOverlay( QQuickItem* = nullptr ); + ~BlurredOverlay() override; + + QQuickItem* grabbedItem() const; + void setGrabbedItem( QQuickItem* ); + + QRectF grabRect() const; + void setGrabRect( const QRectF& ); + void resetGrabRect(); + + protected: + void geometryChange( const QRectF&, const QRectF& ) override; + QSGNode* updatePaintNode( QSGNode*, UpdatePaintNodeData* ) override; + + private: + Q_DECLARE_PRIVATE( BlurredOverlay ) +}; diff --git a/playground/parrots/BlurredTextureNode.cpp b/playground/parrots/BlurredTextureNode.cpp new file mode 100644 index 00000000..b0d89226 --- /dev/null +++ b/playground/parrots/BlurredTextureNode.cpp @@ -0,0 +1,195 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "BlurredTextureNode.h" + +#include +#include +#include + +#include + +namespace +{ + class Material : public QSGMaterial + { + public: + Material() + { + setFlag(Blending | RequiresFullMatrix, true); + } + + ~Material() + { + delete texture; + } + + int compare( const QSGMaterial* other ) const + { + auto material = static_cast< const Material* >( other ); + + const auto key1 = texture->comparisonKey(); + const auto key2 = material->texture->comparisonKey(); + + return ( key1 == key2 ) ? 0 : ( ( key1 > key2 ) ? 1 : -1 ); + } + + QSGMaterialType* type() const override + { + static QSGMaterialType staticType; + return &staticType; + } + + QSGMaterialShader* createShader( + QSGRendererInterface::RenderMode ) const override; + + QSGTexture* texture = nullptr; + }; +} + +namespace +{ + class MaterialShader : public QSGMaterialShader + { + public: + MaterialShader() + { + setFlag( UpdatesGraphicsPipelineState, true ); + + setShaderFileName( VertexStage, ":/shaders/blur.vert.qsb" ); + setShaderFileName( FragmentStage, ":/shaders/blur.frag.qsb" ); + } + + bool updateUniformData( RenderState& state, + QSGMaterial*, QSGMaterial* ) override + { + Q_ASSERT( state.uniformData()->size() >= 68 ); + + auto data = state.uniformData()->data(); + bool changed = false; + + if ( state.isMatrixDirty() ) + { + const auto matrix = state.combinedMatrix(); + memcpy( data + 0, matrix.constData(), 64 ); + + changed = true; + } + + if ( state.isOpacityDirty() ) + { + const float opacity = state.opacity(); + memcpy( data + 64, &opacity, 4 ); + + changed = true; + } + + return changed; + } + + void updateSampledImage( RenderState& state, int binding, + QSGTexture** texture, QSGMaterial* newMaterial, QSGMaterial* ) override + { + Q_UNUSED( binding ); + Q_ASSERT( binding == 1 ); + + auto mat = static_cast< Material* >( newMaterial ); + + if ( mat->texture ) + { + mat->texture->commitTextureOperations( + state.rhi(), state.resourceUpdateBatch() ); + + *texture = mat->texture; + } + } + }; +} + +QSGMaterialShader* Material::createShader( + QSGRendererInterface::RenderMode ) const +{ + return new MaterialShader(); +} + +class BlurredTextureNodePrivate final : public QSGGeometryNodePrivate +{ + public: + BlurredTextureNodePrivate() + : geometry( QSGGeometry::defaultAttributes_TexturedPoint2D(), 4 ) + { + } + + Material material; + QSGGeometry geometry; + + QRectF rect; +}; + +BlurredTextureNode::BlurredTextureNode() + : QSGGeometryNode( *new BlurredTextureNodePrivate ) +{ + Q_D( BlurredTextureNode ); + + setMaterial( &d->material ); + setGeometry( &d->geometry ); +} + +BlurredTextureNode::~BlurredTextureNode() +{ +} + +void BlurredTextureNode::setTexture( QSGTexture* texture ) +{ + d_func()->material.texture = texture; +} + +QSGTexture* BlurredTextureNode::texture() +{ + return d_func()->material.texture; +} + +void BlurredTextureNode::setRect( const QRectF& rect ) +{ + Q_D( BlurredTextureNode ); + + if ( rect == d->rect ) + return; + + d->rect = rect; + + struct Point : QSGGeometry::Point2D + { + inline void operator=( const QPointF& pos ) + { + x = static_cast< float >( pos.x() ); + y = static_cast< float >( pos.y() ); + } + }; + + const QRectF r0( 0, 0, 1, 1 ); + + auto points = static_cast< Point* >( d->geometry.vertexData() ); + + points[0] = rect.topLeft(); + points[1] = r0.topLeft(); + + points[2] = rect.topRight(); + points[3] = r0.topRight(); + + points[4] = rect.bottomLeft(); + points[5] = r0.bottomLeft(); + + points[6] = rect.bottomRight(); + points[7] = r0.bottomRight(); + + d->geometry.markVertexDataDirty(); + markDirty( QSGNode::DirtyGeometry ); +} + +QRectF BlurredTextureNode::rect() const +{ + return d_func()->rect; +} diff --git a/playground/parrots/BlurredTextureNode.h b/playground/parrots/BlurredTextureNode.h new file mode 100644 index 00000000..85ae8058 --- /dev/null +++ b/playground/parrots/BlurredTextureNode.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#pragma once + +#include + +class QRect; +class QSGTexture; +class BlurredTextureNodePrivate; + +class BlurredTextureNode : public QSGGeometryNode +{ + using Inherited = QSGGeometryNode; + + public: + BlurredTextureNode(); + ~BlurredTextureNode(); + + void setTexture( QSGTexture* ); + QSGTexture* texture(); + + void setRect( const QRectF& ); + QRectF rect() const; + + private: + Q_DECLARE_PRIVATE( BlurredTextureNode ) +}; diff --git a/playground/parrots/CMakeLists.txt b/playground/parrots/CMakeLists.txt index 94010312..1eac97ff 100644 --- a/playground/parrots/CMakeLists.txt +++ b/playground/parrots/CMakeLists.txt @@ -3,7 +3,11 @@ # SPDX-License-Identifier: BSD-3-Clause ############################################################################ -set(SOURCES main.cpp) +set(SOURCES + BlurredOverlay.h BlurredOverlay.cpp + BlurredTextureNode.h BlurredTextureNode.cpp + main.cpp) + qt_add_resources(SOURCES images.qrc shaders.qrc) qsk_add_example(parrots ${SOURCES}) diff --git a/playground/parrots/main.cpp b/playground/parrots/main.cpp index 04404e93..8999b6b7 100644 --- a/playground/parrots/main.cpp +++ b/playground/parrots/main.cpp @@ -20,14 +20,7 @@ #include #include -#include -#include - -#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) - #include -#else - #include -#endif +#include "BlurredOverlay.h" class ButtonBox : public QskLinearBox { @@ -41,69 +34,22 @@ class ButtonBox : public QskLinearBox } }; -class ShaderEffect : public QQuickShaderEffect +class Overlay : public BlurredOverlay { - using Inherited = QQuickShaderEffect; + using Inherited = BlurredOverlay; public: - ShaderEffect( QQuickItem* parent = nullptr ) - : QQuickShaderEffect( parent ) + Overlay( QQuickItem* parent = nullptr ) + : Inherited( parent ) { -#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) - setVertexShader( loadShader( ":/shaders/blur.vert" ) ); - setFragmentShader( loadShader( ":/shaders/blur.frag" ) ); -#else - setVertexShader( QUrl( "qrc:/shaders/blur.vert.qsb" ) ); - setFragmentShader( QUrl( "qrc:/shaders/blur.frag.qsb" ) ); -#endif - - m_source = new QQuickShaderEffectSource( this ); - m_source->setLive( true ); - - setSource( m_source ); } - void setSourceItem( QQuickItem* item ) { m_source->setSourceItem( item ); } - QQuickItem* sourceItem() const { return m_source->sourceItem(); } - protected: -#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) - void geometryChanged( const QRectF& newRect, const QRectF& oldRect ) override - { - Inherited::geometryChanged( newRect, oldRect ); - updateSourceRect( newRect ); - } -#else void geometryChange( const QRectF& newRect, const QRectF& oldRect ) override { Inherited::geometryChange( newRect, oldRect ); - updateSourceRect( newRect ); + setGrabRect( grabbedItem()->mapRectFromItem( this, newRect ) ); } -#endif - - private: - void updateSourceRect( const QRectF& rect ) - { - const auto sourceRect = m_source->sourceItem()->mapRectFromItem( this, rect ); - m_source->setSourceRect( sourceRect ); - } - -#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) - QByteArray loadShader( const char* path ) const - { - QFile f( path ); - f.open( QFile::ReadOnly ); - - return f.readAll(); - } -#endif - - void setSource( QQuickShaderEffectSource* source ) - { - setProperty( "source", QVariant::fromValue( source ) ); - } - - QQuickShaderEffectSource* m_source; }; class BlurredBox : public QskControl @@ -117,20 +63,22 @@ class BlurredBox : public QskControl setFlag( QQuickItem::ItemHasContents, false ); setAutoLayoutChildren( true ); - m_effect = new ShaderEffect( this ); + m_overlay = new Overlay( this ); } - void setSourceItem( QQuickItem* item ) + void setGrabbedItem( QQuickItem* item ) { - m_effect->setSourceItem( item ); + m_overlay->setGrabbedItem( item ); } private: - ShaderEffect* m_effect; + Overlay* m_overlay; }; class BackgroundItem : public QskControl { + using Inherited = QskControl; + public: BackgroundItem( QQuickItem* parent = nullptr ) : QskControl( parent ) @@ -144,7 +92,21 @@ class BackgroundItem : public QskControl startTimer( 20 ); } + protected: void timerEvent( QTimerEvent* ) override + { + updateLabel(); + } + + void geometryChange( const QRectF& newGeometry, + const QRectF& oldGeometry ) override + { + Inherited::geometryChange( newGeometry, oldGeometry ); + updateLabel(); + } + + private: + void updateLabel() { static int counter = 0; @@ -177,7 +139,7 @@ class MainView : public QskControl m_background = new BackgroundItem( this ); m_blurredBox = new BlurredBox( this ); - m_blurredBox->setSourceItem( m_background ); + m_blurredBox->setGrabbedItem( m_background ); (void )new ButtonBox( m_blurredBox ); } diff --git a/playground/parrots/shaders/blur-vulkan.frag b/playground/parrots/shaders/blur-vulkan.frag index 5f5c6d48..5e9bad5c 100644 --- a/playground/parrots/shaders/blur-vulkan.frag +++ b/playground/parrots/shaders/blur-vulkan.frag @@ -1,24 +1,25 @@ #version 440 -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; +layout( location = 0 ) in vec2 coord; +layout( location = 0 ) out vec4 fragColor; -layout(binding = 1) uniform sampler2D source; +layout( binding = 1 ) uniform sampler2D source; -layout(std140, binding = 0) uniform buf +layout( std140, binding = 0 ) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; - + mat4 matrix; + float opacity; } ubuf; void main() { - vec2 delta = vec2(0.01, 0.01); + vec2 delta = vec2( 0.01, 0.01 ); - fragColor =(0.0538 * texture(source, qt_TexCoord0 - 3.182 * delta) - + 0.3229 * texture(source, qt_TexCoord0 - 1.364 * delta) - + 0.2466 * texture(source, qt_TexCoord0) - + 0.3229 * texture(source, qt_TexCoord0 + 1.364 * delta) - + 0.0538 * texture(source, qt_TexCoord0 + 3.182 * delta)) * ubuf.qt_Opacity; + fragColor =( + 0.0538 * texture( source, coord - 3.182 * delta ) + + 0.3229 * texture( source, coord - 1.364 * delta ) + + 0.2466 * texture( source, coord ) + + 0.3229 * texture( source, coord + 1.364 * delta ) + + 0.0538 * texture( source, coord + 3.182 * delta ) + ) * ubuf.opacity; } diff --git a/playground/parrots/shaders/blur-vulkan.vert b/playground/parrots/shaders/blur-vulkan.vert index 6ca0bd3c..2fa42cb6 100644 --- a/playground/parrots/shaders/blur-vulkan.vert +++ b/playground/parrots/shaders/blur-vulkan.vert @@ -1,21 +1,21 @@ #version 440 -layout(location = 0) in vec4 qt_Vertex; -layout(location = 1) in vec2 qt_MultiTexCoord0; +layout( location = 0 ) in vec4 in_vertex; +layout( location = 1 ) in vec2 in_coord; -layout(location = 0) out vec2 qt_TexCoord0; +layout( location = 0 ) out vec2 coord; -layout(std140, binding = 0) uniform buf +layout( std140, binding = 0 ) uniform buf { - mat4 qt_Matrix; - float qt_Opacity; + mat4 matrix; + float opacity; } ubuf; out gl_PerVertex { vec4 gl_Position; }; void main() { - qt_TexCoord0 = qt_MultiTexCoord0; - gl_Position = ubuf.qt_Matrix * qt_Vertex; + coord = in_coord; + gl_Position = ubuf.matrix * in_vertex; } diff --git a/playground/parrots/shaders/blur.frag b/playground/parrots/shaders/blur.frag index 4202dce2..8f67b47a 100644 --- a/playground/parrots/shaders/blur.frag +++ b/playground/parrots/shaders/blur.frag @@ -1,15 +1,17 @@ -varying highp vec2 qt_TexCoord0; - uniform sampler2D source; -uniform lowp float qt_Opacity; +uniform lowp float opacity; + +varying highp vec2 coord; void main() { - vec2 delta = vec2(0.01, 0.01); + vec2 delta = vec2( 0.01, 0.01 ); - gl_FragColor =(0.0538 * texture2D(source, qt_TexCoord0 - 3.182 * delta) - + 0.3229 * texture2D(source, qt_TexCoord0 - 1.364 * delta) - + 0.2466 * texture2D(source, qt_TexCoord0) - + 0.3229 * texture2D(source, qt_TexCoord0 + 1.364 * delta) - + 0.0538 * texture2D(source, qt_TexCoord0 + 3.182 * delta)) * qt_Opacity; + gl_FragColor =( + 0.0538 * texture2D( source, coord - 3.182 * delta ) + + 0.3229 * texture2D( source, coord - 1.364 * delta ) + + 0.2466 * texture2D( source, coord ) + + 0.3229 * texture2D( source, coord + 1.364 * delta ) + + 0.0538 * texture2D( source, coord + 3.182 * delta) + ) * opacity; } diff --git a/playground/parrots/shaders/blur.frag.qsb b/playground/parrots/shaders/blur.frag.qsb index 6e909cc2..140daf7c 100644 Binary files a/playground/parrots/shaders/blur.frag.qsb and b/playground/parrots/shaders/blur.frag.qsb differ diff --git a/playground/parrots/shaders/blur.vert b/playground/parrots/shaders/blur.vert index ae1e84a5..29ad5127 100644 --- a/playground/parrots/shaders/blur.vert +++ b/playground/parrots/shaders/blur.vert @@ -1,12 +1,12 @@ -uniform highp mat4 qt_Matrix; +uniform highp mat4 matrix; -attribute highp vec4 qt_Vertex; -attribute highp vec2 qt_MultiTexCoord0; +attribute highp vec4 in_vertex; +attribute highp vec2 in_coord; -varying highp vec2 qt_TexCoord0; +varying highp vec2 coord; void main() { - qt_TexCoord0 = qt_MultiTexCoord0; - gl_Position = qt_Matrix * qt_Vertex; -} \ No newline at end of file + coord = in_coord; + gl_Position = matrix * in_vertex; +} diff --git a/playground/parrots/shaders/blur.vert.qsb b/playground/parrots/shaders/blur.vert.qsb index 323177db..bcc17615 100644 Binary files a/playground/parrots/shaders/blur.vert.qsb and b/playground/parrots/shaders/blur.vert.qsb differ