Material classes reorganized

This commit is contained in:
Uwe Rathmann 2023-12-19 18:37:34 +01:00
parent 717960f15f
commit f9674760c0
6 changed files with 293 additions and 194 deletions

View File

@ -5,6 +5,7 @@
set(SOURCES set(SOURCES
Overlay.h Overlay.cpp Overlay.h Overlay.cpp
TextureFilterMaterial.h TextureFilterMaterial.cpp
TextureFilterNode.h TextureFilterNode.cpp TextureFilterNode.h TextureFilterNode.cpp
main.cpp) main.cpp)

View File

@ -5,6 +5,7 @@
#include "Overlay.h" #include "Overlay.h"
#include "TextureFilterNode.h" #include "TextureFilterNode.h"
#include "TextureFilterMaterial.h"
#include <QskSkinlet.h> #include <QskSkinlet.h>
#include <QskQuick.h> #include <QskQuick.h>
@ -18,6 +19,38 @@
namespace 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 class Skinlet : public QskSkinlet
{ {
using Inherited = QskSkinlet; using Inherited = QskSkinlet;
@ -107,7 +140,7 @@ namespace
if ( rootNode == nullptr ) if ( rootNode == nullptr )
return nullptr; return nullptr;
auto textureNode = static_cast< TextureFilterNode* >( node ); auto textureNode = static_cast< FilterNode* >( node );
if ( textureNode == nullptr ) if ( textureNode == nullptr )
{ {
@ -115,8 +148,7 @@ namespace
QObject::connect( texture, &QskSceneTexture::updateRequested, QObject::connect( texture, &QskSceneTexture::updateRequested,
overlay, &QQuickItem::update ); overlay, &QQuickItem::update );
textureNode = new TextureFilterNode(); textureNode = new FilterNode( texture );
textureNode->setTexture( texture );
} }
{ {

View File

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

View File

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

View File

@ -4,187 +4,11 @@
*****************************************************************************/ *****************************************************************************/
#include "TextureFilterNode.h" #include "TextureFilterNode.h"
#include "TextureFilterMaterial.h"
#include <qsgmaterialshader.h>
#include <qsgmaterial.h>
#include <qsgtexture.h> #include <qsgtexture.h>
#include <private/qsgnode_p.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;
}
#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 class TextureFilterNodePrivate final : public QSGGeometryNodePrivate
{ {
public: public:
@ -193,10 +17,10 @@ class TextureFilterNodePrivate final : public QSGGeometryNodePrivate
{ {
} }
Material material;
QSGGeometry geometry; QSGGeometry geometry;
QRectF rect; QRectF rect;
bool ownsTexture = false;
}; };
TextureFilterNode::TextureFilterNode() TextureFilterNode::TextureFilterNode()
@ -204,23 +28,48 @@ TextureFilterNode::TextureFilterNode()
{ {
Q_D( TextureFilterNode ); Q_D( TextureFilterNode );
setMaterial( &d->material );
setGeometry( &d->geometry ); setGeometry( &d->geometry );
setFlag( QSGNode::OwnsMaterial, true );
} }
TextureFilterNode::~TextureFilterNode() 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 ) void TextureFilterNode::setTexture( QSGTexture* texture )
{ {
d_func()->material.texture = texture; if ( auto mat = textureMaterial() )
markDirty( QSGNode::DirtyMaterial ); {
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 ) void TextureFilterNode::setRect( const QRectF& rect )
@ -238,3 +87,13 @@ void TextureFilterNode::setRect( const QRectF& rect )
markDirty( QSGNode::DirtyGeometry ); markDirty( QSGNode::DirtyGeometry );
} }
} }
void TextureFilterNode::setOwnsTexture( bool on )
{
d_func()->ownsTexture = on;
}
bool TextureFilterNode::ownsTexture() const
{
return d_func()->ownsTexture;
}

View File

@ -7,11 +7,11 @@
#include <qsgnode.h> #include <qsgnode.h>
class QRect; class TextureFilterMaterial;
class QSGTexture;
class TextureFilterNodePrivate; class TextureFilterNodePrivate;
class QSGTexture;
class TextureFilterNode : public QSGGeometryNode class TextureFilterNode : public QSGGeometryNode
{ {
using Inherited = QSGGeometryNode; using Inherited = QSGGeometryNode;
@ -21,15 +21,18 @@ class TextureFilterNode : public QSGGeometryNode
~TextureFilterNode(); ~TextureFilterNode();
void setTexture( QSGTexture* ); void setTexture( QSGTexture* );
QSGTexture* texture(); QSGTexture* texture() const;
#if 0
// deriving from QSGImageNode ???
void setOwnsTexture( bool ); void setOwnsTexture( bool );
bool ownsTexture() const; bool ownsTexture() const;
#endif
void setRect( const QRectF& ); void setRect( const QRectF& );
void setTextureMaterial( TextureFilterMaterial* );
TextureFilterMaterial* textureMaterial() const;
private: private:
void setMaterial( QSGMaterial* ) = delete;
Q_DECLARE_PRIVATE( TextureFilterNode ) Q_DECLARE_PRIVATE( TextureFilterNode )
}; };