diff --git a/examples/examples.pro b/examples/examples.pro index 2148d806..76bb9b66 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -26,6 +26,5 @@ SUBDIRS += \ boxes \ buttons \ frames \ - gbenchmark \ glabels \ messageboxQml diff --git a/examples/gbenchmark/Benchmark.cpp b/examples/gbenchmark/Benchmark.cpp deleted file mode 100644 index eeef334a..00000000 --- a/examples/gbenchmark/Benchmark.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the 3-clause BSD License - *****************************************************************************/ - -#include "Benchmark.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -bool Benchmark::run( const QString& dirName ) -{ - QDir svgDir( dirName ); - - QStringList svgFiles = svgDir.entryList( QStringList() << "*.svg", QDir::Files ); - if ( svgFiles.isEmpty() ) - return false; - - const char qvgPath[] = "/tmp/benchmark/qvg"; - if ( !svgDir.mkpath( qvgPath ) ) - return false; - - QStringList qvgFiles = svgFiles; - for ( int i = 0; i < qvgFiles.size(); i++ ) - { - svgFiles[ i ].prepend( "/" ); - svgFiles[ i ].prepend( dirName ); - - qvgFiles[ i ].replace( ".svg", ".qvg" ); - qvgFiles[ i ].prepend( "/" ); - qvgFiles[ i ].prepend( qvgPath ); - } - - QVector< QskGraphic > graphics( qvgFiles.size() ); - QVector< QSvgRenderer* > renderers( svgFiles.size() ); - - qint64 msElapsed[ 6 ]; - - QElapsedTimer timer; - - { - // compile step - - timer.start(); - - for ( int i = 0; i < svgFiles.size(); i++ ) - { - renderers[ i ] = new QSvgRenderer(); - if ( !renderers[ i ]->load( svgFiles[ i ] ) ) - { - qCritical() << "Can't load" << svgFiles[ i ]; - return false; - } - } - - msElapsed[ 0 ] = timer.elapsed(); - } - - { - // converting into graphics and storing to disk - - timer.start(); - - for ( int i = 0; i < renderers.size(); i++ ) - { - QPainter painter( &graphics[ i ] ); - renderers[ i ]->render( &painter ); - painter.end(); - } - - msElapsed[ 1 ] = timer.elapsed(); - } - - { - // writing them to disk - - timer.start(); - - for ( int i = 0; i < graphics.size(); i++ ) - { - QskGraphicIO::write( graphics[ i ], qvgFiles[ i ] ); - } - - msElapsed[ 2 ] = timer.elapsed(); - } - - { - // loading qvg files to memory - - timer.start(); - - for ( int i = 0; i < qvgFiles.size(); i++ ) - { - graphics[ i ] = QskGraphicIO::read( qvgFiles[ i ] ); - if ( graphics[ i ].isNull() ) - { - qCritical() << "Can't load" << qvgFiles[ i ]; - return false; - } - } - - msElapsed[ 3 ] = timer.elapsed(); - } - - { - // creating textures using OpenGL - - timer.start(); - - const QSize targetSize( 200, 200 ); - const QskColorFilter colorFilter; - - for ( int i = 0; i < qvgFiles.size(); i++ ) - { - using namespace QskTextureRenderer; - - const auto textureId = createTextureFromGraphic( - nullptr, OpenGL, targetSize, graphics[ i ], colorFilter, - Qt::IgnoreAspectRatio ); - - if ( textureId == 0 ) - { - qCritical() << "Can't render texture for" << qvgFiles[ i ]; - return false; - } - } - - msElapsed[ 4 ] = timer.elapsed(); - } - - { - // creating textures using Raster - - timer.start(); - - const QSize targetSize( 200, 200 ); - const QskColorFilter colorFilter; - - for ( int i = 0; i < qvgFiles.size(); i++ ) - { - using namespace QskTextureRenderer; - - const auto textureId = createTextureFromGraphic( - nullptr, Raster, targetSize, graphics[ i ], colorFilter, - Qt::IgnoreAspectRatio ); - - if ( textureId == 0 ) - { - qCritical() << "Can't render texture for" << qvgFiles[ i ]; - return false; - } - } - - msElapsed[ 5 ] = timer.elapsed(); - } - - qDebug() << "#Icons:" << svgFiles.count() << - "Compiled:" << msElapsed[ 0 ] << - "Converted:" << msElapsed[ 1 ] << - "Stored:" << msElapsed[ 2 ] << - "Loaded:" << msElapsed[ 3 ] << - "Rendered OpenGL:" << msElapsed[ 4 ] << - "Rendered Raster:" << msElapsed[ 5 ]; - - svgDir.rmdir( qvgPath ); - - return true; -} diff --git a/examples/gbenchmark/Benchmark.h b/examples/gbenchmark/Benchmark.h deleted file mode 100644 index 4a6efc78..00000000 --- a/examples/gbenchmark/Benchmark.h +++ /dev/null @@ -1,13 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the 3-clause BSD License - *****************************************************************************/ - -#pragma once - -class QString; - -namespace Benchmark -{ - bool run( const QString& svgDir ); -} diff --git a/examples/gbenchmark/gbenchmark.pro b/examples/gbenchmark/gbenchmark.pro deleted file mode 100644 index 850763cf..00000000 --- a/examples/gbenchmark/gbenchmark.pro +++ /dev/null @@ -1,10 +0,0 @@ -CONFIG += qskexample - -QT += svg - -HEADERS += \ - Benchmark.h - -SOURCES += \ - Benchmark.cpp \ - main.cpp diff --git a/examples/gbenchmark/main.cpp b/examples/gbenchmark/main.cpp deleted file mode 100644 index 2a5b00a2..00000000 --- a/examples/gbenchmark/main.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the 3-clause BSD License - *****************************************************************************/ - -#include "Benchmark.h" - -#include -#include -#include - -#include -#include - -class Button : public QskPushButton -{ - public: - Button( const QString& testDir ) - : m_testDir( testDir ) - { - setText( QString( "Run: " ) + testDir ); - setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed ); - } - - void run() - { - Benchmark::run( m_testDir ); - } - - private: - QString m_testDir; -}; - -int main( int argc, char* argv[] ) -{ - QGuiApplication app( argc, argv ); - - QCommandLineParser parser; - parser.setApplicationDescription( "Benchmark for creating textures from SVGs" ); - parser.addHelpOption(); - parser.addPositionalArgument( "svgdir", "Directory with SVG files.", "[pathname]" ); - - parser.process( app ); - - const QStringList args = parser.positionalArguments(); - - if ( args.count() != 1 ) - parser.showHelp( 1 ); - - auto button = new Button( args[ 0 ] ); - button->setLayoutAlignmentHint( Qt::AlignCenter ); - QObject::connect( button, &Button::clicked, button, &Button::run ); - - auto box = new QskLinearBox(); - box->addItem( button ); - - QskWindow window; - window.setColor( Qt::white ); - window.resize( 400, 400 ); - window.addItem( box ); - - window.show(); - - return app.exec(); -} diff --git a/src/controls/QskGraphicLabelSkinlet.cpp b/src/controls/QskGraphicLabelSkinlet.cpp index ea85c8f8..e6a36707 100644 --- a/src/controls/QskGraphicLabelSkinlet.cpp +++ b/src/controls/QskGraphicLabelSkinlet.cpp @@ -10,7 +10,6 @@ #include "QskColorFilter.h" #include "QskFunctions.h" #include "QskGraphic.h" -#include "QskTextureNode.h" QskGraphicLabelSkinlet::QskGraphicLabelSkinlet( QskSkin* skin ) : Inherited( skin ) diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index 61ed5415..29fc172b 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -7,6 +7,7 @@ #include "QskArcNode.h" #include "QskAspect.h" +#include "QskArcMetrics.h" #include "QskBoxBorderColors.h" #include "QskBoxBorderMetrics.h" #include "QskBoxClipNode.h" @@ -24,6 +25,7 @@ #include "QskTextNode.h" #include "QskTextOptions.h" #include "QskSkinStateChanger.h" +#include "QskTextureRenderer.h" #include #include @@ -111,18 +113,17 @@ static inline QSGNode* qskUpdateGraphicNode( if ( control == nullptr ) return nullptr; - auto mode = QskTextureRenderer::OpenGL; - auto graphicNode = static_cast< QskGraphicNode* >( node ); if ( graphicNode == nullptr ) graphicNode = new QskGraphicNode(); - if ( control->testUpdateFlag( QskControl::PreferRasterForTextures ) ) - mode = QskTextureRenderer::Raster; + const bool useRaster = control->testUpdateFlag( QskControl::PreferRasterForTextures ); + graphicNode->setRenderHint( useRaster ? QskPaintedNode::Raster : QskPaintedNode::OpenGL ); + + graphicNode->setMirrored( mirrored ); const auto r = qskSceneAlignedRect( control, rect ); - graphicNode->setGraphic( control->window(), graphic, - colorFilter, mode, r, mirrored ); + graphicNode->setGraphic( control->window(), graphic, colorFilter, r ); return graphicNode; } diff --git a/src/graphic/QskGraphicTextureFactory.cpp b/src/graphic/QskGraphicTextureFactory.cpp index 3a256448..25210b87 100644 --- a/src/graphic/QskGraphicTextureFactory.cpp +++ b/src/graphic/QskGraphicTextureFactory.cpp @@ -54,16 +54,30 @@ QSize QskGraphicTextureFactory::size() const return m_size; } - QSGTexture* QskGraphicTextureFactory::createTexture( QQuickWindow* window ) const { - using namespace QskTextureRenderer; + class PaintHelper : public QskTextureRenderer::PaintHelper + { + public: + PaintHelper( const QskGraphic& graphic, const QskColorFilter& filter ) + : m_graphic( graphic ) + , m_filter( filter ) + { + } - const uint textureId = createTextureFromGraphic( - window, QskTextureRenderer::OpenGL, m_size, m_graphic, m_colorFilter, - Qt::IgnoreAspectRatio ); + void paint( QPainter* painter, const QSize& size ) override + { + const QRect rect( 0, 0, size.width(), size.height() ); + m_graphic.render( painter, rect, m_filter ); + } - return textureFromId( window, textureId, m_size ); + private: + const QskGraphic& m_graphic; + const QskColorFilter& m_filter; + }; + + PaintHelper helper( m_graphic, m_colorFilter ); + return QskTextureRenderer::createPaintedTexture( window, m_size, &helper ); } QSize QskGraphicTextureFactory::textureSize() const diff --git a/src/nodes/QskArcNode.cpp b/src/nodes/QskArcNode.cpp index 698e8364..be8feb07 100644 --- a/src/nodes/QskArcNode.cpp +++ b/src/nodes/QskArcNode.cpp @@ -4,7 +4,19 @@ *****************************************************************************/ #include "QskArcNode.h" +#include "QskArcMetrics.h" #include "QskArcRenderer.h" +#include "QskGradient.h" + +namespace +{ + class ArcData + { + public: + const QskArcMetrics& metrics; + const QskGradient& gradient; + }; +} QskArcNode::QskArcNode() { @@ -17,26 +29,28 @@ QskArcNode::~QskArcNode() void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& metrics, const QskGradient& gradient, QQuickWindow* window ) { - m_metrics = metrics; - m_gradient = gradient; - - update( window, QskTextureRenderer::AutoDetect, rect.toRect() ); + const ArcData arcData { metrics, gradient }; + update( window, rect, QSizeF(), &arcData ); } -void QskArcNode::paint( QPainter* painter, const QSizeF& size ) +void QskArcNode::paint( QPainter* painter, const QSize& size, const void* nodeData ) { - const qreal w = m_metrics.width(); + const auto arcData = reinterpret_cast< const ArcData* >( nodeData ); + + const qreal w = arcData->metrics.width(); const QRectF rect( 0.5 * w, 0.5 * w, size.width() - w, size.height() - w ); QskArcRenderer renderer; - renderer.renderArc( rect, m_metrics, m_gradient, painter ); + renderer.renderArc( rect, arcData->metrics, arcData->gradient, painter ); } -QskHashValue QskArcNode::hash() const +QskHashValue QskArcNode::hash( const void* nodeData ) const { - auto h = m_metrics.hash(); + const auto arcData = reinterpret_cast< const ArcData* >( nodeData ); - for( const auto& stop : qAsConst( m_gradient.stops() ) ) + auto h = arcData->metrics.hash(); + + for( const auto& stop : qAsConst( arcData->gradient.stops() ) ) h = stop.hash( h ); return h; diff --git a/src/nodes/QskArcNode.h b/src/nodes/QskArcNode.h index 0bf3724c..24c66654 100644 --- a/src/nodes/QskArcNode.h +++ b/src/nodes/QskArcNode.h @@ -6,10 +6,13 @@ #ifndef QSK_ARC_NODE_H #define QSK_ARC_NODE_H -#include "QskArcMetrics.h" -#include "QskGradient.h" #include "QskPaintedNode.h" +class QskArcMetrics; +class QskGradient; + +// should be a QSGGeometryNode, TODO .. + class QSK_EXPORT QskArcNode : public QskPaintedNode { public: @@ -19,12 +22,9 @@ class QSK_EXPORT QskArcNode : public QskPaintedNode void setArcData( const QRectF&, const QskArcMetrics&, const QskGradient&, QQuickWindow* ); - void paint( QPainter* painter, const QSizeF& size ) override; - QskHashValue hash() const override; - - private: - QskArcMetrics m_metrics; - QskGradient m_gradient; + protected: + void paint( QPainter*, const QSize&, const void* nodeData ) override; + QskHashValue hash( const void* nodeData ) const override; }; #endif diff --git a/src/nodes/QskGraphicNode.cpp b/src/nodes/QskGraphicNode.cpp index 4e3e4d79..86023740 100644 --- a/src/nodes/QskGraphicNode.cpp +++ b/src/nodes/QskGraphicNode.cpp @@ -8,27 +8,17 @@ #include "QskColorFilter.h" #include "QskPainterCommand.h" -static inline QskHashValue qskHash( - const QskGraphic& graphic, const QskColorFilter& colorFilter, - QskTextureRenderer::RenderMode renderMode ) +namespace { - QskHashValue hash = 12000; - - const auto& substitutions = colorFilter.substitutions(); - if ( substitutions.size() > 0 ) + class GraphicData { - hash = qHashBits( substitutions.constData(), - substitutions.size() * sizeof( substitutions[ 0 ] ), hash ); - } - - hash = graphic.hash( hash ); - hash = qHash( renderMode, hash ); - - return hash; + public: + const QskGraphic& graphic; + const QskColorFilter& colorFilter; + }; } QskGraphicNode::QskGraphicNode() - : m_hash( 0 ) { } @@ -36,14 +26,10 @@ QskGraphicNode::~QskGraphicNode() { } -void QskGraphicNode::setGraphic( - QQuickWindow* window, const QskGraphic& graphic, const QskColorFilter& colorFilter, - QskTextureRenderer::RenderMode renderMode, const QRectF& rect, - Qt::Orientations mirrored ) +void QskGraphicNode::setGraphic( QQuickWindow* window, const QskGraphic& graphic, + const QskColorFilter& colorFilter, const QRectF& rect ) { - bool isTextureDirty = isNull(); - - QSize textureSize; + QSizeF size; if ( graphic.commandTypes() == QskGraphic::RasterData ) { @@ -52,34 +38,43 @@ void QskGraphicNode::setGraphic( There is no benefit in rescaling it into the target rectangle by the CPU and creating a new texture. */ - textureSize = graphic.defaultSize().toSize(); - } - else - { - textureSize = rect.size().toSize(); - - if ( !isTextureDirty ) - { - const auto oldRect = QskTextureNode::rect(); - isTextureDirty = ( rect.width() != static_cast< int >( oldRect.width() ) ) || - ( rect.height() != static_cast< int >( oldRect.height() ) ); - } + size = graphic.defaultSize(); } - const auto hash = qskHash( graphic, colorFilter, renderMode ); - if ( hash != m_hash ) - { - m_hash = hash; - isTextureDirty = true; - } - - auto textureId = QskTextureNode::textureId(); - - if ( isTextureDirty ) - { - textureId = QskTextureRenderer::createTextureFromGraphic( - window, renderMode, textureSize, graphic, colorFilter, Qt::IgnoreAspectRatio ); - } - - QskTextureNode::setTexture( window, rect, textureId, mirrored ); + const GraphicData graphicData { graphic, colorFilter }; + update( window, rect, size, &graphicData ); +} + +void QskGraphicNode::paint( QPainter* painter, const QSize& size, const void* nodeData ) +{ + const auto graphicData = reinterpret_cast< const GraphicData* >( nodeData ); + + const auto& graphic = graphicData->graphic; + const auto& colorFilter = graphicData->colorFilter; + + if ( graphic.commandTypes() == QskGraphic::RasterData ) + { + qDebug() << size; + } + + const QRectF rect( 0, 0, size.width(), size.height() ); + graphic.render( painter, rect, colorFilter, Qt::IgnoreAspectRatio ); +} + +QskHashValue QskGraphicNode::hash( const void* nodeData ) const +{ + const auto graphicData = reinterpret_cast< const GraphicData* >( nodeData ); + + const auto& graphic = graphicData->graphic; + + QskHashValue hash = 12000; + + const auto& substitutions = graphicData->colorFilter.substitutions(); + if ( substitutions.size() > 0 ) + { + hash = qHashBits( substitutions.constData(), + substitutions.size() * sizeof( substitutions[ 0 ] ), hash ); + } + + return graphic.hash( hash ); } diff --git a/src/nodes/QskGraphicNode.h b/src/nodes/QskGraphicNode.h index 3d5925b5..26b5930c 100644 --- a/src/nodes/QskGraphicNode.h +++ b/src/nodes/QskGraphicNode.h @@ -6,29 +6,23 @@ #ifndef QSK_GRAPHIC_NODE_H #define QSK_GRAPHIC_NODE_H -#include "QskTextureRenderer.h" -#include "QskTextureNode.h" +#include "QskPaintedNode.h" class QskGraphic; class QskColorFilter; -class QQuickWindow; -class QSK_EXPORT QskGraphicNode : public QskTextureNode +class QSK_EXPORT QskGraphicNode : public QskPaintedNode { public: QskGraphicNode(); ~QskGraphicNode() override; - void setGraphic( QQuickWindow*, - const QskGraphic&, const QskColorFilter&, - QskTextureRenderer::RenderMode, const QRectF&, - Qt::Orientations mirrored = Qt::Orientations() ); + void setGraphic( QQuickWindow*, const QskGraphic&, + const QskColorFilter&, const QRectF& ); private: - void setTexture( QQuickWindow*, - const QRectF&, uint id, Qt::Orientations ) = delete; - - QskHashValue m_hash; + virtual void paint( QPainter*, const QSize&, const void* nodeData ) override; + virtual QskHashValue hash( const void* nodeData ) const override; }; #endif diff --git a/src/nodes/QskPaintedNode.cpp b/src/nodes/QskPaintedNode.cpp index 574cae82..101f9641 100644 --- a/src/nodes/QskPaintedNode.cpp +++ b/src/nodes/QskPaintedNode.cpp @@ -4,24 +4,44 @@ *****************************************************************************/ #include "QskPaintedNode.h" +#include "QskSGNode.h" #include "QskTextureRenderer.h" -class QskPaintedNode::PaintHelper : public QskTextureRenderer::PaintHelper +#include +#include +#include +#include + +QSK_QT_PRIVATE_BEGIN +#include +QSK_QT_PRIVATE_END + +static inline QSGImageNode::TextureCoordinatesTransformMode + qskEffectiveTransformMode( const Qt::Orientations mirrored ) { - public: - inline PaintHelper( QskPaintedNode* node ) - : m_node( node ) - { - } + QSGImageNode::TextureCoordinatesTransformMode mode; - void paint( QPainter* painter, const QSize& size ) override - { - m_node->paint( painter, size ); - } + if ( mirrored & Qt::Vertical ) + mode |= QSGImageNode::MirrorVertically; - private: - QskPaintedNode* m_node; -}; + if ( mirrored & Qt::Horizontal ) + mode |= QSGImageNode::MirrorHorizontally; + + return mode; +} + +namespace +{ + const quint8 imageRole = 250; // reserved for internal use + + inline QSGImageNode* findImageNode( const QSGNode* parentNode ) + { + auto node = QskSGNode::findChildNode( + const_cast< QSGNode* >( parentNode ), imageRole ); + + return static_cast< QSGImageNode* >( node ); + } +} QskPaintedNode::QskPaintedNode() { @@ -31,33 +51,185 @@ QskPaintedNode::~QskPaintedNode() { } -void QskPaintedNode::update( QQuickWindow* window, - QskTextureRenderer::RenderMode renderMode, const QRect& rect ) +void QskPaintedNode::setRenderHint( RenderHint renderHint ) { - bool isTextureDirty = isNull(); + m_renderHint = renderHint; +} - if ( !isTextureDirty ) +QskPaintedNode::RenderHint QskPaintedNode::renderHint() const +{ + return m_renderHint; +} + +void QskPaintedNode::setMirrored( Qt::Orientations orientations ) +{ + if ( orientations != m_mirrored ) { - const auto oldRect = QskTextureNode::rect(); - isTextureDirty = ( rect.width() != static_cast< int >( oldRect.width() ) ) || - ( rect.height() != static_cast< int >( oldRect.height() ) ); + m_mirrored = orientations; + + if ( auto imageNode = findImageNode( this ) ) + { + imageNode->setTextureCoordinatesTransform( + qskEffectiveTransformMode( orientations ) ); + } + } +} + +Qt::Orientations QskPaintedNode::mirrored() const +{ + return m_mirrored; +} + +QSize QskPaintedNode::textureSize() const +{ + if ( const auto imageNode = findImageNode( this ) ) + { + if ( auto texture = imageNode->texture() ) + return texture->textureSize(); } - const auto newHash = hash(); + return QSize(); +} + +QRectF QskPaintedNode::rect() const +{ + const auto imageNode = findImageNode( this ); + return imageNode ? imageNode->rect() : QRectF(); +} + +void QskPaintedNode::update( QQuickWindow* window, + const QRectF& rect, const QSizeF& size, const void* nodeData ) +{ + auto imageNode = findImageNode( this ); + + if ( rect.isEmpty() ) + { + if ( imageNode ) + { + removeChildNode( imageNode ); + delete imageNode; + } + + return; + } + + if ( imageNode == nullptr ) + { + imageNode = window->createImageNode(); + + imageNode->setOwnsTexture( true ); + QskSGNode::setNodeRole( imageNode, imageRole ); + + appendChildNode( imageNode ); + } + + QSize imageSize; + + { + auto scaledSize = size.isEmpty() ? rect.size() : size; + scaledSize *= window->effectiveDevicePixelRatio(); + + imageSize = scaledSize.toSize(); + } + + bool isTextureDirty = false; + + const auto newHash = hash( nodeData ); if ( ( newHash == 0 ) || ( newHash != m_hash ) ) { m_hash = newHash; isTextureDirty = true; } - - auto textureId = QskTextureNode::textureId(); - - if ( isTextureDirty ) + else { - PaintHelper helper( this ); - textureId = QskTextureRenderer::createTexture( - window, renderMode, rect.size(), &helper ); + isTextureDirty = ( imageSize != textureSize() ); } - QskTextureNode::setTexture( window, rect, textureId ); + + if ( isTextureDirty ) + updateTexture( window, imageSize, nodeData ); + + imageNode->setRect( rect ); + imageNode->setTextureCoordinatesTransform( + qskEffectiveTransformMode( m_mirrored ) ); +} + +void QskPaintedNode::updateTexture( QQuickWindow* window, + const QSize& size, const void* nodeData ) +{ + auto imageNode = findImageNode( this ); + + if ( ( m_renderHint == OpenGL ) && QskTextureRenderer::isOpenGLWindow( window ) ) + { + const auto textureId = createTextureGL( window, size, nodeData ); + + auto texture = qobject_cast< QSGPlainTexture* >( imageNode->texture() ); + if ( texture == nullptr ) + { + texture = new QSGPlainTexture; + texture->setHasAlphaChannel( true ); + texture->setOwnsTexture( true ); + + imageNode->setTexture( texture ); + } + + QskTextureRenderer::setTextureId( window, textureId, size, texture ); + } + else + { + const auto image = createImage( window, size, nodeData ); + + if ( auto texture = qobject_cast< QSGPlainTexture* >( imageNode->texture() ) ) + texture->setImage( image ); + else + imageNode->setTexture( window->createTextureFromImage( image ) ); + } +} + +QImage QskPaintedNode::createImage( QQuickWindow* window, + const QSize& size, const void* nodeData ) +{ + QImage image( size, QImage::Format_RGBA8888_Premultiplied ); + image.fill( Qt::transparent ); + + QPainter painter( &image ); + + /* + setting a devicePixelRatio for the image only works for + value >= 1.0. So we have to scale manually. + */ + const auto ratio = window->effectiveDevicePixelRatio(); + painter.scale( ratio, ratio ); + + paint( &painter, size / ratio, nodeData ); + + painter.end(); + + return image; +} + +quint32 QskPaintedNode::createTextureGL( + QQuickWindow* window, const QSize& size, const void* nodeData ) +{ + class PaintHelper : public QskTextureRenderer::PaintHelper + { + public: + PaintHelper( QskPaintedNode* node, const void* nodeData ) + : m_node( node ) + , m_nodeData( nodeData ) + { + } + + void paint( QPainter* painter, const QSize& size ) override + { + m_node->paint( painter, size, m_nodeData ); + } + + private: + QskPaintedNode* m_node; + const void* m_nodeData; + }; + + PaintHelper helper( this, nodeData ); + return createPaintedTextureGL( window, size, &helper ); } diff --git a/src/nodes/QskPaintedNode.h b/src/nodes/QskPaintedNode.h index 6b53ab6a..cda4250f 100644 --- a/src/nodes/QskPaintedNode.h +++ b/src/nodes/QskPaintedNode.h @@ -6,31 +6,62 @@ #ifndef QSK_PAINTED_NODE_H #define QSK_PAINTED_NODE_H -#include "QskTextureNode.h" -#include "QskTextureRenderer.h" +#include "QskGlobal.h" +#include -class QSK_EXPORT QskPaintedNode : public QskTextureNode +class QQuickWindow; +class QPainter; +class QImage; + +class QSK_EXPORT QskPaintedNode : public QSGNode { public: + /* + Raster usually provides a better antialiasing and is less buggy, + while OpenGL might be faster - depending on the content that has + to be painted. + + Since Qt 5.10 X11 is back and could be an interesting option + with good quality and hardware accelerated performance. TODO ... + + OpenGL might be ignored depending on the backend used by the + application. + */ + enum RenderHint + { + Raster, + OpenGL + }; + QskPaintedNode(); ~QskPaintedNode() override; - void update( QQuickWindow*, - QskTextureRenderer::RenderMode, const QRect& ); + void setRenderHint( RenderHint ); + RenderHint renderHint() const; + + void setMirrored( Qt::Orientations ); + Qt::Orientations mirrored() const; + + QRectF rect() const; + QSize textureSize() const; + + virtual void paint( QPainter*, const QSize&, const void* nodeData ) = 0; protected: - virtual void paint( QPainter*, const QSizeF& ) = 0; + void update( QQuickWindow*, const QRectF&, const QSizeF&, const void* nodeData ); // a hash value of '0' always results in repainting - virtual QskHashValue hash() const = 0; + virtual QskHashValue hash( const void* nodeData ) const = 0; private: - class PaintHelper; + void updateTexture( QQuickWindow*, const QSize&, const void* nodeData ); - void setTexture( QQuickWindow*, - const QRectF&, uint id, Qt::Orientations ) = delete; + QImage createImage( QQuickWindow*, const QSize&, const void* nodeData ); + quint32 createTextureGL( QQuickWindow*, const QSize&, const void* nodeData ); - QskHashValue m_hash; + RenderHint m_renderHint = OpenGL; + Qt::Orientations m_mirrored; + QskHashValue m_hash = 0; }; #endif diff --git a/src/nodes/QskTextureNode.cpp b/src/nodes/QskTextureNode.cpp deleted file mode 100644 index ae90fd66..00000000 --- a/src/nodes/QskTextureNode.cpp +++ /dev/null @@ -1,393 +0,0 @@ -#include "QskTextureNode.h" -#include "QskFunctions.h" - -#include -#include -#include -#include - -QSK_QT_PRIVATE_BEGIN -#include -QSK_QT_PRIVATE_END - -#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) - -#include -#include -#include - -QSK_QT_PRIVATE_BEGIN -#include -#include -QSK_QT_PRIVATE_END - -static void qskUpdateGLTextureId( QRhiTexture* rhiTexture, uint textureId ) -{ - // hack time: we do not want to create a new QSGTexture object for each texture - - class Texture : public QRhiTexture - { - public: - GLuint texture; - // ... - }; - - GLuint id = rhiTexture->nativeTexture().object; - - if ( id ) - { - auto funcs = QOpenGLContext::currentContext()->functions(); - funcs->glDeleteTextures( 1, &id ); - } - - auto glTexture = static_cast< Texture* >( rhiTexture ); - glTexture->texture = textureId; - - Q_ASSERT( rhiTexture->nativeTexture().object == textureId ); -} - -using TextureMaterial = QSGTextureMaterial; -using OpaqueTextureMaterial = QSGOpaqueTextureMaterial; - -static inline void qskDeleteTexture( const TextureMaterial& material ) -{ - delete material.texture(); -} - -#endif - -#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) - -namespace -{ - class MaterialShader final : public QSGMaterialShader - { - public: - MaterialShader( bool isOpaque ); - - char const* const* attributeNames() const override; - void updateState( const RenderState&, QSGMaterial*, QSGMaterial* ) override; - - protected: - void initialize() override; - - private: - int m_matrixId = -1; - int m_opacityId = -1; - - const bool m_isOpaque : 1; - }; - - class Material : public QSGMaterial - { - public: - Material( bool isOpaque ); - - QSGMaterialType* type() const override; - QSGMaterialShader* createShader() const override; - - void setTextureId( uint ); - uint textureId() const; - - int compare( const QSGMaterial* ) const override; - - private: - uint m_textureId = 0; - const bool m_isOpaque : 1; - }; - - class TextureMaterial final : public Material - { - public: - TextureMaterial() - : Material( false ) - { - } - }; - - class OpaqueTextureMaterial final : public Material - { - public: - OpaqueTextureMaterial() - : Material( true ) - { - } - }; - - MaterialShader::MaterialShader( bool isOpaque ) - : m_isOpaque( isOpaque ) - { - setShaderSourceFile( QOpenGLShader::Vertex, - QStringLiteral( ":/qt-project.org/scenegraph/shaders/opaquetexture.vert" ) ); - - const auto fragmentShaderFile = m_isOpaque - ? QStringLiteral( ":/qt-project.org/scenegraph/shaders/opaquetexture.frag" ) - : QStringLiteral( ":/qt-project.org/scenegraph/shaders/texture.frag" ); - - setShaderSourceFile( QOpenGLShader::Fragment, fragmentShaderFile ); - } - - char const* const* MaterialShader::attributeNames() const - { - static char const* const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", 0 }; - return attr; - } - - void MaterialShader::updateState( - const RenderState& state, QSGMaterial* newMaterial, QSGMaterial* oldMaterial ) - { - if ( !m_isOpaque && state.isOpacityDirty() ) - program()->setUniformValue( m_opacityId, state.opacity() ); - - auto* materialOld = static_cast< Material* >( oldMaterial ); - auto* materialNew = static_cast< Material* >( newMaterial ); - - if ( ( materialOld == nullptr ) || - ( materialOld->textureId() != materialNew->textureId() ) ) - { - auto funcs = QOpenGLContext::currentContext()->functions(); - funcs->glBindTexture( GL_TEXTURE_2D, materialNew->textureId() ); - } - - if ( state.isMatrixDirty() ) - program()->setUniformValue( m_matrixId, state.combinedMatrix() ); - } - - void MaterialShader::initialize() - { - m_matrixId = program()->uniformLocation( "qt_Matrix" ); - - if ( !m_isOpaque ) - m_opacityId = program()->uniformLocation( "opacity" ); - } - - Material::Material( bool isOpaque ) - : m_isOpaque( isOpaque ) - { - setFlag( Blending, true ); // alpha blending - } - - void Material::setTextureId( uint id ) - { - m_textureId = id; - } - - uint Material::textureId() const - { - return m_textureId; - } - - QSGMaterialType* Material::type() const - { - if ( m_isOpaque ) - { - static QSGMaterialType typeOpaque; - return &typeOpaque; - } - else - { - static QSGMaterialType type; - return &type; - } - } - - QSGMaterialShader* Material::createShader() const - { - return new MaterialShader( m_isOpaque ); - } - - int Material::compare( const QSGMaterial* other ) const - { - const auto otherMaterial = static_cast< const Material* >( other ); - - if ( m_textureId == otherMaterial->m_textureId ) - return 0; - - return ( m_textureId > otherMaterial->m_textureId ) ? 1 : -1; - } -} - -static inline void qskDeleteTexture( const TextureMaterial& material ) -{ - if ( material.textureId() > 0 ) - { - /* - In certain environments we have the effect, that at - program termination the context is already gone - */ - if ( auto context = QOpenGLContext::currentContext() ) - { - GLuint id = material.textureId(); - - auto funcs = context->functions(); - funcs->glDeleteTextures( 1, &id ); - } - } -} - -#endif - -class QskTextureNodePrivate final : public QSGGeometryNodePrivate -{ - public: - QskTextureNodePrivate() - : geometry( QSGGeometry::defaultAttributes_TexturedPoint2D(), 4 ) - { - } - - void setTextureId( QQuickWindow*, uint id ); - - void updateTextureGeometry() - { - QRectF r( 0, 0, 1, 1 ); - - if ( this->mirrored & Qt::Horizontal ) - { - r.setLeft( 1 ); - r.setRight( 0 ); - } - - if ( mirrored & Qt::Vertical ) - { - r.setTop( 1 ); - r.setBottom( 0 ); - } - - QSGGeometry::updateTexturedRectGeometry( &geometry, rect, r ); - } - - QSGGeometry geometry; - - OpaqueTextureMaterial opaqueMaterial; - TextureMaterial material; - - QRectF rect; - Qt::Orientations mirrored; -}; - -QskTextureNode::QskTextureNode() - : QSGGeometryNode( *new QskTextureNodePrivate ) -{ - Q_D( QskTextureNode ); - - setGeometry( &d->geometry ); - - setMaterial( &d->material ); - setOpaqueMaterial( &d->opaqueMaterial ); -} - -QskTextureNode::~QskTextureNode() -{ - Q_D( const QskTextureNode ); - qskDeleteTexture( d->material ); -} - -void QskTextureNode::setTexture( QQuickWindow* window, - const QRectF& rect, uint textureId, - Qt::Orientations mirrored ) -{ - Q_D( QskTextureNode ); - - if ( ( d->rect != rect ) || ( d->mirrored != mirrored ) ) - { - d->rect = rect; - d->mirrored = mirrored; - - d->updateTextureGeometry(); - markDirty( DirtyGeometry ); - } - - if ( textureId != this->textureId() ) - { - d->setTextureId( window, textureId ); - markDirty( DirtyMaterial ); - } -} - -#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) - -void QskTextureNodePrivate::setTextureId( QQuickWindow*, uint textureId ) -{ - qskDeleteTexture( this->material ); - - this->material.setTextureId( textureId ); - this->opaqueMaterial.setTextureId( textureId ); -} - -uint QskTextureNode::textureId() const -{ - Q_D( const QskTextureNode ); - return d->material.textureId(); -} - -#endif - -#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) - -void QskTextureNodePrivate::setTextureId( QQuickWindow* window, uint textureId ) -{ - auto texture = this->material.texture(); - - if ( texture ) - { - // we do not want to create a new QSGTexture object only - // to replace the textureId - - switch( window->rendererInterface()->graphicsApi() ) - { - case QSGRendererInterface::OpenGL: - { - qskUpdateGLTextureId( texture->rhiTexture(), textureId ); - break; - } - default: - { - delete texture; - texture = nullptr; - } - } - } - - if ( textureId > 0 && texture == nullptr ) - { - texture = QNativeInterface::QSGOpenGLTexture::fromNative( - static_cast< GLuint >( textureId ), window, - this->rect.size().toSize(), QQuickWindow::TextureHasAlphaChannel ); - - } - - this->material.setTexture( texture ); - this->opaqueMaterial.setTexture( texture ); -} - -uint QskTextureNode::textureId() const -{ - Q_D( const QskTextureNode ); - - if ( auto texture = d->material.texture() ) - { - const auto nativeTexture = texture->rhiTexture()->nativeTexture(); - return nativeTexture.object; - } - - return 0; -} - -#endif - -bool QskTextureNode::isNull() const -{ - return textureId() == 0; -} - -QRectF QskTextureNode::rect() const -{ - Q_D( const QskTextureNode ); - return d->rect; -} - -Qt::Orientations QskTextureNode::mirrored() const -{ - Q_D( const QskTextureNode ); - return d->mirrored; -} diff --git a/src/nodes/QskTextureNode.h b/src/nodes/QskTextureNode.h deleted file mode 100644 index 39868a63..00000000 --- a/src/nodes/QskTextureNode.h +++ /dev/null @@ -1,36 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the QSkinny License, Version 1.0 - *****************************************************************************/ - -#ifndef QSK_TEXTURE_NODE_H -#define QSK_TEXTURE_NODE_H - -#include "QskGlobal.h" - -#include -#include - -class QQuickWindow; -class QskTextureNodePrivate; - -class QSK_EXPORT QskTextureNode : public QSGGeometryNode -{ - public: - QskTextureNode(); - ~QskTextureNode() override; - - bool isNull() const; - - void setTexture( QQuickWindow*, const QRectF&, uint id, - Qt::Orientations mirrored = Qt::Orientations() ); - - uint textureId() const; - QRectF rect() const; - Qt::Orientations mirrored() const; - - private: - Q_DECLARE_PRIVATE( QskTextureNode ) -}; - -#endif diff --git a/src/nodes/QskTextureRenderer.cpp b/src/nodes/QskTextureRenderer.cpp index 16bc8074..908cc296 100644 --- a/src/nodes/QskTextureRenderer.cpp +++ b/src/nodes/QskTextureRenderer.cpp @@ -4,92 +4,178 @@ *****************************************************************************/ #include "QskTextureRenderer.h" -#include "QskColorFilter.h" -#include "QskGraphic.h" -#include "QskSetup.h" #include -#include #include -#include #include -#include #include #include #include -#include + +QSK_QT_PRIVATE_BEGIN +#include +#include +#include +QSK_QT_PRIVATE_END #if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) - #include + #include #endif -static inline bool qskHasOpenGLRenderer( const QQuickWindow* window ) +static GLuint qskTakeTexture( QOpenGLFramebufferObject& fbo ) +{ + /* + See https://bugreports.qt.io/browse/QTBUG-103929 + + As we create a FBO for each update of a node we can't live + without having this ( ugly ) workaround. + */ + class MyFBO + { + public: + virtual ~MyFBO() = default; + QScopedPointer< QOpenGLFramebufferObjectPrivate > d_ptr; + }; + + static_assert( sizeof( MyFBO ) == sizeof( QOpenGLFramebufferObject ), + "Bad cast: QOpenGLFramebufferObject does not match" ); + + auto& attachment = reinterpret_cast< MyFBO* >( &fbo )->d_ptr->colorAttachments[0]; + auto guard = attachment.guard; + + const auto textureId = fbo.takeTexture(); + + if ( guard ) + { + class MyGuard : public QOpenGLSharedResourceGuard + { + public: + void invalidateTexture() { invalidateResource(); } + }; + + reinterpret_cast< MyGuard* >( guard )->invalidateTexture(); + } + + attachment.guard = guard; + + return textureId; +} + +bool QskTextureRenderer::isOpenGLWindow( const QQuickWindow* window ) { if ( window == nullptr ) return false; const auto renderer = window->rendererInterface(); - return renderer->graphicsApi() == QSGRendererInterface::OpenGL; + switch( renderer->graphicsApi() ) + { + case QSGRendererInterface::OpenGL: +#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) + case QSGRendererInterface::OpenGLRhi: +#endif + return true; + + default: + return false; + } } -static uint qskCreateTextureOpenGL( QQuickWindow* window, - const QSize& size, QskTextureRenderer::PaintHelper* helper ) +void QskTextureRenderer::setTextureId( QQuickWindow* window, + quint32 textureId, const QSize& size, QSGTexture* texture ) { - const auto ratio = window ? window->effectiveDevicePixelRatio() : 1.0; + auto plainTexture = qobject_cast< QSGPlainTexture* >( texture ); + if ( plainTexture == nullptr ) + return; - const int width = ratio * size.width(); - const int height = ratio * size.height(); + auto rhi = QQuickWindowPrivate::get( window )->rhi; + +#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) + plainTexture->setTextureFromNativeTexture( + rhi, quint64( textureId ), 0, size, {}, {} ); +#else + if ( rhi ) + { + // enabled with: "export QSG_RHI=1" + plainTexture->setTextureFromNativeObject( rhi, + QQuickWindow::NativeObjectTexture, &textureId, 0, size, false ); + } + else + { + plainTexture->setTextureId( textureId ); + plainTexture->setTextureSize( size ); + } +#endif +} + +quint32 QskTextureRenderer::createPaintedTextureGL( + QQuickWindow* window, const QSize& size, QskTextureRenderer::PaintHelper* helper ) +{ + /* + Binding GL_ARRAY_BUFFER/GL_ELEMENT_ARRAY_BUFFER to 0 seems to be enough. + + However - as we do not know what is finally painted and what the + OpenGL paint engine is doing with better reinitialize everything. + + Hope this has no side effects as the context will leave the function + in a modified state. Otherwise we could try to change the buffers + only and reset them, before leaving. + + QQuickFramebufferObject does the FBO rendering early + ( QQuickWindow::beforeRendering ). But so far doing it below updatePaintNode + seems to work as well. Let's see if we run into issues ... + */ + + window->beginExternalCommands(); + +#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) + QQuickOpenGLUtils::resetOpenGLState(); +#else + window->resetOpenGLState(); +#endif + + auto context = QOpenGLContext::currentContext(); QOpenGLFramebufferObjectFormat format1; format1.setAttachment( QOpenGLFramebufferObject::CombinedDepthStencil ); - // ### TODO: get samples from window instead - format1.setSamples( QOpenGLContext::currentContext()->format().samples() ); + format1.setSamples( context->format().samples() ); - QOpenGLFramebufferObject multisampledFbo( width, height, format1 ); + QOpenGLFramebufferObject multisampledFbo( size, format1 ); - QOpenGLPaintDevice pd( width, height ); + QOpenGLPaintDevice pd( size ); pd.setPaintFlipped( true ); { QPainter painter( &pd ); - painter.scale( ratio, ratio ); painter.setCompositionMode( QPainter::CompositionMode_Source ); - painter.fillRect( 0, 0, width, height, Qt::transparent ); + painter.fillRect( 0, 0, size.width(), size.height(), Qt::transparent ); painter.setCompositionMode( QPainter::CompositionMode_SourceOver ); - helper->paint( &painter, size ); + const auto ratio = window->effectiveDevicePixelRatio(); -#if 1 - if ( format1.samples() > 0 ) - { - /* - Multisampling in the window surface might get lost - as a side effect of rendering to the FBO. - weired, needs to be investigated more - */ - painter.setRenderHint( QPainter::Antialiasing, true ); - } -#endif + painter.scale( ratio, ratio ); + helper->paint( &painter, size / ratio ); } QOpenGLFramebufferObjectFormat format2; format2.setAttachment( QOpenGLFramebufferObject::NoAttachment ); - QOpenGLFramebufferObject fbo( width, height, format2 ); + QOpenGLFramebufferObject fbo( size, format2 ); - const QRect fboRect( 0, 0, width, height ); + const QRect fboRect( 0, 0, size.width(), size.height() ); QOpenGLFramebufferObject::blitFramebuffer( &fbo, fboRect, &multisampledFbo, fboRect ); - return fbo.takeTexture(); + window->endExternalCommands(); + + return qskTakeTexture( fbo ); } -static uint qskCreateTextureRaster( QQuickWindow* window, +static QSGTexture* qskCreateTextureRaster( QQuickWindow* window, const QSize& size, QskTextureRenderer::PaintHelper* helper ) { const auto ratio = window ? window->effectiveDevicePixelRatio() : 1.0; @@ -109,130 +195,26 @@ static uint qskCreateTextureRaster( QQuickWindow* window, helper->paint( &painter, size ); } - const auto target = QOpenGLTexture::Target2D; + return window->createTextureFromImage( image, QQuickWindow::TextureHasAlphaChannel ); +} - auto context = QOpenGLContext::currentContext(); - if ( context == nullptr ) - return 0; - - auto& f = *context->functions(); - - GLint oldTexture; // we can't rely on having OpenGL Direct State Access - f.glGetIntegerv( QOpenGLTexture::BindingTarget2D, &oldTexture ); - - GLuint textureId; - f.glGenTextures( 1, &textureId ); - - f.glBindTexture( target, textureId ); - - f.glTexParameteri( target, GL_TEXTURE_MIN_FILTER, QOpenGLTexture::Nearest ); - f.glTexParameteri( target, GL_TEXTURE_MAG_FILTER, QOpenGLTexture::Nearest ); - - f.glTexParameteri( target, GL_TEXTURE_WRAP_S, QOpenGLTexture::ClampToEdge ); - f.glTexParameteri( target, GL_TEXTURE_WRAP_T, QOpenGLTexture::ClampToEdge ); - - if ( QOpenGLTexture::hasFeature( QOpenGLTexture::ImmutableStorage ) ) +QSGTexture* QskTextureRenderer::createPaintedTexture( + QQuickWindow* window, const QSize& size, PaintHelper* helper ) +{ + if ( isOpenGLWindow( window ) ) { - auto& ef = *context->extraFunctions(); - ef.glTexStorage2D( target, 1, - QOpenGLTexture::RGBA8_UNorm, image.width(), image.height() ); + const auto textureId = createPaintedTextureGL( window, size, helper ); - f.glTexSubImage2D( target, 0, 0, 0, image.width(), image.height(), - QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.constBits() ); + auto texture = new QSGPlainTexture; + texture->setHasAlphaChannel( true ); + texture->setOwnsTexture( true ); + + setTextureId( window, textureId, size, texture ); + + return texture; } else { - f.glTexImage2D( target, 0, QOpenGLTexture::RGBA8_UNorm, - image.width(), image.height(), 0, - QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.constBits() ); - } - - f.glBindTexture( target, oldTexture ); - - return textureId; -} - -QSGTexture* QskTextureRenderer::textureFromId( - QQuickWindow* window, uint textureId, const QSize& size ) -{ - const auto flags = static_cast< QQuickWindow::CreateTextureOptions >( - QQuickWindow::TextureHasAlphaChannel | QQuickWindow::TextureOwnsGLTexture ); - - QSGTexture* texture; - -#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) - - texture = QNativeInterface::QSGOpenGLTexture::fromNative( - textureId, window, size, flags ); - -#else - - const int nativeLayout = 0; // VkImageLayout in case of Vulkan - - texture = window->createTextureFromNativeObject( - QQuickWindow::NativeObjectTexture, &textureId, nativeLayout, size, flags ); -#endif - - return texture; -} - -uint QskTextureRenderer::createTexture( - QQuickWindow* window, RenderMode renderMode, - const QSize& size, PaintHelper* helper ) -{ -#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) - // Qt6.0.0 is buggy when using FBOs. So let's disable it for the moment TODO ... - renderMode = Raster; -#endif - - if ( renderMode != Raster ) - { - if ( !qskHasOpenGLRenderer( window ) ) - renderMode = Raster; - } - - if ( renderMode == AutoDetect ) - { - if ( qskSetup->testItemUpdateFlag( QskQuickItem::PreferRasterForTextures ) ) - renderMode = Raster; - else - renderMode = OpenGL; - } - - if ( renderMode == Raster ) return qskCreateTextureRaster( window, size, helper ); - else - return qskCreateTextureOpenGL( window, size, helper ); -} - -uint QskTextureRenderer::createTextureFromGraphic( - QQuickWindow* window, RenderMode renderMode, const QSize& size, - const QskGraphic& graphic, const QskColorFilter& colorFilter, - Qt::AspectRatioMode aspectRatioMode ) -{ - class PaintHelper : public QskTextureRenderer::PaintHelper - { - public: - PaintHelper( const QskGraphic& graphic, - const QskColorFilter& filter, Qt::AspectRatioMode aspectRatioMode ) - : m_graphic( graphic ) - , m_filter( filter ) - , m_aspectRatioMode( aspectRatioMode ) - { - } - - void paint( QPainter* painter, const QSize& size ) override - { - const QRect rect( 0, 0, size.width(), size.height() ); - m_graphic.render( painter, rect, m_filter, m_aspectRatioMode ); - } - - private: - const QskGraphic& m_graphic; - const QskColorFilter& m_filter; - const Qt::AspectRatioMode m_aspectRatioMode; - }; - - PaintHelper helper( graphic, colorFilter, aspectRatioMode ); - return createTexture( window, renderMode, size, &helper ); + } } diff --git a/src/nodes/QskTextureRenderer.h b/src/nodes/QskTextureRenderer.h index 4e83b6fd..afdec3ba 100644 --- a/src/nodes/QskTextureRenderer.h +++ b/src/nodes/QskTextureRenderer.h @@ -7,35 +7,15 @@ #define QSK_TEXTURE_RENDERER_H #include "QskGlobal.h" -#include -class QskGraphic; -class QskColorFilter; - -class QPainter; class QSize; +class QPainter; class QSGTexture; class QQuickWindow; namespace QskTextureRenderer { - /* - Raster usually provides a better antialiasing and is less buggy, - while OpenGL might be faster - depending on the content that has - to be painted. - - Since Qt 5.10 X11 is back and could be an interesting option - with good quality and hardware accelerated performance. TODO ... - */ - enum RenderMode - { - AutoDetect, // depends on QskSetup::controlFlags() - - Raster, - OpenGL - }; - - class QSK_EXPORT PaintHelper + class PaintHelper { public: PaintHelper() = default; @@ -47,15 +27,16 @@ namespace QskTextureRenderer Q_DISABLE_COPY( PaintHelper ) }; - QSK_EXPORT uint createTexture( - QQuickWindow*, RenderMode, const QSize&, PaintHelper* ); + bool isOpenGLWindow( const QQuickWindow* ); - QSK_EXPORT uint createTextureFromGraphic( - QQuickWindow*, RenderMode, const QSize&, const QskGraphic&, - const QskColorFilter&, Qt::AspectRatioMode ); + void setTextureId( QQuickWindow*, + quint32 textureId, const QSize&, QSGTexture* ); - QSK_EXPORT QSGTexture* textureFromId( - QQuickWindow*, uint textureId, const QSize& ); + quint32 createPaintedTextureGL( + QQuickWindow*, const QSize&, QskTextureRenderer::PaintHelper* ); + + QSK_EXPORT QSGTexture* createPaintedTexture( + QQuickWindow* window, const QSize& size, PaintHelper* helper ); } #endif diff --git a/src/src.pro b/src/src.pro index 366590c0..56a98910 100644 --- a/src/src.pro +++ b/src/src.pro @@ -3,6 +3,10 @@ TARGET = $$qskLibraryTarget(qskinny) QT += quick quick-private +greaterThan( QT_MAJOR_VERSION, 5 ) { + QT += opengl-private +} + contains(QSK_CONFIG, QskDll): DEFINES += QSK_MAKEDLL QSK_SUBDIRS = common graphic nodes controls layouts dialogs inputpanel @@ -107,7 +111,6 @@ HEADERS += \ nodes/QskSGNode.h \ nodes/QskTextNode.h \ nodes/QskTextRenderer.h \ - nodes/QskTextureNode.h \ nodes/QskTextureRenderer.h \ nodes/QskTickmarksNode.h \ nodes/QskVertex.h @@ -128,7 +131,6 @@ SOURCES += \ nodes/QskSGNode.cpp \ nodes/QskTextNode.cpp \ nodes/QskTextRenderer.cpp \ - nodes/QskTextureNode.cpp \ nodes/QskTextureRenderer.cpp \ nodes/QskTickmarksNode.cpp \ nodes/QskVertex.cpp diff --git a/tests/checkboxes/target_wrapper.sh b/tests/checkboxes/target_wrapper.sh deleted file mode 100755 index 88cc3928..00000000 --- a/tests/checkboxes/target_wrapper.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -LD_LIBRARY_PATH=/home/uwe/qskinny/config/qsk1/Qt/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} -export LD_LIBRARY_PATH -QT_PLUGIN_PATH=/home/uwe/qskinny/config/qsk1/Qt/plugins${QT_PLUGIN_PATH:+:$QT_PLUGIN_PATH} -export QT_PLUGIN_PATH -exec "$@"