QskPaintedNode improved
This commit is contained in:
parent
c291cde259
commit
e1a58f84ee
@ -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.toRect(), &arcData );
|
||||
}
|
||||
|
||||
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 );
|
||||
|
||||
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;
|
||||
|
@ -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 QSizeF&, const void* nodeData ) override;
|
||||
QskHashValue hash( const void* nodeData ) const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -22,7 +22,11 @@ QSK_QT_PRIVATE_END
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
||||
|
||||
#include <qquickopenglutils.h>
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qopenglframebufferobject_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
static GLuint qskTakeTexture( QOpenGLFramebufferObject& fbo )
|
||||
{
|
||||
@ -76,10 +80,12 @@ namespace
|
||||
{
|
||||
const quint8 imageRole = 250; // reserved for internal use
|
||||
|
||||
inline QSGImageNode* findImageNode( QSGNode* parentNode )
|
||||
inline QSGImageNode* findImageNode( const QSGNode* parentNode )
|
||||
{
|
||||
return static_cast< QSGImageNode* >(
|
||||
QskSGNode::findChildNode( parentNode, imageRole ) );
|
||||
auto node = QskSGNode::findChildNode(
|
||||
const_cast< QSGNode* >( parentNode ), imageRole );
|
||||
|
||||
return static_cast< QSGImageNode* >( node );
|
||||
}
|
||||
|
||||
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,
|
||||
QskTextureRenderer::RenderMode renderMode, const QRectF& rect )
|
||||
const QRectF& rect, const void* nodeData )
|
||||
{
|
||||
auto imageNode = findImageNode( this );
|
||||
|
||||
@ -120,38 +142,33 @@ void QskPaintedNode::update( QQuickWindow* window,
|
||||
removeChildNode( imageNode );
|
||||
delete imageNode;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
bool isDirty = false;
|
||||
|
||||
const auto newHash = hash( nodeData );
|
||||
if ( ( newHash == 0 ) || ( newHash != m_hash ) )
|
||||
{
|
||||
bool isDirty = false;
|
||||
m_hash = newHash;
|
||||
isDirty = true;
|
||||
}
|
||||
|
||||
const auto newHash = hash();
|
||||
if ( ( newHash == 0 ) || ( newHash != m_hash ) )
|
||||
{
|
||||
m_hash = newHash;
|
||||
isDirty = true;
|
||||
}
|
||||
if ( !isDirty )
|
||||
isDirty = ( imageNode == nullptr ) || ( imageNode->rect() != rect );
|
||||
|
||||
if ( !isDirty )
|
||||
isDirty = ( imageNode == nullptr ) || ( imageNode->rect() != rect );
|
||||
|
||||
if ( isDirty )
|
||||
{
|
||||
if ( renderMode != QskTextureRenderer::Raster )
|
||||
{
|
||||
if ( !qskHasOpenGLRenderer( window ) )
|
||||
renderMode = QskTextureRenderer::Raster;
|
||||
}
|
||||
|
||||
if ( renderMode == QskTextureRenderer::Raster )
|
||||
updateImageNode( window, rect );
|
||||
else
|
||||
updateImageNodeGL( window, rect );
|
||||
}
|
||||
if ( isDirty )
|
||||
{
|
||||
if ( ( m_renderHint == OpenGL ) && qskHasOpenGLRenderer( window ) )
|
||||
updateImageNodeGL( window, rect, nodeData );
|
||||
else
|
||||
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 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.
|
||||
*/
|
||||
painter.scale( ratio, ratio );
|
||||
paint( &painter, rect.size() );
|
||||
paint( &painter, rect.size(), nodeData );
|
||||
}
|
||||
|
||||
auto imageNode = findImageNode( this );
|
||||
@ -190,7 +207,8 @@ void QskPaintedNode::updateImageNode( QQuickWindow* window, const QRectF& 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 QSize size( ratio * rect.width(), ratio * rect.height() );
|
||||
@ -217,7 +235,12 @@ void QskPaintedNode::updateImageNodeGL( QQuickWindow* window, const QRectF& rect
|
||||
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;
|
||||
|
||||
@ -241,9 +264,28 @@ void QskPaintedNode::updateImageNodeGL( QQuickWindow* window, const QRectF& rect
|
||||
imageNode->setRect( rect );
|
||||
}
|
||||
|
||||
// this method will be moved to QskTextureRenderer. TODO ...
|
||||
uint32_t QskPaintedNode::createTexture( QQuickWindow* window, const QSize& size )
|
||||
uint32_t QskPaintedNode::createTexture(
|
||||
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();
|
||||
|
||||
QOpenGLFramebufferObjectFormat format1;
|
||||
@ -257,13 +299,6 @@ uint32_t QskPaintedNode::createTexture( QQuickWindow* window, const QSize& size
|
||||
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();
|
||||
|
||||
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.setCompositionMode( QPainter::CompositionMode_SourceOver );
|
||||
|
||||
paint( &painter, size );
|
||||
|
||||
gl->glBindBuffer( GL_ARRAY_BUFFER, bufferId );
|
||||
paint( &painter, size, nodeData );
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObjectFormat format2;
|
||||
@ -288,5 +321,7 @@ uint32_t QskPaintedNode::createTexture( QQuickWindow* window, const QSize& size
|
||||
QOpenGLFramebufferObject::blitFramebuffer(
|
||||
&fbo, fboRect, &multisampledFbo, fboRect );
|
||||
|
||||
window->endExternalCommands();
|
||||
|
||||
return qskTakeTexture( fbo );
|
||||
}
|
||||
|
@ -6,31 +6,56 @@
|
||||
#ifndef QSK_PAINTED_NODE_H
|
||||
#define QSK_PAINTED_NODE_H
|
||||
|
||||
#include "QskTextureRenderer.h"
|
||||
#include "QskGlobal.h"
|
||||
#include <qsgnode.h>
|
||||
|
||||
class QQuickWindow;
|
||||
class QPainter;
|
||||
|
||||
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 QRectF& );
|
||||
void setRenderHint( RenderHint );
|
||||
RenderHint renderHint() const;
|
||||
|
||||
QRectF rect() const;
|
||||
|
||||
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
|
||||
virtual QskHashValue hash() const = 0;
|
||||
virtual QskHashValue hash( const void* nodeData ) const = 0;
|
||||
|
||||
private:
|
||||
void updateImageNode( QQuickWindow*, const QRectF& );
|
||||
void updateImageNodeGL( QQuickWindow*, const QRectF& );
|
||||
void updateImageNode( QQuickWindow*, const QRectF&, const void* nodeData );
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user