6#include "QskSceneTexture.h"
7#include "QskTreeNode.h"
12#include <private/qquickwindow_p.h>
13#include <private/qsgtexture_p.h>
15#define QT_BUILD_QUICK_LIB
16#include <private/qsgbatchrenderer_p.h>
17#undef QT_BUILD_QUICK_LIB
28#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
29#include <qopenglframebufferobject.h>
32static int qskRenderOrderCompare(
const QSGNode* rootNode,
33 const QSGNode* node1,
const QSGNode* node2 )
35 if ( rootNode == node1 )
38 if ( rootNode == node2 )
41 for (
auto node = rootNode->firstChild();
42 node !=
nullptr; node = node->nextSibling() )
44 const auto ret = qskRenderOrderCompare( node, node1, node2 );
54#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
55 inline QSGRendererInterface::RenderMode contextRenderMode(
56 QSGDefaultRenderContext* context )
58 return context->useDepthBufferFor2D()
59 ? QSGRendererInterface::RenderMode2D
60 : QSGRendererInterface::RenderMode2DNoDepthBuffer;
64 class Renderer final :
public QSGBatchRenderer::Renderer
66 using Inherited = QSGBatchRenderer::Renderer;
72#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
73 inline int textureId()
const {
return m_fbo ? m_fbo->texture() : 0; }
75 inline void renderScene()
77 class Bindable :
public QSGBindable
80 Bindable( QOpenGLFramebufferObject* fbo ) : m_fbo( fbo ) {}
81 void bind()
const override { m_fbo->bind(); }
83 QOpenGLFramebufferObject* m_fbo;
86 Inherited::renderScene( Bindable( m_fbo ) );
90 inline QRhiTexture* rhiTexture()
const {
return m_rhiTexture; }
92 inline bool isDirty()
const {
return m_dirty; }
94 void setFinalNode( QSGTransformNode* );
96 void setProjection(
const QRectF& );
97 void setTextureSize(
const QSize& );
98 QSize textureSize()
const;
101 void nodeChanged( QSGNode*, QSGNode::DirtyState )
override;
102 void render()
override;
105 void createTarget(
const QSize& );
109 QSGTransformNode* m_finalNode =
nullptr;
112#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
113 QOpenGLFramebufferObject* m_fbo =
nullptr;
116#if QT_VERSION < QT_VERSION_CHECK( 6, 4, 0 )
119 QRhiRenderTarget* rt =
nullptr;
120 QRhiRenderPassDescriptor* rpDesc =
nullptr;
121 QRhiCommandBuffer* cb =
nullptr;
124 QRhiTexture* m_rhiTexture =
nullptr;
129 Renderer::Renderer(
QskSceneTexture* texture, QSGDefaultRenderContext* context )
130#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
131 : Inherited( context )
133 : Inherited( context, contextRenderMode( context ) )
135 , m_texture( texture )
137 setClearColor( Qt::transparent );
139 connect(
this, &QSGRenderer::sceneGraphChanged,
140 this, &Renderer::markDirty );
143 Renderer::~Renderer()
148 void Renderer::setFinalNode( QSGTransformNode* node )
150 if ( node != m_finalNode )
157 void Renderer::setProjection(
const QRectF& rect )
159 bool flipFramebuffer =
true;
160 bool flipMatrix =
false;
162 if (
const auto rhi = context()->rhi() )
164 flipFramebuffer = rhi->isYUpInFramebuffer();
165 flipMatrix = !rhi->isYUpInNDC();
170 if ( flipFramebuffer )
172 r.moveTop( r.bottom() );
173 r.setHeight( -r.height() );
176 MatrixTransformFlags matrixFlags;
179 matrixFlags |= QSGAbstractRenderer::MatrixTransformFlipY;
181 setProjectionMatrixToRect( r, matrixFlags );
184 void Renderer::setTextureSize(
const QSize& size )
186 if (
const auto rhi = context()->rhi() )
188 if ( m_rt.rt && m_rt.rt->pixelSize() != size )
191 if ( m_rt.rt ==
nullptr )
192 createTarget( size );
196#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
197 if ( m_fbo && m_fbo->size() != size )
200 if ( m_fbo ==
nullptr )
201 createTarget( size );
205 const QRect r( 0, 0, size.width(), size.height() );
208 setViewportRect( r );
211 QSize Renderer::textureSize()
const
213#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
214 if ( m_fbo )
return m_fbo->size();
216 if( m_rt.rt )
return m_rt.rt->pixelSize();
221 void Renderer::render()
225 qskTryBlockTrailingNodes( m_finalNode, rootNode(),
true,
false );
228 static int counter = 0;
229 qDebug() << ++counter;
230 QSGNodeDumper::dump( rootNode() );
233 qskTryBlockTrailingNodes( m_finalNode, rootNode(),
false,
false );
236 void Renderer::nodeChanged( QSGNode* node, QSGNode::DirtyState state )
247 if ( qskRenderOrderCompare( rootNode(), node, m_finalNode ) > 0 )
250 Inherited::nodeChanged( node, state );
254 void Renderer::markDirty()
259 Q_EMIT m_texture->updateRequested();
263 void Renderer::createTarget(
const QSize& size )
265 if (
const auto rhi = context()->rhi() )
267 auto flags = QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource;
269 m_rhiTexture = rhi->newTexture( QRhiTexture::RGBA8, size, 1, flags );
270#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
271 m_rhiTexture->build();
273 m_rhiTexture->create();
276 QRhiColorAttachment color0( m_rhiTexture );
277 auto target = rhi->newTextureRenderTarget( { color0 } );
279 target->setRenderPassDescriptor(
280 target->newCompatibleRenderPassDescriptor() );
282#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
289 m_rt.rpDesc = target->renderPassDescriptor();
291 auto defaultContext = qobject_cast< QSGDefaultRenderContext* >( context() );
292 m_rt.cb = defaultContext->currentFrameCommandBuffer();
294#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
295 setRenderTarget( m_rt.rt );
296 setCommandBuffer( m_rt.cb );
297 setRenderPassDescriptor( m_rt.rpDesc );
302#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
303 QOpenGLFramebufferObjectFormat format;
304 format.setInternalTextureFormat( GL_RGBA8 );
305 format.setSamples( 0 );
306 format.setAttachment( QOpenGLFramebufferObject::CombinedDepthStencil );
308 m_fbo =
new QOpenGLFramebufferObject( size, format );
313 void Renderer::clearTarget()
315 if (
const auto rhi = context()->rhi() )
321 m_rt.rpDesc =
nullptr;
324 m_rhiTexture =
nullptr;
328#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
336class QskSceneTexturePrivate final :
public QSGTexturePrivate
339 QskSceneTexturePrivate(
const QQuickWindow* window,
QskSceneTexture* texture )
340#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
341 : QSGTexturePrivate()
343 : QSGTexturePrivate( texture )
345 , devicePixelRatio( window->effectiveDevicePixelRatio() )
350 auto dw = QQuickWindowPrivate::get(
const_cast< QQuickWindow*
>( window ) );
351 context =
dynamic_cast< QSGDefaultRenderContext*
>( dw->context );
354#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
355 int comparisonKey()
const override
359 if ( renderer->textureId() )
360 return renderer->textureId();
362 if ( renderer->rhiTexture() )
363 return int( qintptr( renderer->rhiTexture() ) );
366 return int( qintptr(
this ) );
369 QRhiTexture *rhiTexture()
const override
370 {
return renderer ? renderer->rhiTexture() :
nullptr; }
373 QSize pixelSize()
const
375 QSize size( qCeil( rect.width() ), qCeil( rect.height() ) );
376 size *= devicePixelRatio;
378 const QSize minSize = context->sceneGraphContext()->minimumFBOSize();
380 while ( size.width() < minSize.width() )
383 while ( size.height() < minSize.height() )
390 const qreal devicePixelRatio;
392 Renderer* renderer =
nullptr;
393 QSGDefaultRenderContext* context =
nullptr;
396QskSceneTexture::QskSceneTexture(
const QQuickWindow* window )
397 : Inherited( *new QskSceneTexturePrivate( window, this ) )
399 Q_ASSERT( d_func()->context );
402QskSceneTexture::~QskSceneTexture()
404 delete d_func()->renderer;
407QSize QskSceneTexture::textureSize()
const
410 return d->renderer ? d->renderer->textureSize() : QSize();
413void QskSceneTexture::render(
const QSGRootNode* rootNode,
414 const QSGTransformNode* finalNode,
const QRectF& rect )
420 if ( d->renderer ==
nullptr )
422 d->renderer =
new Renderer(
this, d->context );
423 d->renderer->setDevicePixelRatio( d->devicePixelRatio );
426 d->renderer->setRootNode(
const_cast< QSGRootNode*
>( rootNode ) );
427 d->renderer->setFinalNode(
const_cast< QSGTransformNode*
>( finalNode ) );
429 d->renderer->setProjection( d->rect );
430 d->renderer->setTextureSize( d->pixelSize() );
431 d->renderer->renderScene();
434bool QskSceneTexture::isDirty()
const
437 return d->renderer ? d->renderer->isDirty() :
true;
440QRectF QskSceneTexture::normalizedTextureSubRect()
const
442 return QRectF( 0, 1, 1, -1 );
445bool QskSceneTexture::hasAlphaChannel()
const
450bool QskSceneTexture::hasMipmaps()
const
455#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
457void QskSceneTexture::bind()
459 if ( d_func()->rhiTexture() ==
nullptr )
461 auto funcs = QOpenGLContext::currentContext()->functions();
462 funcs->glBindTexture( GL_TEXTURE_2D, textureId() );
468int QskSceneTexture::textureId()
const
471 return d->renderer ? d->renderer->textureId() : 0;
476qint64 QskSceneTexture::comparisonKey()
const
478 return qint64( rhiTexture() );
481QRhiTexture* QskSceneTexture::rhiTexture()
const
484 return d->renderer ? d->renderer->rhiTexture() :
nullptr;
489#include "moc_QskSceneTexture.cpp"