QskPaintedNode improved
This commit is contained in:
parent
c291cde259
commit
e1a58f84ee
|
@ -4,7 +4,19 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#include "QskArcNode.h"
|
#include "QskArcNode.h"
|
||||||
|
#include "QskArcMetrics.h"
|
||||||
#include "QskArcRenderer.h"
|
#include "QskArcRenderer.h"
|
||||||
|
#include "QskGradient.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class ArcData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const QskArcMetrics& metrics;
|
||||||
|
const QskGradient& gradient;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
QskArcNode::QskArcNode()
|
QskArcNode::QskArcNode()
|
||||||
{
|
{
|
||||||
|
@ -17,26 +29,28 @@ QskArcNode::~QskArcNode()
|
||||||
void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& metrics,
|
void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& metrics,
|
||||||
const QskGradient& gradient, QQuickWindow* window )
|
const QskGradient& gradient, QQuickWindow* window )
|
||||||
{
|
{
|
||||||
m_metrics = metrics;
|
const ArcData arcData { metrics, gradient };
|
||||||
m_gradient = gradient;
|
update( window, rect.toRect(), &arcData );
|
||||||
|
|
||||||
update( window, QskTextureRenderer::AutoDetect, rect.toRect() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskArcNode::paint( QPainter* painter, const QSizeF& size )
|
void QskArcNode::paint( QPainter* painter, const QSizeF& 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 );
|
const QRectF rect( 0.5 * w, 0.5 * w, size.width() - w, size.height() - w );
|
||||||
|
|
||||||
QskArcRenderer renderer;
|
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 );
|
h = stop.hash( h );
|
||||||
|
|
||||||
return h;
|
return h;
|
||||||
|
|
|
@ -6,10 +6,13 @@
|
||||||
#ifndef QSK_ARC_NODE_H
|
#ifndef QSK_ARC_NODE_H
|
||||||
#define QSK_ARC_NODE_H
|
#define QSK_ARC_NODE_H
|
||||||
|
|
||||||
#include "QskArcMetrics.h"
|
|
||||||
#include "QskGradient.h"
|
|
||||||
#include "QskPaintedNode.h"
|
#include "QskPaintedNode.h"
|
||||||
|
|
||||||
|
class QskArcMetrics;
|
||||||
|
class QskGradient;
|
||||||
|
|
||||||
|
// should be a QSGGeometryNode, TODO ..
|
||||||
|
|
||||||
class QSK_EXPORT QskArcNode : public QskPaintedNode
|
class QSK_EXPORT QskArcNode : public QskPaintedNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -19,12 +22,9 @@ class QSK_EXPORT QskArcNode : public QskPaintedNode
|
||||||
void setArcData( const QRectF&, const QskArcMetrics&,
|
void setArcData( const QRectF&, const QskArcMetrics&,
|
||||||
const QskGradient&, QQuickWindow* );
|
const QskGradient&, QQuickWindow* );
|
||||||
|
|
||||||
void paint( QPainter* painter, const QSizeF& size ) override;
|
protected:
|
||||||
QskHashValue hash() const override;
|
void paint( QPainter*, const QSizeF&, const void* nodeData ) override;
|
||||||
|
QskHashValue hash( const void* nodeData ) const override;
|
||||||
private:
|
|
||||||
QskArcMetrics m_metrics;
|
|
||||||
QskGradient m_gradient;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -22,7 +22,11 @@ QSK_QT_PRIVATE_END
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
|
||||||
|
#include <qquickopenglutils.h>
|
||||||
|
|
||||||
|
QSK_QT_PRIVATE_BEGIN
|
||||||
#include <private/qopenglframebufferobject_p.h>
|
#include <private/qopenglframebufferobject_p.h>
|
||||||
|
QSK_QT_PRIVATE_END
|
||||||
|
|
||||||
static GLuint qskTakeTexture( QOpenGLFramebufferObject& fbo )
|
static GLuint qskTakeTexture( QOpenGLFramebufferObject& fbo )
|
||||||
{
|
{
|
||||||
|
@ -76,10 +80,12 @@ namespace
|
||||||
{
|
{
|
||||||
const quint8 imageRole = 250; // reserved for internal use
|
const quint8 imageRole = 250; // reserved for internal use
|
||||||
|
|
||||||
inline QSGImageNode* findImageNode( QSGNode* parentNode )
|
inline QSGImageNode* findImageNode( const QSGNode* parentNode )
|
||||||
{
|
{
|
||||||
return static_cast< QSGImageNode* >(
|
auto node = QskSGNode::findChildNode(
|
||||||
QskSGNode::findChildNode( parentNode, imageRole ) );
|
const_cast< QSGNode* >( parentNode ), imageRole );
|
||||||
|
|
||||||
|
return static_cast< QSGImageNode* >( node );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool qskHasOpenGLRenderer( QQuickWindow* window )
|
static inline bool qskHasOpenGLRenderer( QQuickWindow* window )
|
||||||
|
@ -108,8 +114,24 @@ QskPaintedNode::~QskPaintedNode()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QskPaintedNode::setRenderHint( RenderHint renderHint )
|
||||||
|
{
|
||||||
|
m_renderHint = renderHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
QskPaintedNode::RenderHint QskPaintedNode::renderHint() const
|
||||||
|
{
|
||||||
|
return m_renderHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF QskPaintedNode::rect() const
|
||||||
|
{
|
||||||
|
const auto imageNode = findImageNode( this );
|
||||||
|
return imageNode ? imageNode->rect() : QRectF();
|
||||||
|
}
|
||||||
|
|
||||||
void QskPaintedNode::update( QQuickWindow* window,
|
void QskPaintedNode::update( QQuickWindow* window,
|
||||||
QskTextureRenderer::RenderMode renderMode, const QRectF& rect )
|
const QRectF& rect, const void* nodeData )
|
||||||
{
|
{
|
||||||
auto imageNode = findImageNode( this );
|
auto imageNode = findImageNode( this );
|
||||||
|
|
||||||
|
@ -120,12 +142,13 @@ void QskPaintedNode::update( QQuickWindow* window,
|
||||||
removeChildNode( imageNode );
|
removeChildNode( imageNode );
|
||||||
delete imageNode;
|
delete imageNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
bool isDirty = false;
|
bool isDirty = false;
|
||||||
|
|
||||||
const auto newHash = hash();
|
const auto newHash = hash( nodeData );
|
||||||
if ( ( newHash == 0 ) || ( newHash != m_hash ) )
|
if ( ( newHash == 0 ) || ( newHash != m_hash ) )
|
||||||
{
|
{
|
||||||
m_hash = newHash;
|
m_hash = newHash;
|
||||||
|
@ -137,21 +160,15 @@ void QskPaintedNode::update( QQuickWindow* window,
|
||||||
|
|
||||||
if ( isDirty )
|
if ( isDirty )
|
||||||
{
|
{
|
||||||
if ( renderMode != QskTextureRenderer::Raster )
|
if ( ( m_renderHint == OpenGL ) && qskHasOpenGLRenderer( window ) )
|
||||||
{
|
updateImageNodeGL( window, rect, nodeData );
|
||||||
if ( !qskHasOpenGLRenderer( window ) )
|
|
||||||
renderMode = QskTextureRenderer::Raster;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( renderMode == QskTextureRenderer::Raster )
|
|
||||||
updateImageNode( window, rect );
|
|
||||||
else
|
else
|
||||||
updateImageNodeGL( window, rect );
|
updateImageNode( window, rect, nodeData );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskPaintedNode::updateImageNode( QQuickWindow* window, const QRectF& rect )
|
void QskPaintedNode::updateImageNode(
|
||||||
|
QQuickWindow* window, const QRectF& rect, const void* nodeData )
|
||||||
{
|
{
|
||||||
const auto ratio = window->effectiveDevicePixelRatio();
|
const auto ratio = window->effectiveDevicePixelRatio();
|
||||||
const auto size = rect.size() * ratio;
|
const auto size = rect.size() * ratio;
|
||||||
|
@ -167,7 +184,7 @@ void QskPaintedNode::updateImageNode( QQuickWindow* window, const QRectF& rect )
|
||||||
value >= 1.0. So we have to scale manually.
|
value >= 1.0. So we have to scale manually.
|
||||||
*/
|
*/
|
||||||
painter.scale( ratio, ratio );
|
painter.scale( ratio, ratio );
|
||||||
paint( &painter, rect.size() );
|
paint( &painter, rect.size(), nodeData );
|
||||||
}
|
}
|
||||||
|
|
||||||
auto imageNode = findImageNode( this );
|
auto imageNode = findImageNode( this );
|
||||||
|
@ -190,7 +207,8 @@ void QskPaintedNode::updateImageNode( QQuickWindow* window, const QRectF& rect )
|
||||||
imageNode->setRect( rect );
|
imageNode->setRect( rect );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskPaintedNode::updateImageNodeGL( QQuickWindow* window, const QRectF& rect )
|
void QskPaintedNode::updateImageNodeGL(
|
||||||
|
QQuickWindow* window, const QRectF& rect, const void* nodeData )
|
||||||
{
|
{
|
||||||
const auto ratio = window->effectiveDevicePixelRatio();
|
const auto ratio = window->effectiveDevicePixelRatio();
|
||||||
const QSize size( ratio * rect.width(), ratio * rect.height() );
|
const QSize size( ratio * rect.width(), ratio * rect.height() );
|
||||||
|
@ -217,7 +235,12 @@ void QskPaintedNode::updateImageNodeGL( QQuickWindow* window, const QRectF& rect
|
||||||
imageNode->setTexture( texture );
|
imageNode->setTexture( texture );
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto textureId = createTexture( window, size );
|
/*
|
||||||
|
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;
|
auto rhi = QQuickWindowPrivate::get( window )->rhi;
|
||||||
|
|
||||||
|
@ -241,9 +264,28 @@ void QskPaintedNode::updateImageNodeGL( QQuickWindow* window, const QRectF& rect
|
||||||
imageNode->setRect( rect );
|
imageNode->setRect( rect );
|
||||||
}
|
}
|
||||||
|
|
||||||
// this method will be moved to QskTextureRenderer. TODO ...
|
uint32_t QskPaintedNode::createTexture(
|
||||||
uint32_t QskPaintedNode::createTexture( QQuickWindow* window, const QSize& size )
|
QQuickWindow* window, const QSize& size, const void* nodeData )
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
window->beginExternalCommands();
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
QQuickOpenGLUtils::resetOpenGLState();
|
||||||
|
#else
|
||||||
|
window->resetOpenGLState();
|
||||||
|
#endif
|
||||||
|
|
||||||
auto context = QOpenGLContext::currentContext();
|
auto context = QOpenGLContext::currentContext();
|
||||||
|
|
||||||
QOpenGLFramebufferObjectFormat format1;
|
QOpenGLFramebufferObjectFormat format1;
|
||||||
|
@ -257,13 +299,6 @@ uint32_t QskPaintedNode::createTexture( QQuickWindow* window, const QSize& size
|
||||||
pd.setPaintFlipped( true );
|
pd.setPaintFlipped( true );
|
||||||
|
|
||||||
{
|
{
|
||||||
int bufferId;
|
|
||||||
|
|
||||||
auto gl = context->functions();
|
|
||||||
|
|
||||||
gl->glGetIntegerv( GL_ARRAY_BUFFER_BINDING, &bufferId);
|
|
||||||
gl->glBindBuffer( GL_ARRAY_BUFFER, 0 );
|
|
||||||
|
|
||||||
const auto ratio = window->effectiveDevicePixelRatio();
|
const auto ratio = window->effectiveDevicePixelRatio();
|
||||||
|
|
||||||
QPainter painter( &pd );
|
QPainter painter( &pd );
|
||||||
|
@ -273,9 +308,7 @@ uint32_t QskPaintedNode::createTexture( QQuickWindow* window, const QSize& size
|
||||||
painter.fillRect( 0, 0, size.width(), size.height(), Qt::transparent );
|
painter.fillRect( 0, 0, size.width(), size.height(), Qt::transparent );
|
||||||
painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
|
painter.setCompositionMode( QPainter::CompositionMode_SourceOver );
|
||||||
|
|
||||||
paint( &painter, size );
|
paint( &painter, size, nodeData );
|
||||||
|
|
||||||
gl->glBindBuffer( GL_ARRAY_BUFFER, bufferId );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QOpenGLFramebufferObjectFormat format2;
|
QOpenGLFramebufferObjectFormat format2;
|
||||||
|
@ -288,5 +321,7 @@ uint32_t QskPaintedNode::createTexture( QQuickWindow* window, const QSize& size
|
||||||
QOpenGLFramebufferObject::blitFramebuffer(
|
QOpenGLFramebufferObject::blitFramebuffer(
|
||||||
&fbo, fboRect, &multisampledFbo, fboRect );
|
&fbo, fboRect, &multisampledFbo, fboRect );
|
||||||
|
|
||||||
|
window->endExternalCommands();
|
||||||
|
|
||||||
return qskTakeTexture( fbo );
|
return qskTakeTexture( fbo );
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,31 +6,56 @@
|
||||||
#ifndef QSK_PAINTED_NODE_H
|
#ifndef QSK_PAINTED_NODE_H
|
||||||
#define QSK_PAINTED_NODE_H
|
#define QSK_PAINTED_NODE_H
|
||||||
|
|
||||||
#include "QskTextureRenderer.h"
|
#include "QskGlobal.h"
|
||||||
#include <qsgnode.h>
|
#include <qsgnode.h>
|
||||||
|
|
||||||
|
class QQuickWindow;
|
||||||
|
class QPainter;
|
||||||
|
|
||||||
class QSK_EXPORT QskPaintedNode : public QSGNode
|
class QSK_EXPORT QskPaintedNode : public QSGNode
|
||||||
{
|
{
|
||||||
public:
|
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();
|
||||||
~QskPaintedNode() override;
|
~QskPaintedNode() override;
|
||||||
|
|
||||||
void update( QQuickWindow*,
|
void setRenderHint( RenderHint );
|
||||||
QskTextureRenderer::RenderMode, const QRectF& );
|
RenderHint renderHint() const;
|
||||||
|
|
||||||
|
QRectF rect() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void paint( QPainter*, const QSizeF& ) = 0;
|
void update( QQuickWindow*, const QRectF&, const void* nodeData );
|
||||||
|
|
||||||
|
virtual void paint( QPainter*, const QSizeF&, const void* nodeData ) = 0;
|
||||||
|
|
||||||
// a hash value of '0' always results in repainting
|
// a hash value of '0' always results in repainting
|
||||||
virtual QskHashValue hash() const = 0;
|
virtual QskHashValue hash( const void* nodeData ) const = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateImageNode( QQuickWindow*, const QRectF& );
|
void updateImageNode( QQuickWindow*, const QRectF&, const void* nodeData );
|
||||||
void updateImageNodeGL( QQuickWindow*, const QRectF& );
|
void updateImageNodeGL( QQuickWindow*, const QRectF&, const void* nodeData );
|
||||||
|
|
||||||
uint32_t createTexture( QQuickWindow*, const QSize& );
|
uint32_t createTexture( QQuickWindow*, const QSize&, const void* nodeData );
|
||||||
|
|
||||||
QskHashValue m_hash;
|
RenderHint m_renderHint = OpenGL;
|
||||||
|
QskHashValue m_hash = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue