default graphic pipeline without native OpenGL calls.
code is QRHI compiant now
This commit is contained in:
parent
5dc4200cdc
commit
54b55c0324
@ -26,6 +26,5 @@ SUBDIRS += \
|
||||
boxes \
|
||||
buttons \
|
||||
frames \
|
||||
gbenchmark \
|
||||
glabels \
|
||||
messageboxQml
|
||||
|
@ -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 <QskGraphic.h>
|
||||
#include <QskGraphicIO.h>
|
||||
#include <QskColorFilter.h>
|
||||
#include <QskTextureRenderer.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QElapsedTimer>
|
||||
#include <QPainter>
|
||||
#include <QQuickWindow>
|
||||
#include <QStringList>
|
||||
#include <QSvgRenderer>
|
||||
|
||||
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;
|
||||
}
|
@ -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 );
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
CONFIG += qskexample
|
||||
|
||||
QT += svg
|
||||
|
||||
HEADERS += \
|
||||
Benchmark.h
|
||||
|
||||
SOURCES += \
|
||||
Benchmark.cpp \
|
||||
main.cpp
|
@ -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 <QskLinearBox.h>
|
||||
#include <QskPushButton.h>
|
||||
#include <QskWindow.h>
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QGuiApplication>
|
||||
|
||||
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();
|
||||
}
|
@ -113,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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -30,10 +30,10 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& metrics,
|
||||
const QskGradient& gradient, QQuickWindow* window )
|
||||
{
|
||||
const ArcData arcData { metrics, gradient };
|
||||
update( window, rect.toRect(), &arcData );
|
||||
update( window, rect, QSizeF(), &arcData );
|
||||
}
|
||||
|
||||
void QskArcNode::paint( QPainter* painter, const QSizeF& size, const void* nodeData )
|
||||
void QskArcNode::paint( QPainter* painter, const QSize& size, const void* nodeData )
|
||||
{
|
||||
const auto arcData = reinterpret_cast< const ArcData* >( nodeData );
|
||||
|
||||
|
@ -23,7 +23,7 @@ class QSK_EXPORT QskArcNode : public QskPaintedNode
|
||||
const QskGradient&, QQuickWindow* );
|
||||
|
||||
protected:
|
||||
void paint( QPainter*, const QSizeF&, const void* nodeData ) override;
|
||||
void paint( QPainter*, const QSize&, const void* nodeData ) override;
|
||||
QskHashValue hash( const void* nodeData ) const override;
|
||||
};
|
||||
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -5,65 +5,17 @@
|
||||
|
||||
#include "QskPaintedNode.h"
|
||||
#include "QskSGNode.h"
|
||||
#include "QskTextureRenderer.h"
|
||||
|
||||
#include <qsgimagenode.h>
|
||||
#include <qquickwindow.h>
|
||||
#include <qimage.h>
|
||||
#include <qpainter.h>
|
||||
|
||||
#include <qopenglframebufferobject.h>
|
||||
#include <qopenglpaintdevice.h>
|
||||
#include <qopenglfunctions.h>
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qsgplaintexture_p.h>
|
||||
#include <private/qquickwindow_p.h>
|
||||
#include <private/qopenglframebufferobject_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
||||
#include <qquickopenglutils.h>
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static inline QSGImageNode::TextureCoordinatesTransformMode
|
||||
qskEffectiveTransformMode( const Qt::Orientations mirrored )
|
||||
{
|
||||
@ -89,15 +41,6 @@ namespace
|
||||
|
||||
return static_cast< QSGImageNode* >( node );
|
||||
}
|
||||
|
||||
static inline bool qskHasOpenGLRenderer( QQuickWindow* window )
|
||||
{
|
||||
if ( window == nullptr )
|
||||
return false;
|
||||
|
||||
const auto renderer = window->rendererInterface();
|
||||
return renderer->graphicsApi() == QSGRendererInterface::OpenGL;
|
||||
}
|
||||
}
|
||||
|
||||
QskPaintedNode::QskPaintedNode()
|
||||
@ -137,6 +80,17 @@ 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();
|
||||
}
|
||||
|
||||
return QSize();
|
||||
}
|
||||
|
||||
QRectF QskPaintedNode::rect() const
|
||||
{
|
||||
const auto imageNode = findImageNode( this );
|
||||
@ -144,7 +98,7 @@ QRectF QskPaintedNode::rect() const
|
||||
}
|
||||
|
||||
void QskPaintedNode::update( QQuickWindow* window,
|
||||
const QRectF& rect, const void* nodeData )
|
||||
const QRectF& rect, const QSizeF& size, const void* nodeData )
|
||||
{
|
||||
auto imageNode = findImageNode( this );
|
||||
|
||||
@ -159,90 +113,55 @@ void QskPaintedNode::update( QQuickWindow* window,
|
||||
return;
|
||||
}
|
||||
|
||||
bool isDirty = false;
|
||||
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;
|
||||
isDirty = true;
|
||||
isTextureDirty = true;
|
||||
}
|
||||
|
||||
if ( !isDirty )
|
||||
isDirty = ( imageNode == nullptr ) || ( imageNode->rect() != rect );
|
||||
|
||||
if ( isDirty )
|
||||
{
|
||||
if ( ( m_renderHint == OpenGL ) && qskHasOpenGLRenderer( window ) )
|
||||
updateImageNodeGL( window, rect, nodeData );
|
||||
else
|
||||
updateImageNode( window, rect, nodeData );
|
||||
{
|
||||
isTextureDirty = ( imageSize != textureSize() );
|
||||
}
|
||||
|
||||
imageNode = findImageNode( this );
|
||||
if ( imageNode )
|
||||
{
|
||||
|
||||
if ( isTextureDirty )
|
||||
updateTexture( window, imageSize, nodeData );
|
||||
|
||||
imageNode->setRect( rect );
|
||||
imageNode->setTextureCoordinatesTransform(
|
||||
qskEffectiveTransformMode( m_mirrored ) );
|
||||
}
|
||||
}
|
||||
|
||||
void QskPaintedNode::updateImageNode(
|
||||
QQuickWindow* window, const QRectF& rect, const void* nodeData )
|
||||
void QskPaintedNode::updateTexture( QQuickWindow* window,
|
||||
const QSize& size, const void* nodeData )
|
||||
{
|
||||
const auto ratio = window->effectiveDevicePixelRatio();
|
||||
const auto size = rect.size() * ratio;
|
||||
|
||||
QImage image( size.toSize(), 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.
|
||||
*/
|
||||
painter.scale( ratio, ratio );
|
||||
paint( &painter, rect.size(), nodeData );
|
||||
}
|
||||
|
||||
auto imageNode = findImageNode( this );
|
||||
|
||||
if ( imageNode == nullptr )
|
||||
if ( ( m_renderHint == OpenGL ) && QskTextureRenderer::isOpenGLWindow( window ) )
|
||||
{
|
||||
imageNode = window->createImageNode();
|
||||
|
||||
imageNode->setOwnsTexture( true );
|
||||
QskSGNode::setNodeRole( imageNode, imageRole );
|
||||
|
||||
appendChildNode( imageNode );
|
||||
}
|
||||
|
||||
if ( auto texture = qobject_cast< QSGPlainTexture* >( imageNode->texture() ) )
|
||||
texture->setImage( image );
|
||||
else
|
||||
imageNode->setTexture( window->createTextureFromImage( image ) );
|
||||
}
|
||||
|
||||
void QskPaintedNode::updateImageNodeGL(
|
||||
QQuickWindow* window, const QRectF& rect, const void* nodeData )
|
||||
{
|
||||
const auto ratio = window->effectiveDevicePixelRatio();
|
||||
const QSize size( ratio * rect.width(), ratio * rect.height() );
|
||||
|
||||
auto imageNode = findImageNode( this );
|
||||
|
||||
if ( imageNode == nullptr )
|
||||
{
|
||||
imageNode = window->createImageNode();
|
||||
|
||||
imageNode->setOwnsTexture( true );
|
||||
QskSGNode::setNodeRole( imageNode, imageRole );
|
||||
|
||||
appendChildNode( imageNode );
|
||||
}
|
||||
const auto textureId = createTextureGL( window, size, nodeData );
|
||||
|
||||
auto texture = qobject_cast< QSGPlainTexture* >( imageNode->texture() );
|
||||
if ( texture == nullptr )
|
||||
@ -254,91 +173,63 @@ void QskPaintedNode::updateImageNodeGL(
|
||||
imageNode->setTexture( texture );
|
||||
}
|
||||
|
||||
/*
|
||||
QQuickFramebufferObject does the FBO rendering early
|
||||
( QQuickWindow::beforeRendering ). However doing it below updatePaintNode
|
||||
seems to work as well. Let's see if we run into issues ...
|
||||
*/
|
||||
const auto textureId = createTexture( window, size, nodeData );
|
||||
|
||||
auto rhi = QQuickWindowPrivate::get( window )->rhi;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
||||
texture->setTextureFromNativeTexture(
|
||||
rhi, quint64( textureId ), 0, size, {}, {} );
|
||||
#else
|
||||
if ( rhi )
|
||||
{
|
||||
// enabled with: "export QSG_RHI=1"
|
||||
texture->setTextureFromNativeObject( rhi,
|
||||
QQuickWindow::NativeObjectTexture, &textureId, 0, size, false );
|
||||
QskTextureRenderer::setTextureId( window, textureId, size, texture );
|
||||
}
|
||||
else
|
||||
{
|
||||
texture->setTextureId( textureId );
|
||||
texture->setTextureSize( size );
|
||||
const auto image = createImage( window, size, nodeData );
|
||||
|
||||
if ( auto texture = qobject_cast< QSGPlainTexture* >( imageNode->texture() ) )
|
||||
texture->setImage( image );
|
||||
else
|
||||
imageNode->setTexture( window->createTextureFromImage( image ) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t QskPaintedNode::createTexture(
|
||||
QQuickWindow* window, const QSize& size, const void* nodeData )
|
||||
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 );
|
||||
|
||||
/*
|
||||
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.
|
||||
setting a devicePixelRatio for the image only works for
|
||||
value >= 1.0. So we have to scale manually.
|
||||
*/
|
||||
|
||||
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 );
|
||||
|
||||
format1.setSamples( context->format().samples() );
|
||||
|
||||
QOpenGLFramebufferObject multisampledFbo( size, format1 );
|
||||
|
||||
QOpenGLPaintDevice pd( size );
|
||||
pd.setPaintFlipped( true );
|
||||
|
||||
{
|
||||
const auto ratio = window->effectiveDevicePixelRatio();
|
||||
|
||||
QPainter painter( &pd );
|
||||
painter.scale( ratio, ratio );
|
||||
|
||||
painter.setCompositionMode( QPainter::CompositionMode_Source );
|
||||
painter.fillRect( 0, 0, size.width(), size.height(), Qt::transparent );
|
||||
painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
|
||||
paint( &painter, size / ratio, nodeData );
|
||||
|
||||
paint( &painter, size, 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 )
|
||||
{
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObjectFormat format2;
|
||||
format2.setAttachment( QOpenGLFramebufferObject::NoAttachment );
|
||||
void paint( QPainter* painter, const QSize& size ) override
|
||||
{
|
||||
m_node->paint( painter, size, m_nodeData );
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject fbo( size, format2 );
|
||||
private:
|
||||
QskPaintedNode* m_node;
|
||||
const void* m_nodeData;
|
||||
};
|
||||
|
||||
const QRect fboRect( 0, 0, size.width(), size.height() );
|
||||
|
||||
QOpenGLFramebufferObject::blitFramebuffer(
|
||||
&fbo, fboRect, &multisampledFbo, fboRect );
|
||||
|
||||
window->endExternalCommands();
|
||||
|
||||
return qskTakeTexture( fbo );
|
||||
PaintHelper helper( this, nodeData );
|
||||
return createPaintedTextureGL( window, size, &helper );
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
class QQuickWindow;
|
||||
class QPainter;
|
||||
class QImage;
|
||||
|
||||
class QSK_EXPORT QskPaintedNode : public QSGNode
|
||||
{
|
||||
@ -42,20 +43,21 @@ class QSK_EXPORT QskPaintedNode : public QSGNode
|
||||
Qt::Orientations mirrored() const;
|
||||
|
||||
QRectF rect() const;
|
||||
QSize textureSize() const;
|
||||
|
||||
virtual void paint( QPainter*, const QSize&, const void* nodeData ) = 0;
|
||||
|
||||
protected:
|
||||
void update( QQuickWindow*, const QRectF&, const void* nodeData );
|
||||
|
||||
virtual void paint( QPainter*, const QSizeF&, const void* nodeData ) = 0;
|
||||
void update( QQuickWindow*, const QRectF&, const QSizeF&, const void* nodeData );
|
||||
|
||||
// a hash value of '0' always results in repainting
|
||||
virtual QskHashValue hash( const void* nodeData ) const = 0;
|
||||
|
||||
private:
|
||||
void updateImageNode( QQuickWindow*, const QRectF&, const void* nodeData );
|
||||
void updateImageNodeGL( QQuickWindow*, const QRectF&, const void* nodeData );
|
||||
void updateTexture( QQuickWindow*, const QSize&, const void* nodeData );
|
||||
|
||||
uint32_t createTexture( QQuickWindow*, const QSize&, const void* nodeData );
|
||||
QImage createImage( QQuickWindow*, const QSize&, const void* nodeData );
|
||||
quint32 createTextureGL( QQuickWindow*, const QSize&, const void* nodeData );
|
||||
|
||||
RenderHint m_renderHint = OpenGL;
|
||||
Qt::Orientations m_mirrored;
|
||||
|
@ -4,92 +4,177 @@
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskTextureRenderer.h"
|
||||
#include "QskColorFilter.h"
|
||||
#include "QskGraphic.h"
|
||||
#include "QskSetup.h"
|
||||
|
||||
#include <qopenglcontext.h>
|
||||
#include <qopenglextrafunctions.h>
|
||||
#include <qopenglframebufferobject.h>
|
||||
#include <qopenglfunctions.h>
|
||||
#include <qopenglpaintdevice.h>
|
||||
#include <qopengltexture.h>
|
||||
|
||||
#include <qimage.h>
|
||||
#include <qpainter.h>
|
||||
|
||||
#include <qquickwindow.h>
|
||||
#include <qsgtexture.h>
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qsgplaintexture_p.h>
|
||||
#include <private/qopenglframebufferobject_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
||||
#include <qsgtexture_platform.h>
|
||||
#include <qquickopenglutils.h>
|
||||
#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 +194,26 @@ static uint qskCreateTextureRaster( QQuickWindow* window,
|
||||
helper->paint( &painter, size );
|
||||
}
|
||||
|
||||
const auto target = QOpenGLTexture::Target2D;
|
||||
|
||||
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 ) )
|
||||
{
|
||||
auto& ef = *context->extraFunctions();
|
||||
ef.glTexStorage2D( target, 1,
|
||||
QOpenGLTexture::RGBA8_UNorm, image.width(), image.height() );
|
||||
|
||||
f.glTexSubImage2D( target, 0, 0, 0, image.width(), image.height(),
|
||||
QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.constBits() );
|
||||
}
|
||||
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;
|
||||
return window->createTextureFromImage( image, QQuickWindow::TextureHasAlphaChannel );
|
||||
}
|
||||
|
||||
QSGTexture* QskTextureRenderer::textureFromId(
|
||||
QQuickWindow* window, uint textureId, const QSize& size )
|
||||
QSGTexture* QskTextureRenderer::createPaintedTexture(
|
||||
QQuickWindow* window, const QSize& size, PaintHelper* helper )
|
||||
{
|
||||
const auto flags = static_cast< QQuickWindow::CreateTextureOptions >(
|
||||
QQuickWindow::TextureHasAlphaChannel | QQuickWindow::TextureOwnsGLTexture );
|
||||
if ( isOpenGLWindow( window ) )
|
||||
{
|
||||
const auto textureId = createPaintedTextureGL( window, size, helper );
|
||||
|
||||
QSGTexture* texture;
|
||||
auto texture = new QSGPlainTexture;
|
||||
texture->setHasAlphaChannel( true );
|
||||
texture->setOwnsTexture( true );
|
||||
|
||||
#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
|
||||
setTextureId( window, textureId, size, texture );
|
||||
|
||||
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 );
|
||||
}
|
||||
|
@ -7,35 +7,15 @@
|
||||
#define QSK_TEXTURE_RENDERER_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
#include <qnamespace.h>
|
||||
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user