diff --git a/playground/CMakeLists.txt b/playground/CMakeLists.txt index 97c9efe1..d22f0c1c 100644 --- a/playground/CMakeLists.txt +++ b/playground/CMakeLists.txt @@ -7,10 +7,7 @@ add_subdirectory(shadows) add_subdirectory(shapes) add_subdirectory(charts) add_subdirectory(plots) - -if (QT_VERSION_MAJOR VERSION_GREATER 5) - add_subdirectory(parrots) -endif() +add_subdirectory(parrots) if (BUILD_INPUTCONTEXT) add_subdirectory(inputpanel) diff --git a/playground/parrots/Overlay.cpp b/playground/parrots/Overlay.cpp index b274037c..aaffe6a6 100644 --- a/playground/parrots/Overlay.cpp +++ b/playground/parrots/Overlay.cpp @@ -7,12 +7,12 @@ #include "TextureFilterNode.h" #include -#include #include #include #include #include #include +#include #include #include diff --git a/playground/parrots/TextureFilterNode.cpp b/playground/parrots/TextureFilterNode.cpp index c72a4eca..1c4f2938 100644 --- a/playground/parrots/TextureFilterNode.cpp +++ b/playground/parrots/TextureFilterNode.cpp @@ -42,8 +42,12 @@ namespace 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; }; @@ -51,6 +55,53 @@ namespace 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: @@ -114,14 +165,26 @@ namespace } } }; +#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: @@ -152,6 +215,7 @@ TextureFilterNode::~TextureFilterNode() void TextureFilterNode::setTexture( QSGTexture* texture ) { d_func()->material.texture = texture; + markDirty( QSGNode::DirtyMaterial ); } QSGTexture* TextureFilterNode::texture() diff --git a/playground/parrots/TextureFilterNode.h b/playground/parrots/TextureFilterNode.h index 1621b3bf..d8536248 100644 --- a/playground/parrots/TextureFilterNode.h +++ b/playground/parrots/TextureFilterNode.h @@ -23,6 +23,11 @@ class TextureFilterNode : public QSGGeometryNode void setTexture( QSGTexture* ); QSGTexture* texture(); +#if 0 + // deriving from QSGImageNode ??? + void setOwnsTexture( bool ); + bool ownsTexture() const; +#endif void setRect( const QRectF& ); private: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e017237a..313e1b93 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -120,6 +120,7 @@ list(APPEND HEADERS nodes/QskPaintedNode.h nodes/QskPlainTextRenderer.h nodes/QskRichTextRenderer.h + nodes/QskSceneTexture.h nodes/QskSGNode.h nodes/QskStrokeNode.h nodes/QskStippledLineRenderer.h @@ -157,6 +158,7 @@ list(APPEND SOURCES nodes/QskPlainTextRenderer.cpp nodes/QskRectangleNode.cpp nodes/QskRichTextRenderer.cpp + nodes/QskSceneTexture.cpp nodes/QskSGNode.cpp nodes/QskStrokeNode.cpp nodes/QskStippledLineRenderer.cpp @@ -169,11 +171,6 @@ list(APPEND SOURCES nodes/QskVertex.cpp ) -if (QT_VERSION_MAJOR VERSION_GREATER 5) - list(APPEND HEADERS nodes/QskSceneTexture.h) - list(APPEND SOURCES nodes/QskSceneTexture.cpp) -endif() - qt_add_resources(SOURCES nodes/shaders.qrc) list(APPEND HEADERS diff --git a/src/nodes/QskSceneTexture.cpp b/src/nodes/QskSceneTexture.cpp index 8660fdcb..1f3f313b 100644 --- a/src/nodes/QskSceneTexture.cpp +++ b/src/nodes/QskSceneTexture.cpp @@ -10,11 +10,21 @@ QSK_QT_PRIVATE_BEGIN #include +#include + +#define QT_BUILD_QUICK_LIB // suppress Qt5 warnings #include +#undef QT_BUILD_QUICK_LIB + QSK_QT_PRIVATE_END +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) +#include +#endif + namespace { +#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) inline QSGRendererInterface::RenderMode contextRenderMode( QSGDefaultRenderContext* context ) { @@ -22,6 +32,7 @@ namespace ? QSGRendererInterface::RenderMode2D : QSGRendererInterface::RenderMode2DNoDepthBuffer; } +#endif class Renderer final : public QSGBatchRenderer::Renderer { @@ -31,8 +42,14 @@ namespace Renderer( QskSceneTexture*, QSGDefaultRenderContext* ); ~Renderer() override; +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + inline int textureId() const { return m_fbo ? m_fbo->texture() : 0; } + inline void renderScene() { Inherited::renderScene( textureId() ); } +#else + inline QRhiTexture* texture() const { return m_rhiTexture; } +#endif + void setFinalNode( QSGTransformNode* ); - QRhiTexture* texture() const { return m_rhiTexture; } void setProjection( const QRectF& ); void setTextureSize( const QSize& ); @@ -45,15 +62,22 @@ namespace void createTarget( const QSize& ); void clearTarget(); - private: - QRhiTexture* m_rhiTexture = nullptr; QSGTransformNode* m_finalNode = nullptr; - QskSceneTexture* m_texture = nullptr; + +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + QOpenGLFramebufferObject* m_fbo; +#else + QRhiTexture* m_rhiTexture = nullptr; +#endif }; Renderer::Renderer( QskSceneTexture* texture, QSGDefaultRenderContext* context ) +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + : Inherited( context ) +#else : Inherited( context, contextRenderMode( context ) ) +#endif , m_texture( texture ) { setClearColor( Qt::transparent ); @@ -74,11 +98,17 @@ namespace void Renderer::setProjection( const QRectF& rect ) { - const auto rhi = context()->rhi(); +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + const bool flipFramebuffer = true; + const bool flipMatrix = false; +#else + const bool flipFramebuffer = rhi->isYUpInFramebuffer(); + const bool flipMatrix = rhi->isYUpInNDC(); +#endif auto r = rect; - if ( rhi->isYUpInFramebuffer() ) + if ( flipFramebuffer ) { r.moveTop( r.bottom() ); r.setHeight( -r.height() ); @@ -86,7 +116,7 @@ namespace MatrixTransformFlags matrixFlags; - if ( !rhi->isYUpInNDC() ) + if ( flipMatrix ) matrixFlags |= QSGAbstractRenderer::MatrixTransformFlipY; setProjectionMatrixToRect( r, matrixFlags ); @@ -94,11 +124,19 @@ namespace void Renderer::setTextureSize( const QSize& size ) { +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + if ( m_fbo && m_fbo->size() != size ) + clearTarget(); + + if ( m_fbo == nullptr ) + createTarget( size ); +#else if ( m_rt.rt && m_rt.rt->pixelSize() != size ) clearTarget(); if ( m_rt.rt == nullptr ) createTarget( size ); +#endif const QRect r( 0, 0, size.width(), size.height() ); @@ -131,6 +169,14 @@ namespace void Renderer::createTarget( const QSize& size ) { +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + QOpenGLFramebufferObjectFormat format; + format.setInternalTextureFormat( GL_RGBA8 ); + format.setSamples( 0 ); + format.setAttachment( QOpenGLFramebufferObject::CombinedDepthStencil ); + + m_fbo = new QOpenGLFramebufferObject( size, format ); +#else const auto rhi = context()->rhi(); auto flags = QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource; @@ -151,10 +197,15 @@ namespace auto defaultContext = qobject_cast< QSGDefaultRenderContext* >( context() ); m_rt.cb = defaultContext->currentFrameCommandBuffer(); +#endif } void Renderer::clearTarget() { +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + delete m_fbo; + m_fbo = nullptr; +#else delete m_rt.rt; m_rt.rt = nullptr; @@ -163,6 +214,7 @@ namespace delete m_rhiTexture; m_rhiTexture = nullptr; +#endif } } @@ -170,11 +222,18 @@ class QskSceneTexturePrivate final : public QSGTexturePrivate { public: QskSceneTexturePrivate( const QQuickWindow* window, QskSceneTexture* texture ) +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + : QSGTexturePrivate() +#else : QSGTexturePrivate( texture ) +#endif , devicePixelRatio( window->effectiveDevicePixelRatio() ) { - context = dynamic_cast< QSGDefaultRenderContext* >( - QQuickWindowPrivate::get( window )->context ); + Q_UNUSED( texture ); + + // Qt5 needs the extra const_cast + auto dw = QQuickWindowPrivate::get( const_cast< QQuickWindow* >( window ) ); + context = dynamic_cast< QSGDefaultRenderContext* >( dw->context ); } QRectF rect; @@ -185,7 +244,7 @@ class QskSceneTexturePrivate final : public QSGTexturePrivate }; QskSceneTexture::QskSceneTexture( const QQuickWindow* window ) - : Inherited(*( new QskSceneTexturePrivate( window, this ) ) ) + : Inherited( *new QskSceneTexturePrivate( window, this ) ) { Q_ASSERT( d_func()->context ); } @@ -213,17 +272,6 @@ QSize QskSceneTexture::textureSize() const return size; } -qint64 QskSceneTexture::comparisonKey() const -{ - return qint64( rhiTexture() ); -} - -QRhiTexture* QskSceneTexture::rhiTexture() const -{ - Q_D( const QskSceneTexture ); - return d->renderer ? d->renderer->texture() : nullptr; -} - void QskSceneTexture::render( const QSGRootNode* rootNode, const QSGTransformNode* finalNode, const QRectF& rect ) { @@ -231,8 +279,6 @@ void QskSceneTexture::render( const QSGRootNode* rootNode, d->rect = rect; - const auto pixelSize = textureSize(); - if ( d->renderer == nullptr ) { d->renderer = new Renderer( this, d->context ); @@ -243,7 +289,7 @@ void QskSceneTexture::render( const QSGRootNode* rootNode, d->renderer->setFinalNode( const_cast< QSGTransformNode* >( finalNode ) ); d->renderer->setProjection( d->rect ); - d->renderer->setTextureSize( pixelSize ); + d->renderer->setTextureSize( textureSize() ); d->renderer->renderScene(); } @@ -262,9 +308,35 @@ bool QskSceneTexture::hasMipmaps() const return false; } -void QskSceneTexture::commitTextureOperations( QRhi*, QRhiResourceUpdateBatch* ) +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + +void QskSceneTexture::bind() { - // what to do here ? + auto funcs = QOpenGLContext::currentContext()->functions(); + funcs->glBindTexture( GL_TEXTURE_2D, textureId() ); + + updateBindOptions(); } +int QskSceneTexture::textureId() const +{ + Q_D( const QskSceneTexture ); + return d->renderer ? d->renderer->textureId() : 0; +} + +#else + +qint64 QskSceneTexture::comparisonKey() const +{ + return qint64( rhiTexture() ); +} + +QRhiTexture* QskSceneTexture::rhiTexture() const +{ + Q_D( const QskSceneTexture ); + return d->renderer ? d->renderer->texture() : nullptr; +} + +#endif + #include "moc_QskSceneTexture.cpp" diff --git a/src/nodes/QskSceneTexture.h b/src/nodes/QskSceneTexture.h index 1a66f931..c5d89d10 100644 --- a/src/nodes/QskSceneTexture.h +++ b/src/nodes/QskSceneTexture.h @@ -29,15 +29,19 @@ class QSK_EXPORT QskSceneTexture : public QSGTexture QSize textureSize() const override; +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + void bind() override; + int textureId() const override; +#else qint64 comparisonKey() const override; QRhiTexture* rhiTexture() const override; +#endif QRectF normalizedTextureSubRect() const override; // satisfy the QSGTexture API bool hasAlphaChannel() const override; bool hasMipmaps() const override; - void commitTextureOperations( QRhi*, QRhiResourceUpdateBatch* ) override; Q_SIGNALS: void updateRequested();