diff --git a/playground/parrots/CMakeLists.txt b/playground/parrots/CMakeLists.txt index 61230a6e..702fb82b 100644 --- a/playground/parrots/CMakeLists.txt +++ b/playground/parrots/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES Overlay.h Overlay.cpp + TextureFilterMaterial.h TextureFilterMaterial.cpp TextureFilterNode.h TextureFilterNode.cpp main.cpp) diff --git a/playground/parrots/Overlay.cpp b/playground/parrots/Overlay.cpp index aaffe6a6..b9b6a760 100644 --- a/playground/parrots/Overlay.cpp +++ b/playground/parrots/Overlay.cpp @@ -5,6 +5,7 @@ #include "Overlay.h" #include "TextureFilterNode.h" +#include "TextureFilterMaterial.h" #include #include @@ -18,6 +19,38 @@ namespace { + class Material : public TextureFilterMaterial + { + public: + using TextureFilterMaterial::TextureFilterMaterial; + + QSGMaterialType* type() const override + { + static QSGMaterialType staticType; + return &staticType; + } + }; + + class FilterNode : public TextureFilterNode + { + public: + FilterNode( QSGTexture* texture ) + { + QString shaders[] = { ":/shaders/blur.vert", ":/shaders/blur.frag" }; + +#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) + shaders[0] += ".qsb"; + shaders[1] += ".qsb"; +#endif + + setFlag( QSGNode::OwnsMaterial, true ); + setTextureMaterial( new Material( shaders[0], shaders[1] ) ); + + setOwnsTexture( true ); + setTexture( texture ); + } + }; + class Skinlet : public QskSkinlet { using Inherited = QskSkinlet; @@ -107,7 +140,7 @@ namespace if ( rootNode == nullptr ) return nullptr; - auto textureNode = static_cast< TextureFilterNode* >( node ); + auto textureNode = static_cast< FilterNode* >( node ); if ( textureNode == nullptr ) { @@ -115,8 +148,7 @@ namespace QObject::connect( texture, &QskSceneTexture::updateRequested, overlay, &QQuickItem::update ); - textureNode = new TextureFilterNode(); - textureNode->setTexture( texture ); + textureNode = new FilterNode( texture ); } { diff --git a/playground/parrots/TextureFilterMaterial.cpp b/playground/parrots/TextureFilterMaterial.cpp new file mode 100644 index 00000000..7a5e67e7 --- /dev/null +++ b/playground/parrots/TextureFilterMaterial.cpp @@ -0,0 +1,168 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "TextureFilterMaterial.h" + +#include +#include +#include + + +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + +namespace +{ + class ShaderGL : public QSGMaterialShader + { + public: + void setSource( QOpenGLShader::ShaderType type, const QString& fileName ) + { + setShaderSourceFile( type, fileName ); + } + + char const* const* attributeNames() const override + { + static char const* const names[] = { "in_vertex", "in_coord", nullptr }; + return names; + } + + void initialize() override + { + QSGMaterialShader::initialize(); + + auto p = program(); + + m_matrixId = p->uniformLocation( "matrix" ); + m_opacityId = p->uniformLocation( "opacity" ); + } + + void updateState( const QSGMaterialShader::RenderState& state, + QSGMaterial* newMaterial, QSGMaterial* ) override + { + auto p = program(); + + if ( state.isMatrixDirty() ) + p->setUniformValue( m_matrixId, state.combinedMatrix() ); + + if ( state.isOpacityDirty() ) + p->setUniformValue( m_opacityId, state.opacity() ); + + auto material = static_cast< TextureFilterMaterial* >( newMaterial ); + if ( material->texture() ) + material->texture()->bind(); + } + + private: + int m_matrixId = -1; + int m_opacityId = -1; + }; +} + +QSGMaterialShader* TextureFilterMaterial::createShader() const +{ + Q_ASSERT( !( flags() & QSGMaterial::RhiShaderWanted ) ); + + auto shader = new ShaderGL(); + + shader->setSource( QOpenGLShader::Vertex, m_shaderSourceFiles[ 0 ] ); + shader->setSource( QOpenGLShader::Fragment, m_shaderSourceFiles[ 1 ] ); + + return shader; +} + +#else // Qt6 + +namespace +{ + class Shader : public QSGMaterialShader + { + public: + Shader() + { + setFlag( UpdatesGraphicsPipelineState, true ); + } + + void setSource( QSGMaterialShader::Stage stage, const QString& filename ) + { + setShaderFileName( stage, filename ); + } + + 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 = dynamic_cast< TextureFilterMaterial* >( newMaterial ); + if ( auto txt = mat->texture() ) + { + txt->commitTextureOperations( state.rhi(), state.resourceUpdateBatch() ); + *texture = txt; + } + } + }; +} + +QSGMaterialShader* TextureFilterMaterial::createShader( + QSGRendererInterface::RenderMode ) const +{ + auto shader = new Shader(); + + shader->setSource( Shader::VertexStage, m_shaderSourceFiles[ 0 ] ); + shader->setSource( Shader::FragmentStage, m_shaderSourceFiles[ 1 ] ); + + return shader; +} + +#endif + +TextureFilterMaterial::TextureFilterMaterial( + const QString& vertexShaderSourceFile, + const QString& fragmentShaderSourceFile ) + : m_shaderSourceFiles{ vertexShaderSourceFile, fragmentShaderSourceFile } +{ + setFlag( Blending | RequiresFullMatrix, true ); +} + +TextureFilterMaterial::~TextureFilterMaterial() +{ +} + +int TextureFilterMaterial::compare( const QSGMaterial* other ) const +{ + auto material = static_cast< const TextureFilterMaterial* >( other ); + + const auto key1 = texture()->comparisonKey(); + const auto key2 = material->texture()->comparisonKey(); + + return ( key1 == key2 ) ? 0 : ( ( key1 > key2 ) ? 1 : -1 ); +} diff --git a/playground/parrots/TextureFilterMaterial.h b/playground/parrots/TextureFilterMaterial.h new file mode 100644 index 00000000..cf58950b --- /dev/null +++ b/playground/parrots/TextureFilterMaterial.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#pragma once + +#include +#include + +class QSGTexture; + +class TextureFilterMaterial : public QSGMaterial +{ + public: + TextureFilterMaterial( const QString& vertexShaderSourceFile, + const QString& fragmentShaderSourceFile ); + + ~TextureFilterMaterial() override; + + int compare( const QSGMaterial* other ) const override; + + void setTexture( QSGTexture* texture ) { m_texture = texture; } + QSGTexture* texture() const { return m_texture; } + +#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) + QSGMaterialShader* createShader( + QSGRendererInterface::RenderMode ) const override final; +#else + QSGMaterialShader* createShader() const override final; +#endif + + private: + QSGTexture* m_texture = nullptr; + const QString m_shaderSourceFiles[ 2 ]; +}; diff --git a/playground/parrots/TextureFilterNode.cpp b/playground/parrots/TextureFilterNode.cpp index 1c4f2938..c9374797 100644 --- a/playground/parrots/TextureFilterNode.cpp +++ b/playground/parrots/TextureFilterNode.cpp @@ -4,187 +4,11 @@ *****************************************************************************/ #include "TextureFilterNode.h" +#include "TextureFilterMaterial.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; - } - -#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) - QSGMaterialShader* createShader() const override; -#else - QSGMaterialShader* createShader( - QSGRendererInterface::RenderMode ) const override; -#endif - - QSGTexture* texture = nullptr; - }; -} - -namespace -{ -#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) - class MaterialShaderGL : public QSGMaterialShader - { - public: - MaterialShaderGL() - { - setShaderSourceFile( QOpenGLShader::Vertex, ":/shaders/blur.vert" ); - setShaderSourceFile( QOpenGLShader::Fragment, ":/shaders/blur.frag" ); - } - - char const* const* attributeNames() const override - { - static char const* const names[] = { "in_vertex", "in_coord", nullptr }; - return names; - } - - void initialize() override - { - QSGMaterialShader::initialize(); - - auto p = program(); - - m_matrixId = p->uniformLocation( "matrix" ); - m_opacityId = p->uniformLocation( "opacity" ); - } - - void updateState( const QSGMaterialShader::RenderState& state, - QSGMaterial* newMaterial, QSGMaterial* ) override - { - auto p = program(); - - if ( state.isMatrixDirty() ) - p->setUniformValue( m_matrixId, state.combinedMatrix() ); - - if ( state.isOpacityDirty() ) - p->setUniformValue( m_opacityId, state.opacity() ); - - auto material = static_cast< Material* >( newMaterial ); - if ( material->texture ) - material->texture->bind(); - } - - private: - int m_matrixId = -1; - int m_opacityId = -1; - }; -#else - class MaterialShader : public QSGMaterialShader - { - public: - MaterialShader() - { - setFlag( UpdatesGraphicsPipelineState, true ); - - /* - Using our own shaders - we do not want to add a dependency - to the quickeffects module. - */ - setShaderFileName( VertexStage, ":/shaders/blur.vert.qsb" ); -#if 1 - setShaderFileName( FragmentStage, ":/shaders/blur.frag.qsb" ); -#else - setShaderFileName( FragmentStage, ":/shaders/rgbswap.frag.qsb" ); -#endif - } - - 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; - } - } - }; -#endif -} - -#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) -QSGMaterialShader* Material::createShader() const -{ - Q_ASSERT( !( flags() & QSGMaterial::RhiShaderWanted ) ); - return new MaterialShaderGL(); -} - -#else - -QSGMaterialShader* Material::createShader( - QSGRendererInterface::RenderMode ) const -{ - return new MaterialShader(); -} - -#endif - class TextureFilterNodePrivate final : public QSGGeometryNodePrivate { public: @@ -193,10 +17,10 @@ class TextureFilterNodePrivate final : public QSGGeometryNodePrivate { } - Material material; QSGGeometry geometry; - QRectF rect; + + bool ownsTexture = false; }; TextureFilterNode::TextureFilterNode() @@ -204,23 +28,48 @@ TextureFilterNode::TextureFilterNode() { Q_D( TextureFilterNode ); - setMaterial( &d->material ); setGeometry( &d->geometry ); + setFlag( QSGNode::OwnsMaterial, true ); } TextureFilterNode::~TextureFilterNode() { + setTexture( nullptr ); +} + +void TextureFilterNode::setTextureMaterial( TextureFilterMaterial* material ) +{ + QSGTexture* texture = nullptr; + if ( auto oldMaterial = textureMaterial() ) + texture = oldMaterial->texture(); + + Inherited::setMaterial( material ); + + if ( material ) + material->setTexture( texture ); +} + +TextureFilterMaterial* TextureFilterNode::textureMaterial() const +{ + return dynamic_cast< TextureFilterMaterial* >( material() ); } void TextureFilterNode::setTexture( QSGTexture* texture ) { - d_func()->material.texture = texture; - markDirty( QSGNode::DirtyMaterial ); + if ( auto mat = textureMaterial() ) + { + if ( ownsTexture() && mat->texture() != texture ) + delete mat->texture(); + + mat->setTexture( texture ); + markDirty( QSGNode::DirtyMaterial ); + } } -QSGTexture* TextureFilterNode::texture() +QSGTexture* TextureFilterNode::texture() const { - return d_func()->material.texture; + auto mat = textureMaterial(); + return mat ? mat->texture() : nullptr; } void TextureFilterNode::setRect( const QRectF& rect ) @@ -238,3 +87,13 @@ void TextureFilterNode::setRect( const QRectF& rect ) markDirty( QSGNode::DirtyGeometry ); } } + +void TextureFilterNode::setOwnsTexture( bool on ) +{ + d_func()->ownsTexture = on; +} + +bool TextureFilterNode::ownsTexture() const +{ + return d_func()->ownsTexture; +} diff --git a/playground/parrots/TextureFilterNode.h b/playground/parrots/TextureFilterNode.h index d8536248..05108286 100644 --- a/playground/parrots/TextureFilterNode.h +++ b/playground/parrots/TextureFilterNode.h @@ -7,11 +7,11 @@ #include -class QRect; -class QSGTexture; - +class TextureFilterMaterial; class TextureFilterNodePrivate; +class QSGTexture; + class TextureFilterNode : public QSGGeometryNode { using Inherited = QSGGeometryNode; @@ -21,15 +21,18 @@ class TextureFilterNode : public QSGGeometryNode ~TextureFilterNode(); void setTexture( QSGTexture* ); - QSGTexture* texture(); + QSGTexture* texture() const; -#if 0 - // deriving from QSGImageNode ??? void setOwnsTexture( bool ); bool ownsTexture() const; -#endif + void setRect( const QRectF& ); + void setTextureMaterial( TextureFilterMaterial* ); + TextureFilterMaterial* textureMaterial() const; + private: + void setMaterial( QSGMaterial* ) = delete; + Q_DECLARE_PRIVATE( TextureFilterNode ) };