6#include "QskSceneTexture.h"
7#include "QskTreeNode.h"
8#include "QskInternalMacros.h"
13#include <private/qquickwindow_p.h>
14#include <private/qsgtexture_p.h>
16#define QT_BUILD_QUICK_LIB
17#include <private/qsgbatchrenderer_p.h>
18#undef QT_BUILD_QUICK_LIB
29#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
30#include <qopenglframebufferobject.h>
33static int qskRenderOrderCompare(
const QSGNode* rootNode,
34 const QSGNode* node1,
const QSGNode* node2 )
36 if ( rootNode == node1 )
39 if ( rootNode == node2 )
42 for (
auto node = rootNode->firstChild();
43 node !=
nullptr; node = node->nextSibling() )
45 const auto ret = qskRenderOrderCompare( node, node1, node2 );
55#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
56 inline QSGRendererInterface::RenderMode contextRenderMode(
57 QSGDefaultRenderContext* context )
59 return context->useDepthBufferFor2D()
60 ? QSGRendererInterface::RenderMode2D
61 : QSGRendererInterface::RenderMode2DNoDepthBuffer;
65 class Renderer final :
public QSGBatchRenderer::Renderer
67 using Inherited = QSGBatchRenderer::Renderer;
73#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
74 inline int textureId()
const {
return m_fbo ? m_fbo->texture() : 0; }
76 inline void renderScene()
78 class Bindable :
public QSGBindable
81 Bindable( QOpenGLFramebufferObject* fbo ) : m_fbo( fbo ) {}
82 void bind()
const override { m_fbo->bind(); }
84 QOpenGLFramebufferObject* m_fbo;
87 Inherited::renderScene( Bindable( m_fbo ) );
91 inline QRhiTexture* rhiTexture()
const {
return m_rhiTexture; }
93 inline bool isDirty()
const {
return m_dirty; }
95 void setFinalNode( QSGTransformNode* );
97 void setProjection(
const QRectF& );
98 void setTextureSize(
const QSize& );
99 QSize textureSize()
const;
102 void nodeChanged( QSGNode*, QSGNode::DirtyState )
override;
103 void render()
override;
106 void createTarget(
const QSize& );
110 QSGTransformNode* m_finalNode =
nullptr;
113#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
114 QOpenGLFramebufferObject* m_fbo =
nullptr;
117#if QT_VERSION < QT_VERSION_CHECK( 6, 4, 0 )
120 QRhiRenderTarget* rt =
nullptr;
121 QRhiRenderPassDescriptor* rpDesc =
nullptr;
122 QRhiCommandBuffer* cb =
nullptr;
125 QRhiTexture* m_rhiTexture =
nullptr;
130 Renderer::Renderer(
QskSceneTexture* texture, QSGDefaultRenderContext* context )
131#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
132 : Inherited( context )
134 : Inherited( context, contextRenderMode( context ) )
136 , m_texture( texture )
138 setClearColor( Qt::transparent );
140 connect(
this, &QSGRenderer::sceneGraphChanged,
141 this, &Renderer::markDirty );
144 Renderer::~Renderer()
149 void Renderer::setFinalNode( QSGTransformNode* node )
151 if ( node != m_finalNode )
158 void Renderer::setProjection(
const QRectF& rect )
160 bool flipFramebuffer =
true;
161 bool flipMatrix =
false;
163 if (
const auto rhi = context()->rhi() )
165 flipFramebuffer = rhi->isYUpInFramebuffer();
166 flipMatrix = !rhi->isYUpInNDC();
171 if ( flipFramebuffer )
173 r.moveTop( r.bottom() );
174 r.setHeight( -r.height() );
177 MatrixTransformFlags matrixFlags;
180 matrixFlags |= QSGAbstractRenderer::MatrixTransformFlipY;
182 setProjectionMatrixToRect( r, matrixFlags );
185 void Renderer::setTextureSize(
const QSize& size )
187 if (
const auto rhi = context()->rhi() )
189 if ( m_rt.rt && m_rt.rt->pixelSize() != size )
192 if ( m_rt.rt ==
nullptr )
193 createTarget( size );
197#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
198 if ( m_fbo && m_fbo->size() != size )
201 if ( m_fbo ==
nullptr )
202 createTarget( size );
206 const QRect r( 0, 0, size.width(), size.height() );
209 setViewportRect( r );
212 QSize Renderer::textureSize()
const
214#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
215 if ( m_fbo )
return m_fbo->size();
217 if( m_rt.rt )
return m_rt.rt->pixelSize();
222 void Renderer::render()
226 qskTryBlockTrailingNodes( m_finalNode, rootNode(),
true,
false );
229 static int counter = 0;
230 qDebug() << ++counter;
231 QSGNodeDumper::dump( rootNode() );
234 qskTryBlockTrailingNodes( m_finalNode, rootNode(),
false,
false );
237 void Renderer::nodeChanged( QSGNode* node, QSGNode::DirtyState state )
248 if ( qskRenderOrderCompare( rootNode(), node, m_finalNode ) > 0 )
251 Inherited::nodeChanged( node, state );
255 void Renderer::markDirty()
260 Q_EMIT m_texture->updateRequested();
264 void Renderer::createTarget(
const QSize& size )
266 if (
const auto rhi = context()->rhi() )
268 auto flags = QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource;
270 m_rhiTexture = rhi->newTexture( QRhiTexture::RGBA8, size, 1, flags );
271#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
272 m_rhiTexture->build();
274 m_rhiTexture->create();
277 QRhiColorAttachment color0( m_rhiTexture );
278 auto target = rhi->newTextureRenderTarget( { color0 } );
280 target->setRenderPassDescriptor(
281 target->newCompatibleRenderPassDescriptor() );
283#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
290 m_rt.rpDesc = target->renderPassDescriptor();
292 auto defaultContext = qobject_cast< QSGDefaultRenderContext* >( context() );
293 m_rt.cb = defaultContext->currentFrameCommandBuffer();
295#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
296 setRenderTarget( m_rt.rt );
297 setCommandBuffer( m_rt.cb );
298 setRenderPassDescriptor( m_rt.rpDesc );
303#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
304 QOpenGLFramebufferObjectFormat format;
305 format.setInternalTextureFormat( GL_RGBA8 );
306 format.setSamples( 0 );
307 format.setAttachment( QOpenGLFramebufferObject::CombinedDepthStencil );
309 m_fbo =
new QOpenGLFramebufferObject( size, format );
314 void Renderer::clearTarget()
316 if (
const auto rhi = context()->rhi() )
322 m_rt.rpDesc =
nullptr;
325 m_rhiTexture =
nullptr;
329#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
337class QskSceneTexturePrivate final :
public QSGTexturePrivate
340 QskSceneTexturePrivate(
const QQuickWindow* window,
QskSceneTexture* texture )
341#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
342 : QSGTexturePrivate()
344 : QSGTexturePrivate( texture )
346 , devicePixelRatio( window->effectiveDevicePixelRatio() )
351 auto dw = QQuickWindowPrivate::get(
const_cast< QQuickWindow*
>( window ) );
352 context =
dynamic_cast< QSGDefaultRenderContext*
>( dw->context );
355#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
356 int comparisonKey()
const override
360 if ( renderer->textureId() )
361 return renderer->textureId();
363 if ( renderer->rhiTexture() )
364 return int( qintptr( renderer->rhiTexture() ) );
367 return int( qintptr(
this ) );
370 QRhiTexture *rhiTexture()
const override
371 {
return renderer ? renderer->rhiTexture() :
nullptr; }
374 QSize pixelSize()
const
376 QSize size( qCeil( rect.width() ), qCeil( rect.height() ) );
377 size *= devicePixelRatio;
379 const QSize minSize = context->sceneGraphContext()->minimumFBOSize();
381 while ( size.width() < minSize.width() )
384 while ( size.height() < minSize.height() )
391 const qreal devicePixelRatio;
393 Renderer* renderer =
nullptr;
394 QSGDefaultRenderContext* context =
nullptr;
397QskSceneTexture::QskSceneTexture(
const QQuickWindow* window )
398 : Inherited( *new QskSceneTexturePrivate( window, this ) )
400 Q_ASSERT( d_func()->context );
403QskSceneTexture::~QskSceneTexture()
405 delete d_func()->renderer;
408QSize QskSceneTexture::textureSize()
const
411 return d->renderer ? d->renderer->textureSize() : QSize();
414void QskSceneTexture::render(
const QSGRootNode* rootNode,
415 const QSGTransformNode* finalNode,
const QRectF& rect )
421 if ( d->renderer ==
nullptr )
423 d->renderer =
new Renderer(
this, d->context );
424 d->renderer->setDevicePixelRatio( d->devicePixelRatio );
427 d->renderer->setRootNode(
const_cast< QSGRootNode*
>( rootNode ) );
428 d->renderer->setFinalNode(
const_cast< QSGTransformNode*
>( finalNode ) );
430 d->renderer->setProjection( d->rect );
431 d->renderer->setTextureSize( d->pixelSize() );
432 d->renderer->renderScene();
435bool QskSceneTexture::isDirty()
const
438 return d->renderer ? d->renderer->isDirty() :
true;
441QRectF QskSceneTexture::normalizedTextureSubRect()
const
443 return QRectF( 0, 1, 1, -1 );
446bool QskSceneTexture::hasAlphaChannel()
const
451bool QskSceneTexture::hasMipmaps()
const
456#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
458void QskSceneTexture::bind()
460 if ( d_func()->rhiTexture() ==
nullptr )
462 auto funcs = QOpenGLContext::currentContext()->functions();
463 funcs->glBindTexture( GL_TEXTURE_2D, textureId() );
469int QskSceneTexture::textureId()
const
472 return d->renderer ? d->renderer->textureId() : 0;
477qint64 QskSceneTexture::comparisonKey()
const
479 return qint64( rhiTexture() );
482QRhiTexture* QskSceneTexture::rhiTexture()
const
485 return d->renderer ? d->renderer->rhiTexture() :
nullptr;
490#include "moc_QskSceneTexture.cpp"