using QSGLayer

This commit is contained in:
Uwe Rathmann 2023-12-07 11:24:47 +01:00
parent 0392f8ea36
commit 7f6e77d53d
13 changed files with 559 additions and 104 deletions

View File

@ -6,7 +6,10 @@ add_subdirectory(invoker)
add_subdirectory(shadows) add_subdirectory(shadows)
add_subdirectory(shapes) add_subdirectory(shapes)
add_subdirectory(charts) add_subdirectory(charts)
add_subdirectory(parrots)
if (QT_VERSION_MAJOR VERSION_GREATER 5)
add_subdirectory(parrots)
endif()
if (BUILD_INPUTCONTEXT) if (BUILD_INPUTCONTEXT)
add_subdirectory(inputpanel) add_subdirectory(inputpanel)

View File

@ -0,0 +1,223 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "BlurredOverlay.h"
#include "BlurredTextureNode.h"
#include <private/qquickitem_p.h>
#include <private/qquickwindow_p.h>
#include <private/qsgadaptationlayer_p.h>
#include <private/qquickitemchangelistener_p.h>
#include <qpointer.h>
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"

View File

@ -0,0 +1,35 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <qquickitem.h>
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 )
};

View File

@ -0,0 +1,195 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "BlurredTextureNode.h"
#include <qsgmaterialshader.h>
#include <qsgmaterial.h>
#include <qsgtexture.h>
#include <private/qsgnode_p.h>
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;
}

View File

@ -0,0 +1,30 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <qsgnode.h>
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 )
};

View File

@ -3,7 +3,11 @@
# SPDX-License-Identifier: BSD-3-Clause # 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) qt_add_resources(SOURCES images.qrc shaders.qrc)
qsk_add_example(parrots ${SOURCES}) qsk_add_example(parrots ${SOURCES})

View File

@ -20,14 +20,7 @@
#include <SkinnyShortcut.h> #include <SkinnyShortcut.h>
#include <cmath> #include <cmath>
#include <private/qquickshadereffect_p.h> #include "BlurredOverlay.h"
#include <private/qquickshadereffectsource_p.h>
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
#include <QFile>
#else
#include <QUrl>
#endif
class ButtonBox : public QskLinearBox 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: public:
ShaderEffect( QQuickItem* parent = nullptr ) Overlay( QQuickItem* parent = nullptr )
: QQuickShaderEffect( parent ) : 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: 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 void geometryChange( const QRectF& newRect, const QRectF& oldRect ) override
{ {
Inherited::geometryChange( newRect, oldRect ); 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 class BlurredBox : public QskControl
@ -117,20 +63,22 @@ class BlurredBox : public QskControl
setFlag( QQuickItem::ItemHasContents, false ); setFlag( QQuickItem::ItemHasContents, false );
setAutoLayoutChildren( true ); 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: private:
ShaderEffect* m_effect; Overlay* m_overlay;
}; };
class BackgroundItem : public QskControl class BackgroundItem : public QskControl
{ {
using Inherited = QskControl;
public: public:
BackgroundItem( QQuickItem* parent = nullptr ) BackgroundItem( QQuickItem* parent = nullptr )
: QskControl( parent ) : QskControl( parent )
@ -144,7 +92,21 @@ class BackgroundItem : public QskControl
startTimer( 20 ); startTimer( 20 );
} }
protected:
void timerEvent( QTimerEvent* ) override 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; static int counter = 0;
@ -177,7 +139,7 @@ class MainView : public QskControl
m_background = new BackgroundItem( this ); m_background = new BackgroundItem( this );
m_blurredBox = new BlurredBox( this ); m_blurredBox = new BlurredBox( this );
m_blurredBox->setSourceItem( m_background ); m_blurredBox->setGrabbedItem( m_background );
(void )new ButtonBox( m_blurredBox ); (void )new ButtonBox( m_blurredBox );
} }

View File

@ -1,24 +1,25 @@
#version 440 #version 440
layout(location = 0) in vec2 qt_TexCoord0; layout( location = 0 ) in vec2 coord;
layout(location = 0) out vec4 fragColor; 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; mat4 matrix;
float qt_Opacity; float opacity;
} ubuf; } ubuf;
void main() 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) fragColor =(
+ 0.3229 * texture(source, qt_TexCoord0 - 1.364 * delta) 0.0538 * texture( source, coord - 3.182 * delta )
+ 0.2466 * texture(source, qt_TexCoord0) + 0.3229 * texture( source, coord - 1.364 * delta )
+ 0.3229 * texture(source, qt_TexCoord0 + 1.364 * delta) + 0.2466 * texture( source, coord )
+ 0.0538 * texture(source, qt_TexCoord0 + 3.182 * delta)) * ubuf.qt_Opacity; + 0.3229 * texture( source, coord + 1.364 * delta )
+ 0.0538 * texture( source, coord + 3.182 * delta )
) * ubuf.opacity;
} }

View File

@ -1,21 +1,21 @@
#version 440 #version 440
layout(location = 0) in vec4 qt_Vertex; layout( location = 0 ) in vec4 in_vertex;
layout(location = 1) in vec2 qt_MultiTexCoord0; 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; mat4 matrix;
float qt_Opacity; float opacity;
} ubuf; } ubuf;
out gl_PerVertex { vec4 gl_Position; }; out gl_PerVertex { vec4 gl_Position; };
void main() void main()
{ {
qt_TexCoord0 = qt_MultiTexCoord0; coord = in_coord;
gl_Position = ubuf.qt_Matrix * qt_Vertex; gl_Position = ubuf.matrix * in_vertex;
} }

View File

@ -1,15 +1,17 @@
varying highp vec2 qt_TexCoord0;
uniform sampler2D source; uniform sampler2D source;
uniform lowp float qt_Opacity; uniform lowp float opacity;
varying highp vec2 coord;
void main() 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) gl_FragColor =(
+ 0.3229 * texture2D(source, qt_TexCoord0 - 1.364 * delta) 0.0538 * texture2D( source, coord - 3.182 * delta )
+ 0.2466 * texture2D(source, qt_TexCoord0) + 0.3229 * texture2D( source, coord - 1.364 * delta )
+ 0.3229 * texture2D(source, qt_TexCoord0 + 1.364 * delta) + 0.2466 * texture2D( source, coord )
+ 0.0538 * texture2D(source, qt_TexCoord0 + 3.182 * delta)) * qt_Opacity; + 0.3229 * texture2D( source, coord + 1.364 * delta )
+ 0.0538 * texture2D( source, coord + 3.182 * delta)
) * opacity;
} }

View File

@ -1,12 +1,12 @@
uniform highp mat4 qt_Matrix; uniform highp mat4 matrix;
attribute highp vec4 qt_Vertex; attribute highp vec4 in_vertex;
attribute highp vec2 qt_MultiTexCoord0; attribute highp vec2 in_coord;
varying highp vec2 qt_TexCoord0; varying highp vec2 coord;
void main() void main()
{ {
qt_TexCoord0 = qt_MultiTexCoord0; coord = in_coord;
gl_Position = qt_Matrix * qt_Vertex; gl_Position = matrix * in_vertex;
} }