18#include "extensions/qquick3drenderextensions.h"
19#include <QtQuick3DUtils/private/qquick3dprofiler_p.h>
21#include <QtQuick3DRuntimeRender/private/qssgrendererutil_p.h>
22#include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
24#include <QtQuick/private/qquickwindow_p.h>
25#include <QtQuick/private/qsgdefaultrendercontext_p.h>
26#include <QtQuick/private/qsgtexture_p.h>
27#include <QtQuick/private/qsgplaintexture_p.h>
28#include <QtQuick/private/qsgrendernode_p.h>
30#include <QtQuick3DRuntimeRender/private/qssgrendereffect_p.h>
31#include <QtQuick3DRuntimeRender/private/qssgrhieffectsystem_p.h>
32#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
33#include <QtQuick3DRuntimeRender/private/qssgrhiquadrenderer_p.h>
34#include <QtQuick3DRuntimeRender/private/qssgrhicontext_p.h>
35#include <QtQuick3DRuntimeRender/private/qssgcputonemapper_p.h>
36#include <QtQuick3DRuntimeRender/private/qssgrenderroot_p.h>
37#include <QtQuick3DRuntimeRender/private/qssgrenderuserpass_p.h>
39#include <QtQuick3DUtils/private/qssgutils_p.h>
40#include <QtQuick3DUtils/private/qssgassert_p.h>
43#include <qtquick3d_tracepoints_p.h>
45#include <QtCore/QObject>
46#include <QtCore/qqueue.h>
50Q_TRACE_PREFIX(qtquick3d,
52 "class QQuick3DViewport;"
56Q_TRACE_POINT(qtquick3d, QSSG_prepareFrame_entry,
int width,
int height);
67 static bool val = (qEnvironmentVariableIntValue(
"QT_QUICK3D_DUMP_RENDERTIMES") > 0);
71#if QT_CONFIG(qml_debug)
73static inline quint64 statDrawCallCount(
const QSSGRhiContextStats &stats)
76 const QSSGRhiContextStats::PerLayerInfo &info(stats.perLayerInfo[stats.layerKey]);
77 for (
const auto &pass : info.renderPasses)
78 count += QSSGRhiContextStats::totalDrawCallCountForPass(pass);
79 count += QSSGRhiContextStats::totalDrawCallCountForPass(info.externalRenderPass);
83#define STAT_PAYLOAD(stats)
84 (statDrawCallCount(stats) | (quint64(stats.perLayerInfo[stats.layerKey].renderPasses.size()) << 32
))
88template <
typename In,
typename Out>
89static void bfs(In *inExtension, QList<Out *> &outList)
91 QSSG_ASSERT(inExtension,
return);
93 QQueue<In *> queue { { inExtension } };
94 while (queue.size() > 0) {
95 if (
auto cur = queue.dequeue()) {
96 if (
auto *ext =
static_cast<Out *>(QQuick3DObjectPrivate::get(cur)->spatialNode))
97 outList.push_back(ext);
98 for (
auto &chld : cur->childItems())
99 queue.enqueue(qobject_cast<In *>(chld));
109 , devicePixelRatio(1)
111 qsgnode_set_description(
this, QStringLiteral(
"fbonode"));
112 setFlag(QSGNode::UsePreprocess,
true);
124 markDirty(DirtyMaterial);
129 return QSGSimpleTextureNode::texture();
142 if (QThread::currentThread() == QCoreApplication::instance()->thread())
145 QCoreApplication::postEvent(window,
new QEvent(QEvent::Type(QQuickWindowPrivate::FullUpdateRequest)));
152 renderer->renderStats()->startRender();
156 if (
renderer->m_sgContext->rhiContext()->isValid()) {
157 QRhiTexture *rhiTexture =
renderer->renderToRhiTexture(window);
158 bool needsNewWrapper =
false;
159 if (!texture() || (texture()->textureSize() != renderer->surfaceSize()
160 || texture()->rhiTexture() != rhiTexture))
162 needsNewWrapper =
true;
164 if (needsNewWrapper) {
166 QSGPlainTexture *t =
new QSGPlainTexture;
167 t->setOwnsTexture(
false);
168 t->setHasAlphaChannel(
true);
169 t->setTexture(rhiTexture);
170 t->setTextureSize(
renderer->surfaceSize());
175 markDirty(QSGNode::DirtyMaterial);
176 emit textureChanged();
181 if (
renderer->m_requestedFramesCount > 0) {
183 requestFullUpdate(window);
191 if (!qFuzzyCompare(window->effectiveDevicePixelRatio(), devicePixelRatio)) {
205 const auto &rhiCtx = m_sgContext->rhiContext();
206 auto *rhi = rhiCtx->rhi();
208 QSSGRhiContextStats::get(*rhiCtx).cleanupLayerInfo(m_layer);
209 m_sgContext->bufferManager()->releaseResourcesForLayer(m_layer);
219 if (m_sceneRootNode && winAttacment)
220 removeNodeFromLayer(m_sceneRootNode);
226 winAttacment->queueForCleanup(m_layer);
234 releaseAaDependentRhiResources();
235 delete m_effectSystem;
240 const auto &rhiCtx = m_sgContext->rhiContext();
241 if (!rhiCtx->isValid())
244 delete m_textureRenderTarget;
245 m_textureRenderTarget =
nullptr;
247 delete m_textureRenderPassDescriptor;
248 m_textureRenderPassDescriptor =
nullptr;
250 delete m_depthStencilBuffer;
251 m_depthStencilBuffer =
nullptr;
253 delete m_multiViewDepthStencilBuffer;
254 m_multiViewDepthStencilBuffer =
nullptr;
256 delete m_msaaRenderBufferLegacy;
257 m_msaaRenderBufferLegacy =
nullptr;
259 delete m_msaaRenderTexture;
260 m_msaaRenderTexture =
nullptr;
262 delete m_msaaMultiViewRenderBuffer;
263 m_msaaMultiViewRenderBuffer =
nullptr;
265 delete m_ssaaTexture;
266 m_ssaaTexture =
nullptr;
268 delete m_ssaaTextureToTextureRenderTarget;
269 m_ssaaTextureToTextureRenderTarget =
nullptr;
271 delete m_ssaaTextureToTextureRenderPassDescriptor;
272 m_ssaaTextureToTextureRenderPassDescriptor =
nullptr;
274 delete m_temporalAATexture;
275 m_temporalAATexture =
nullptr;
276 delete m_temporalAARenderTarget;
277 m_temporalAARenderTarget =
nullptr;
278 delete m_temporalAARenderPassDescriptor;
279 m_temporalAARenderPassDescriptor =
nullptr;
281 delete m_prevTempAATexture;
282 m_prevTempAATexture =
nullptr;
287 QVector2D(0.500000f, 0.500000f),
288 QVector2D(0.333333f, 0.666667f),
289 QVector2D(0.250000f, 0.750000f),
290 QVector2D(0.200000f, 0.800000f),
291 QVector2D(0.166667f, 0.833333f),
292 QVector2D(0.142857f, 0.857143f),
293 QVector2D(0.125000f, 0.875000f),
294 QVector2D(0.111111f, 0.888889f),
304 QRhiTexture *currentTexture = m_texture;
308 m_renderStats->startRenderPrepare();
310 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
312 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
313 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
315 rhiCtxD->setMainRenderPassDescriptor(m_textureRenderPassDescriptor);
316 rhiCtxD->setRenderTarget(m_textureRenderTarget);
318 QRhiCommandBuffer *cb =
nullptr;
319 QRhiSwapChain *swapchain = qw->swapChain();
321 cb = swapchain->currentFrameCommandBuffer();
322 rhiCtxD->setCommandBuffer(cb);
324 QSGRendererInterface *rif = qw->rendererInterface();
325 cb =
static_cast<QRhiCommandBuffer *>(
326 rif->getResource(qw, QSGRendererInterface::RhiRedirectCommandBuffer));
328 rhiCtxD->setCommandBuffer(cb);
330 qWarning(
"Neither swapchain nor redirected command buffer are available.");
331 return currentTexture;
337 rhiCtxD->setMainPassSampleCount(m_msaaRenderBufferLegacy ? m_msaaRenderBufferLegacy->sampleCount() :
338 (m_msaaRenderTexture ? m_msaaRenderTexture->sampleCount() :
339 (m_msaaMultiViewRenderBuffer ? m_msaaMultiViewRenderBuffer->sampleCount() : 1)));
343 int ssaaAdjustedWidth = m_surfaceSize.width();
344 int ssaaAdjustedHeight = m_surfaceSize.height();
345 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
346 ssaaAdjustedWidth *= m_layer->ssaaMultiplier;
347 ssaaAdjustedHeight *= m_layer->ssaaMultiplier;
350 Q_TRACE(QSSG_prepareFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
352 float dpr = m_sgContext->renderer()->dpr();
353 const QRect vp = QRect(0, 0, ssaaAdjustedWidth, ssaaAdjustedHeight);
358 m_renderStats->endRenderPrepare();
360 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, profilingId);
362 Q_TRACE(QSSG_prepareFrame_exit);
364 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
365 Q_TRACE(QSSG_renderFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
367 m_renderStats->startRender();
369 QColor clearColor = Qt::transparent;
370 if (m_backgroundMode == QSSGRenderLayer::Background::Color
371 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBoxCubeMap && !m_layer->skyBoxCubeMap)
372 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBox && !m_layer->lightProbe))
376 clearColor = m_layer->firstEffect ? m_linearBackgroundColor : m_tonemappedBackgroundColor;
381 cb->beginPass(m_textureRenderTarget, clearColor, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
382 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
383 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(m_textureRenderTarget));
386 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
387 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, QByteArrayLiteral(
"main"));
389 const bool temporalAA = m_layer->temporalAAIsActive;
390 const bool progressiveAA = m_layer->progressiveAAIsActive;
391 const bool superSamplingAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA;
392 QRhi *rhi = rhiCtx->rhi();
394 currentTexture = superSamplingAA ? m_ssaaTexture : m_texture;
397 if (m_effectSystem && m_layer->firstEffect && !m_layer->renderedCameras.isEmpty()) {
398 const auto &renderer = m_sgContext->renderer();
400 Q_ASSERT(theRenderData);
401 QRhiTexture *theDepthTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::DepthTexture)->texture;
402 QRhiTexture *theNormalTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::NormalTexture)->texture;
403 QRhiTexture *theMotionVectorTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::MotionVectorTexture)->texture;
405 currentTexture = m_effectSystem->process(*m_layer,
409 theMotionVectorTexture);
412 if ((progressiveAA || temporalAA) && m_prevTempAATexture) {
413 cb->debugMarkBegin(QByteArrayLiteral(
"Temporal AA"));
414 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
415 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"Temporal AA"));
416 QRhiTexture *blendResult;
417 uint *aaIndex = progressiveAA ? &m_layer->progAAPassIndex : &m_layer->tempAAPassIndex;
420 if ((temporalAA && m_layer->temporalAAMode != QSSGRenderLayer::TAAMode::MotionVector) ||
422 (temporalAA && m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector ?
423 quint32(QSSGLayerRenderData::MAX_AA_LEVELS) :
424 quint32(m_layer->antialiasingQuality))) {
425 const auto &renderer = m_sgContext->renderer();
427 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
428 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ m_layer,
nullptr,
nullptr, 0 }));
429 QRhiBuffer *&ubuf = dcd.ubuf;
430 const int ubufSize = 4 *
sizeof(
float);
432 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
435 int idx = *aaIndex - 1;
437 const QSize textureSize = m_prevTempAATexture->pixelSize();
438 QVector4D bufferData;
440 bufferData = QVector4D(s_ProgressiveAABlendFactors[idx]);
441 else if (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::Default)
442 bufferData = QVector4D(s_TemporalAABlendFactors);
444 bufferData = QVector4D(1.0f / qMax(textureSize.width(), 1), 1.0f / qMax(textureSize.height(), 1),
445 0.9f + (qMin(qMax(m_layer->temporalAAStrength, 0.3f), 1.0f) - 0.3f) / 0.7f * 0.09f, 0.0f);
447 rub->updateDynamicBuffer(ubuf, 0, 4 *
sizeof(
float), &bufferData);
448 QSSGRhiGraphicsPipelineState ps;
449 ps.viewport = QRhiViewport(0, 0,
float(textureSize.width()),
float(textureSize.height()));
451 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
452 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
453 QSSGRhiShaderResourceBindingList bindings;
454 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
455 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
456 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, m_prevTempAATexture, sampler);
457 if (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector) {
459 Q_ASSERT(theRenderData);
460 QRhiTexture *theDepthTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::DepthTexture)->texture;
461 QRhiTexture *theMotionVectorTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::MotionVectorTexture)->texture;
462 bindings.addTexture(3, QRhiShaderResourceBinding::FragmentStage, theDepthTexture, sampler);
463 bindings.addTexture(4, QRhiShaderResourceBinding::FragmentStage, theMotionVectorTexture, sampler);
464 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiTemporalAAShader().get());
469 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiProgressiveAAShader().get());
472 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
473 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx, rub);
474 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_temporalAARenderTarget, QSSGRhiQuadRenderer::UvCoords);
475 blendResult = m_temporalAATexture;
477 blendResult = m_prevTempAATexture;
481 blendResult = currentTexture;
484 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
486 const bool isMotionVector = m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector;
487 const quint32 aaLimit = (temporalAA && isMotionVector) ? quint32(QSSGLayerRenderData::MAX_AA_LEVELS) : quint32(m_layer->antialiasingQuality);
489 const bool aaActive = (temporalAA && !isMotionVector) || (*aaIndex < aaLimit);
490 const bool usePrevTexture = m_prevTempAATexture !=
nullptr;
492 if (aaActive && usePrevTexture) {
493 QRhiTexture *copySource = (blendResult && (progressiveAA || isMotionVector)) ? blendResult : currentTexture;
496 auto *rub = rhi->nextResourceUpdateBatch();
497 rub->copyTexture(m_prevTempAATexture, copySource);
498 cb->resourceUpdate(rub);
504 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"temporal_aa"));
506 currentTexture = blendResult;
509 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
519 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
520 const auto &renderer = m_sgContext->renderer();
522 cb->debugMarkBegin(QByteArrayLiteral(
"SSAA downsample"));
523 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
525 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"SSAA downsample"));
527 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
534 const auto &shaderPipeline = m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiSupersampleResolveShader(m_layer->viewCount);
536 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
537 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
538 QSSGRhiShaderResourceBindingList bindings;
539 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
540 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
542 QSSGRhiGraphicsPipelineState ps;
543 ps.viewport = QRhiViewport(0, 0,
float(m_surfaceSize.width()),
float(m_surfaceSize.height()));
544 ps.viewCount = m_layer->viewCount;
545 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
547 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_ssaaTextureToTextureRenderTarget, QSSGRhiQuadRenderer::UvCoords);
549 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"ssaa_downsample"));
551 currentTexture = m_texture;
554 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
555 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiCtx)),
559 m_renderStats->endRender(dumpRenderTimes());
560 Q_TRACE(QSSG_renderFrame_exit);
563 return currentTexture;
568 m_sgContext->renderer()->beginFrame(*m_layer);
573 m_sgContext->renderer()->endFrame(*m_layer);
581 const auto &renderer = m_sgContext->renderer();
583 renderer->setDpr(displayPixelRatio);
585 renderer->setViewport(viewport);
587 renderer->prepareLayerForRender(*m_layer);
591 const bool renderReady = !m_layer->renderData->renderedCameras.isEmpty();
593 renderer->rhiPrepare(*m_layer);
604 m_sgContext->renderer()->rhiRender(*m_layer);
610#if QT_CONFIG(quick_shadereffect)
611static QRhiTexture::Format toRhiTextureFormat(QQuickShaderEffectSource::Format format)
614 case QQuickShaderEffectSource::RGBA8:
615 return QRhiTexture::RGBA8;
616 case QQuickShaderEffectSource::RGBA16F:
617 return QRhiTexture::RGBA16F;
618 case QQuickShaderEffectSource::RGBA32F:
619 return QRhiTexture::RGBA32F;
621 return QRhiTexture::RGBA8;
626static QVector3D tonemapRgb(
const QVector3D &c, QQuick3DSceneEnvironment::QQuick3DEnvironmentTonemapModes tonemapMode)
628 switch (tonemapMode) {
629 case QQuick3DSceneEnvironment::TonemapModeLinear:
630 return QSSGTonemapper::tonemapLinearToSrgb(c);
631 case QQuick3DSceneEnvironment::TonemapModeHejlDawson:
632 return QSSGTonemapper::tonemapHejlDawson(c);
633 case QQuick3DSceneEnvironment::TonemapModeAces:
634 return QSSGTonemapper::tonemapAces(c);
635 case QQuick3DSceneEnvironment::TonemapModeFilmic:
636 return QSSGTonemapper::tonemapFilmic(c);
645 Q_TRACE_SCOPE(QSSG_synchronize, view3D, size, dpr);
647 Q_ASSERT(view3D !=
nullptr);
648 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
649 Q_ASSERT(rhiCtx !=
nullptr);
653 m_layer =
new QSSGRenderLayer();
655 bool newRenderStats =
false;
656 if (!m_renderStats) {
657 m_renderStats = view3D->renderStats();
658 newRenderStats =
true;
662 m_renderStats->startSync();
664 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DSynchronizeFrame);
666 m_sgContext->renderer()->setDpr(dpr);
667 bool layerSizeIsDirty = m_surfaceSize != size;
668 m_surfaceSize = size;
670 QQuick3DSceneEnvironment *environment = view3D->environment();
671 if (environment->lightmapper()) {
672 QQuick3DLightmapper *lightmapper = environment->lightmapper();
673 lmOptions.opacityThreshold = lightmapper->opacityThreshold();
674 lmOptions.bias = lightmapper->bias();
675 lmOptions.useAdaptiveBias = lightmapper->isAdaptiveBiasEnabled();
676 lmOptions.indirectLightEnabled = lightmapper->isIndirectLightEnabled();
677 lmOptions.indirectLightSamples = lightmapper->samples();
678 lmOptions.indirectLightWorkgroupSize = lightmapper->indirectLightWorkgroupSize();
679 lmOptions.indirectLightBounces = lightmapper->bounces();
680 lmOptions.indirectLightFactor = lightmapper->indirectLightFactor();
681 lmOptions.sigma = lightmapper->denoiseSigma();
682 lmOptions.texelsPerUnit = lightmapper->texelsPerUnit();
688 if (environment->m_dirtyFlags & QQuick3DSceneEnvironment::InternalDirtyFlag::LightmapperDirty) {
689 environment->m_dirtyFlags &= ~QQuick3DSceneEnvironment::InternalDirtyFlag::LightmapperDirty;
691 const QQmlContext *context = qmlContext(view3D);
692 const QUrl originalSource = environment->lightmapper() ? environment->lightmapper()->source()
693 : QUrl::fromLocalFile(QStringLiteral(
"lightmaps.bin"));
694 const auto resolvedUrl = context ? context->resolvedUrl(originalSource) : originalSource;
695 const auto qmlSource = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
696 const QString lightmapSource = qmlSource.isEmpty() ? originalSource.path() : qmlSource;
697 lmOptions.source = lightmapSource;
698 m_layer->lightmapSource = lightmapSource;
701 m_sgContext->bufferManager()->setLightmapSource(m_layer->lightmapSource);
702 if (QQuick3DSceneManager *sceneManager = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager)
703 sceneManager->lightmapSourceTracker = { m_layer->lightmapSource,
true };
707 QSet<QSSGRenderGraphObject *> resourceLoaders;
708 QQuick3DWindowAttachment::SyncResult requestSharedUpdate = QQuick3DWindowAttachment::SyncResultFlag::None;
709 if (
auto window = view3D->window()) {
710 if (!winAttacment || winAttacment->window() != window)
711 winAttacment = QQuick3DSceneManager::getOrSetWindowAttachment(*window);
713 if (winAttacment && winAttacment->rci() != m_sgContext)
714 winAttacment->setRci(m_sgContext);
716 QSSGRenderRoot *rootNode = winAttacment->rootNode();
717 if (m_layer->rootNode != rootNode) {
718 Q_ASSERT(m_layer->rootNode ==
nullptr);
719 rootNode->addChild(*m_layer);
720 rootNode->setStartVersion(m_layer->h.version());
721 m_layer->ref(rootNode);
725 requestSharedUpdate |= winAttacment->synchronize(resourceLoaders);
729 QQuick3DNode *importScene = view3D->importScene();
731 QQuick3DSceneManager *importSceneManager = QQuick3DObjectPrivate::get(importScene)->sceneManager;
734 if (
auto window = importSceneManager->window(); window && window != view3D->window()) {
735 if (
auto winAttacment = importSceneManager->wattached) {
737 auto rci = winAttacment->rci();
738 const bool inlineSync = (rci && rci->rhi() && (rci->rhi()->thread() == m_sgContext->rhi()->thread()));
742 winAttacment->synchronize(resourceLoaders);
743 }
else if (rci && !window->isExposed()) {
745 winAttacment->synchronize(resourceLoaders);
746 }
else if (!rci || (requestSharedUpdate & QQuick3DWindowAttachment::SyncResultFlag::SharedResourcesDirty)) {
751 winAttacment->requestUpdate();
764 m_layer->viewCount = rhiCtx->mainPassViewCount();
765 updateLayerNode(*m_layer, *view3D, resourceLoaders.values());
769 m_requestedFramesCount = 0;
770 if (m_layer->isProgressiveAAEnabled() || m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector) {
777 m_requestedFramesCount = (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector ? 45 :
778 int(m_layer->antialiasingQuality) + 1);
779 }
else if (m_layer->isTemporalAAEnabled()) {
784 m_requestedFramesCount = (m_aaIsDirty || m_temporalIsDirty) ? QSSGLayerRenderData::MAX_TEMPORAL_AA_LEVELS : 1;
789 for (QSSGRenderEffect *effectNode = m_layer->firstEffect; effectNode; effectNode = effectNode->m_nextEffect)
790 effectNode->finalizeShaders(*m_layer, m_sgContext.get());
793 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
794 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses))
795 userPass->finalizeShaders(*m_sgContext);
799 m_renderStats->setRhiContext(rhiCtx, m_layer);
801 static const auto getStageIndex = [](
const QSSGRenderExtension &ext) -> size_t {
802 const QSSGRenderExtension::RenderMode mode = ext.mode();
803 const QSSGRenderExtension::RenderStage stage = ext.stage();
806 if (mode == QSSGRenderExtension::RenderMode::Standalone)
807 return size_t(QSSGRenderLayer::RenderExtensionStage::TextureProviders);
810 case QSSGRenderExtension::RenderStage::PreColor:
811 return size_t(QSSGRenderLayer::RenderExtensionStage::Overlay);
812 case QSSGRenderExtension::RenderStage::PostColor:
813 return size_t(QSSGRenderLayer::RenderExtensionStage::Underlay);
816 Q_UNREACHABLE_RETURN(size_t(QSSGRenderLayer::RenderExtensionStage::Underlay));
822 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
823 const bool rebuildExtensionLists = (requestSharedUpdate & QQuick3DWindowAttachment::SyncResultFlag::ExtensionsDiry)
824 || view3D->extensionListDirty()
825 || sm->autoRegisteredExtensionsDirty;
830 if (rebuildExtensionLists) {
832 for (size_t i = 0; i != size_t(QSSGRenderLayer::RenderExtensionStage::Count); ++i)
833 m_layer->renderExtensions[i].clear();
836 const auto &extensions = view3D->extensionList();
837 for (
const auto &ext : extensions) {
838 const auto type = QQuick3DObjectPrivate::get(ext)->type;
839 if (QSSGRenderGraphObject::isExtension(type)) {
840 if (type == QSSGRenderGraphObject::Type::RenderExtension) {
841 if (
auto *renderExt = qobject_cast<QQuick3DRenderExtension *>(ext)) {
842 if (QSSGRenderExtension *ssgExt =
static_cast<QSSGRenderExtension *>(QQuick3DObjectPrivate::get(renderExt)->spatialNode)) {
843 const auto stage = getStageIndex(*ssgExt);
844 auto &list = m_layer->renderExtensions[size_t(stage)];
845 bfs(qobject_cast<QQuick3DRenderExtension *>(ext), list);
852 view3D->clearExtensionListDirty();
856 if (sm->autoRegisteredExtensionsDirty) {
857 for (QSSGRenderExtension *ae : std::as_const(sm->autoRegisteredExtensions))
858 m_layer->renderExtensions[getStageIndex(*ae)].push_back(ae);
859 sm->autoRegisteredExtensionsDirty =
false;
863 bool postProcessingNeeded = m_layer->firstEffect;
864 bool postProcessingWasActive = m_effectSystem;
865 QSSGRenderTextureFormat::Format effectOutputFormatOverride = QSSGRenderTextureFormat::Unknown;
866 if (postProcessingNeeded) {
867 QSSGRenderEffect *lastEffect = m_layer->firstEffect;
868 while (lastEffect->m_nextEffect)
869 lastEffect = lastEffect->m_nextEffect;
870 effectOutputFormatOverride = QSSGRhiEffectSystem::overriddenOutputFormat(lastEffect);
872 const auto layerTextureFormat = [effectOutputFormatOverride, view3D](QRhi *rhi,
bool postProc) {
873 if (effectOutputFormatOverride != QSSGRenderTextureFormat::Unknown)
874 return QSSGBufferManager::toRhiFormat(effectOutputFormatOverride);
889 const QRhiTexture::Format preferredPostProcFormat = QRhiTexture::RGBA16F;
890 if (postProc && rhi->isTextureFormatSupported(preferredPostProcFormat))
891 return preferredPostProcFormat;
893#if QT_CONFIG(quick_shadereffect)
894 const QRhiTexture::Format preferredView3DFormat = toRhiTextureFormat(view3D->renderFormat());
895 if (rhi->isTextureFormatSupported(preferredView3DFormat))
896 return preferredView3DFormat;
899 return QRhiTexture::RGBA8;
901 bool postProcessingStateDirty = postProcessingNeeded != postProcessingWasActive;
904 m_backgroundMode = QSSGRenderLayer::Background(view3D->environment()->backgroundMode());
908 QColor currentUserBackgroundColor = view3D->environment()->clearColor();
909 if (m_userBackgroundColor != currentUserBackgroundColor) {
910 m_userBackgroundColor = currentUserBackgroundColor;
911 m_linearBackgroundColor = QSSGUtils::color::sRGBToLinearColor(m_userBackgroundColor);
912 const QVector3D tc = tonemapRgb(QVector3D(m_linearBackgroundColor.redF(),
913 m_linearBackgroundColor.greenF(),
914 m_linearBackgroundColor.blueF()),
915 view3D->environment()->tonemapMode());
916 m_tonemappedBackgroundColor = QColor::fromRgbF(tc.x(), tc.y(), tc.z(), m_linearBackgroundColor.alphaF());
918 m_layer->scissorRect = QRect(view3D->environment()->scissorRect().topLeft() * dpr,
919 view3D->environment()->scissorRect().size() * dpr);
925 auto sceneRootNode =
static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(view3D->scene())->spatialNode);
926 if (sceneRootNode != m_sceneRootNode) {
928 removeNodeFromLayer(m_sceneRootNode);
931 addNodeToLayer(sceneRootNode);
933 m_sceneRootNode = sceneRootNode;
937 QSSGRenderNode *importSceneRootNode =
nullptr;
939 importSceneRootNode =
static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(importScene)->spatialNode);
941 if (importSceneRootNode != m_importSceneRootNode) {
942 if (m_importSceneRootNode)
943 m_layer->removeImportScene(*m_importSceneRootNode);
945 if (importSceneRootNode) {
949 QObject *sceneParent = importScene->parent();
950 bool isEmbedded =
false;
951 while (sceneParent) {
952 if (sceneParent == view3D) {
956 sceneParent = sceneParent->parent();
959 m_layer->setImportScene(*importSceneRootNode);
962 m_importSceneRootNode = importSceneRootNode;
970 QSSGRenderRoot *rootNode = winAttacment->rootNode();
971 if (rootNode->isDirty(QSSGRenderRoot::DirtyFlag::TreeDirty)) {
973 for (QSSGRenderNode &layer : rootNode->children) {
974 if (QSSG_GUARD_X(layer.type == QSSGRenderGraphObject::Type::Layer,
"Layer type mismatch"))
975 static_cast<QSSGRenderLayer &>(layer).markDirty(QSSGRenderLayer::DirtyFlag::TreeDirty);
980 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
981 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses)) {
982 if (
const auto *fo = sm->lookUpNode(userPass); fo && fo->parentItem()) {
983 const auto *pi = fo->parentItem();
984 if (
const QSSGRenderGraphObject *parentNode = QQuick3DObjectPrivate::get(pi)->spatialNode; parentNode && QSSGRenderGraphObject::isNodeType(parentNode->type))
985 userPass->setDependencyIndex(
static_cast<
const QSSGRenderNode *>(parentNode)->h.index());
987 userPass->setDependencyIndex(0);
994 maybeSetupLightmapBaking(view3D);
996 if (m_useFBO && rhiCtx->isValid()) {
997 QRhi *rhi = rhiCtx->rhi();
998 const QSize renderSize = m_layer->isSsaaEnabled() ? m_surfaceSize * m_layer->ssaaMultiplier : m_surfaceSize;
1002 if (layerSizeIsDirty || postProcessingStateDirty) {
1003 m_texture->setPixelSize(m_surfaceSize);
1004 m_texture->setFormat(layerTextureFormat(rhi, postProcessingNeeded));
1005 m_texture->create();
1016 if (postProcessingStateDirty && (m_layer->antialiasingMode != QSSGRenderLayer::AAMode::NoAA || m_layer->isTemporalAAEnabled())) {
1017 releaseAaDependentRhiResources();
1019 if (m_ssaaTexture) {
1020 m_ssaaTexture->setPixelSize(renderSize);
1021 m_ssaaTexture->create();
1023 if (m_depthStencilBuffer) {
1024 m_depthStencilBuffer->setPixelSize(renderSize);
1025 m_depthStencilBuffer->create();
1027 if (m_multiViewDepthStencilBuffer) {
1028 m_multiViewDepthStencilBuffer->setPixelSize(renderSize);
1029 m_multiViewDepthStencilBuffer->create();
1031 if (m_msaaRenderBufferLegacy) {
1032 m_msaaRenderBufferLegacy->setPixelSize(renderSize);
1033 m_msaaRenderBufferLegacy->create();
1035 if (m_msaaRenderTexture) {
1036 m_msaaRenderTexture->setPixelSize(renderSize);
1037 m_msaaRenderTexture->create();
1039 if (m_msaaMultiViewRenderBuffer) {
1040 m_msaaMultiViewRenderBuffer->setPixelSize(renderSize);
1041 m_msaaMultiViewRenderBuffer->create();
1047 if (postProcessingStateDirty) {
1048 delete m_textureRenderPassDescriptor;
1049 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
1050 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
1052 m_textureRenderTarget->create();
1053 if (m_ssaaTextureToTextureRenderTarget)
1054 m_ssaaTextureToTextureRenderTarget->create();
1056 if (m_temporalAATexture) {
1057 m_temporalAATexture->setPixelSize(renderSize);
1058 m_temporalAATexture->create();
1060 if (m_prevTempAATexture) {
1061 m_prevTempAATexture->setPixelSize(renderSize);
1062 m_prevTempAATexture->create();
1064 if (m_temporalAARenderTarget)
1065 m_temporalAARenderTarget->create();
1068 }
else if (m_aaIsDirty && rhi->backend() == QRhi::Metal) {
1069 m_texture->create();
1073 releaseAaDependentRhiResources();
1076 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget
1077 | QRhiTexture::UsedAsTransferSource;
1078 const QRhiTexture::Format textureFormat = layerTextureFormat(rhi, postProcessingNeeded);
1081 if (m_layer->viewCount >= 2)
1082 m_texture = rhi->newTextureArray(textureFormat, m_layer->viewCount, m_surfaceSize, 1, textureFlags);
1084 m_texture = rhi->newTexture(textureFormat, m_surfaceSize, 1, textureFlags);
1085 m_texture->create();
1088 if (!m_ssaaTexture && m_layer->isSsaaEnabled()) {
1089 if (m_layer->viewCount >= 2)
1090 m_ssaaTexture = rhi->newTextureArray(textureFormat, m_layer->viewCount, renderSize, 1, textureFlags);
1092 m_ssaaTexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1093 m_ssaaTexture->create();
1096 if (m_timeBasedAA && !m_temporalAATexture) {
1097 m_temporalAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1098 m_temporalAATexture->create();
1099 m_prevTempAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1100 m_prevTempAATexture->create();
1104 if (m_aaIsDirty || layerSizeIsDirty)
1105 m_layer->tempAAPassIndex = m_layer->progAAPassIndex = 0;
1109 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::MSAA) {
1110 if (rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer)) {
1111 m_samples = qMax(1,
int(m_layer->antialiasingQuality));
1117 const QVector<
int> supported = rhi->supportedSampleCounts();
1118 if (!supported.contains(m_samples)) {
1119 if (!supported.isEmpty()) {
1120 auto it = std::lower_bound(supported.cbegin(), supported.cend(), m_samples);
1121 m_samples = it == supported.cend() ? supported.last() : *it;
1127 static bool warned =
false;
1130 qWarning(
"Multisample renderbuffers are not supported, disabling MSAA for Offscreen View3D");
1136 if (m_layer->viewCount >= 2) {
1137 if (!m_multiViewDepthStencilBuffer) {
1138 const auto format = rhi->isTextureFormatSupported(QRhiTexture::D24S8) ? QRhiTexture::D24S8 : QRhiTexture::D32FS8;
1139 m_multiViewDepthStencilBuffer = rhi->newTextureArray(format, m_layer->viewCount, renderSize,
1140 m_samples, QRhiTexture::RenderTarget);
1141 m_multiViewDepthStencilBuffer->create();
1144 if (!m_depthStencilBuffer) {
1145 m_depthStencilBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, renderSize, m_samples);
1146 m_depthStencilBuffer->create();
1150 if (!m_textureRenderTarget) {
1151 QRhiTextureRenderTargetDescription rtDesc;
1152 QRhiColorAttachment att;
1153 if (m_samples > 1) {
1154 if (m_layer->viewCount >= 2) {
1155 m_msaaMultiViewRenderBuffer = rhi->newTextureArray(textureFormat, m_layer->viewCount, renderSize, m_samples, QRhiTexture::RenderTarget);
1156 m_msaaMultiViewRenderBuffer->create();
1157 att.setTexture(m_msaaMultiViewRenderBuffer);
1159 if (!rhi->isFeatureSupported(QRhi::MultisampleTexture)) {
1161 m_msaaRenderBufferLegacy = rhi->newRenderBuffer(QRhiRenderBuffer::Color, renderSize, m_samples, {}, m_texture->format());
1162 m_msaaRenderBufferLegacy->create();
1163 att.setRenderBuffer(m_msaaRenderBufferLegacy);
1170 m_msaaRenderTexture = rhi->newTexture(textureFormat, renderSize, m_samples, QRhiTexture::RenderTarget);
1171 m_msaaRenderTexture->create();
1172 att.setTexture(m_msaaRenderTexture);
1175 att.setResolveTexture(m_texture);
1177 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA)
1178 att.setTexture(m_ssaaTexture);
1180 att.setTexture(m_texture);
1182 att.setMultiViewCount(m_layer->viewCount);
1183 rtDesc.setColorAttachments({ att });
1184 if (m_depthStencilBuffer)
1185 rtDesc.setDepthStencilBuffer(m_depthStencilBuffer);
1186 if (m_multiViewDepthStencilBuffer)
1187 rtDesc.setDepthTexture(m_multiViewDepthStencilBuffer);
1189 m_textureRenderTarget = rhi->newTextureRenderTarget(rtDesc);
1190 m_textureRenderTarget->setName(QByteArrayLiteral(
"View3D"));
1191 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
1192 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
1193 m_textureRenderTarget->create();
1196 if (!m_ssaaTextureToTextureRenderTarget && m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
1197 QRhiColorAttachment att(m_texture);
1198 att.setMultiViewCount(m_layer->viewCount);
1199 m_ssaaTextureToTextureRenderTarget = rhi->newTextureRenderTarget(QRhiTextureRenderTargetDescription({ att }));
1200 m_ssaaTextureToTextureRenderTarget->setName(QByteArrayLiteral(
"SSAA texture"));
1201 m_ssaaTextureToTextureRenderPassDescriptor = m_ssaaTextureToTextureRenderTarget->newCompatibleRenderPassDescriptor();
1202 m_ssaaTextureToTextureRenderTarget->setRenderPassDescriptor(m_ssaaTextureToTextureRenderPassDescriptor);
1203 m_ssaaTextureToTextureRenderTarget->create();
1206 if (m_layer->firstEffect) {
1207 if (!m_effectSystem)
1208 m_effectSystem =
new QSSGRhiEffectSystem(m_sgContext);
1209 m_effectSystem->setup(renderSize);
1210 }
else if (m_effectSystem) {
1211 delete m_effectSystem;
1212 m_effectSystem =
nullptr;
1215 if (m_timeBasedAA && !m_temporalAARenderTarget) {
1216 m_temporalAARenderTarget = rhi->newTextureRenderTarget({ m_temporalAATexture });
1217 m_temporalAARenderTarget->setName(QByteArrayLiteral(
"Temporal AA texture"));
1218 m_temporalAARenderPassDescriptor = m_temporalAARenderTarget->newCompatibleRenderPassDescriptor();
1219 m_temporalAARenderTarget->setRenderPassDescriptor(m_temporalAARenderPassDescriptor);
1220 m_temporalAARenderTarget->create();
1223 m_textureNeedsFlip = rhi->isYUpInFramebuffer();
1224 m_aaIsDirty =
false;
1228 m_renderStats->endSync(dumpRenderTimes());
1230 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DSynchronizeFrame, quint64(m_surfaceSize.width()) | quint64(m_surfaceSize.height()) << 32, profilingId);
1236 fboNode->invalidatePending =
true;
1241 if (m_layer && m_layer->renderData) {
1242 if (
const auto &mgr = m_layer->renderData->getShadowMapManager())
1243 mgr->releaseCachedResources();
1244 if (
const auto &mgr = m_layer->renderData->getReflectionMapManager())
1245 mgr->releaseCachedResources();
1251 if (!m_layer || !m_layer->renderData)
1252 return std::nullopt;
1254 QMutexLocker locker(&m_layer->renderedCamerasMutex);
1256 if (m_layer->renderedCameras.isEmpty())
1257 return std::nullopt;
1259 QMatrix4x4 globalTransform = m_layer->renderData->getGlobalTransform(*m_layer->renderedCameras[0]);
1261 const QVector2D viewportSize(m_surfaceSize.width(), m_surfaceSize.height());
1262 const QVector2D position(
float(pos.x()),
float(pos.y()));
1263 const QRectF viewportRect(QPointF{}, QSizeF(m_surfaceSize));
1267 QVector2D correctCoords(position.x(), viewportSize.y() - position.y());
1268 QVector2D theLocalMouse = QSSGUtils::rect::toRectRelative(viewportRect, correctCoords);
1269 if ((theLocalMouse.x() < 0.0f || theLocalMouse.x() >= viewportSize.x() || theLocalMouse.y() < 0.0f
1270 || theLocalMouse.y() >= viewportSize.y()))
1271 return std::nullopt;
1273 return m_layer->renderedCameras[0]->unproject(globalTransform, theLocalMouse, viewportRect);
1276std::optional<QSSGRenderPickResult>
QQuick3DSceneRenderer::syncPickClosestPoint(
const QVector3D ¢er,
float radiusSquared, QSSGRenderNode *node)
1279 return std::nullopt;
1281 return QSSGRendererPrivate::syncPickClosestPoint(*m_sgContext,
1283 center, radiusSquared,
1290 return QQuick3DSceneRenderer::PickResultList();
1292 return QSSGRendererPrivate::syncPick(*m_sgContext,
1300 return QQuick3DSceneRenderer::PickResultList();
1302 return QSSGRendererPrivate::syncPick(*m_sgContext,
1309 QVarLengthArray<QSSGRenderNode *> subset)
1312 return QQuick3DSceneRenderer::PickResultList();
1314 return QSSGRendererPrivate::syncPickSubset(*m_layer,
1315 *m_sgContext->bufferManager(),
1323 return QQuick3DSceneRenderer::PickResultList();
1325 return QSSGRendererPrivate::syncPickAll(*m_sgContext,
1335 return QSSGRendererPrivate::syncPickInFrustum(*m_sgContext, *m_layer, frustum);
1340 QSSGRendererPrivate::setGlobalPickingEnabled(*m_sgContext->renderer(), isEnabled);
1345 return m_renderStats;
1348void QQuick3DRenderLayerHelpers::updateLayerNodeHelper(
const QQuick3DViewport &view3D,
1349 const std::shared_ptr<QSSGRenderContextInterface>& rci,
1350 QSSGRenderLayer &layerNode,
1352 bool &temporalIsDirty)
1354 QList<QSSGRenderGraphObject *> resourceLoaders;
1356 QQuick3DSceneRenderer dummyRenderer(rci);
1359 dummyRenderer.updateLayerNode(layerNode, view3D, resourceLoaders);
1361 aaIsDirty = dummyRenderer.m_aaIsDirty;
1362 temporalIsDirty = dummyRenderer.m_temporalIsDirty;
1366 const QQuick3DViewport &view3D,
1367 const QList<QSSGRenderGraphObject *> &resourceLoaders)
1369 QQuick3DSceneEnvironment *environment = view3D.environment();
1370 const auto &effects = environment->effectList();
1372 QSSGRenderLayer::AAMode aaMode = QSSGRenderLayer::AAMode(environment->antialiasingMode());
1373 if (aaMode != layerNode.antialiasingMode) {
1374 layerNode.antialiasingMode = aaMode;
1375 layerNode.progAAPassIndex = 0;
1378 QSSGRenderLayer::AAQuality aaQuality = QSSGRenderLayer::AAQuality(environment->antialiasingQuality());
1379 if (aaQuality != layerNode.antialiasingQuality) {
1380 layerNode.antialiasingQuality = aaQuality;
1381 layerNode.ssaaMultiplier = QSSGRenderLayer::ssaaMultiplierForQuality(aaQuality);
1386 const bool temporalAARequested = environment->temporalAAEnabled();
1387 const bool wasTaaEnabled = layerNode.isTemporalAAEnabled();
1388 layerNode.temporalAAMode = temporalAARequested ? QSSGRenderLayer::TAAMode(environment->m_temporalAAMode + 1)
1389 : QSSGRenderLayer::TAAMode::Off;
1392 if (wasTaaEnabled != layerNode.isTemporalAAEnabled()) {
1393 layerNode.tempAAPassIndex = 0;
1395 m_temporalIsDirty =
true;
1398 layerNode.temporalAAStrength = environment->temporalAAStrength();
1400 layerNode.specularAAEnabled = environment->specularAAEnabled();
1402 layerNode.background = QSSGRenderLayer::Background(environment->backgroundMode());
1403 layerNode.clearColor = QVector3D(
float(environment->clearColor().redF()),
1404 float(environment->clearColor().greenF()),
1405 float(environment->clearColor().blueF()));
1407 layerNode.gridEnabled = environment->gridEnabled();
1408 layerNode.gridScale = environment->gridScale();
1409 layerNode.gridFlags = environment->gridFlags();
1411 layerNode.aoStrength = environment->aoStrength();
1412 layerNode.aoDistance = environment->aoDistance();
1413 layerNode.aoSoftness = environment->aoSoftness();
1414 layerNode.aoEnabled = environment->aoEnabled();
1415 layerNode.aoBias = environment->aoBias();
1416 layerNode.aoSamplerate = environment->aoSampleRate();
1417 layerNode.aoDither = environment->aoDither();
1420 if (environment->lightProbe())
1421 layerNode.lightProbe = environment->lightProbe()->getRenderImage();
1423 layerNode.lightProbe =
nullptr;
1424 if (view3D.environment()->skyBoxCubeMap())
1425 layerNode.skyBoxCubeMap = view3D.environment()->skyBoxCubeMap()->getRenderImage();
1427 layerNode.skyBoxCubeMap =
nullptr;
1429 layerNode.lightProbeSettings.probeExposure = environment->probeExposure();
1431 layerNode.lightProbeSettings.probeHorizon = qMin(environment->probeHorizon() - 1.0f, -0.001f);
1432 layerNode.setProbeOrientation(environment->probeOrientation());
1434 QQuick3DViewport::updateCameraForLayer(view3D, layerNode);
1436 layerNode.layerFlags.setFlag(QSSGRenderLayer::LayerFlag::EnableDepthTest, environment->depthTestEnabled());
1437 layerNode.layerFlags.setFlag(QSSGRenderLayer::LayerFlag::EnableDepthPrePass, environment->depthPrePassEnabled());
1439 layerNode.tonemapMode = QQuick3DSceneRenderer::getTonemapMode(*environment);
1440 layerNode.skyboxBlurAmount = environment->skyboxBlurAmount();
1441 if (
auto debugSettings = view3D.environment()->debugSettings()) {
1442 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode(debugSettings->materialOverride());
1443 layerNode.wireframeMode = debugSettings->wireframeEnabled();
1444 layerNode.drawDirectionalLightShadowBoxes = debugSettings->drawDirectionalLightShadowBoxes();
1445 layerNode.drawPointLightShadowBoxes = debugSettings->drawPointLightShadowBoxes();
1446 layerNode.drawShadowCastingBounds = debugSettings->drawShadowCastingBounds();
1447 layerNode.drawShadowReceivingBounds = debugSettings->drawShadowReceivingBounds();
1448 layerNode.drawCascades = debugSettings->drawCascades();
1449 layerNode.drawSceneCascadeIntersection = debugSettings->drawSceneCascadeIntersection();
1450 layerNode.disableShadowCameraUpdate = debugSettings->disableShadowCameraUpdate();
1451 layerNode.drawCulledObjects = debugSettings->drawCulledObjects();
1453 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode::None;
1454 layerNode.wireframeMode =
false;
1457 if (environment->fog() && environment->fog()->isEnabled()) {
1458 layerNode.fog.enabled =
true;
1459 const QQuick3DFog *fog = environment->fog();
1460 layerNode.fog.color = QSSGUtils::color::sRGBToLinear(fog->color()).toVector3D();
1461 layerNode.fog.density = fog->density();
1462 layerNode.fog.depthEnabled = fog->isDepthEnabled();
1463 layerNode.fog.depthBegin = fog->depthNear();
1464 layerNode.fog.depthEnd = fog->depthFar();
1465 layerNode.fog.depthCurve = fog->depthCurve();
1466 layerNode.fog.heightEnabled = fog->isHeightEnabled();
1467 layerNode.fog.heightMin = fog->leastIntenseY();
1468 layerNode.fog.heightMax = fog->mostIntenseY();
1469 layerNode.fog.heightCurve = fog->heightCurve();
1470 layerNode.fog.transmitEnabled = fog->isTransmitEnabled();
1471 layerNode.fog.transmitCurve = fog->transmitCurve();
1473 layerNode.fog.enabled =
false;
1475 const auto method =
static_cast<QSSGRenderLayer::OITMethod>(environment->oitMethod());
1476 layerNode.oitMethodDirty = method != layerNode.oitMethod;
1477 layerNode.oitMethod = method;
1482 layerNode.firstEffect =
nullptr;
1483 auto rit = effects.crbegin();
1484 const auto rend = effects.crend();
1485 for (; rit != rend; ++rit) {
1486 QQuick3DObjectPrivate *p = QQuick3DObjectPrivate::get(*rit);
1487 QSSGRenderEffect *effectNode =
static_cast<QSSGRenderEffect *>(p->spatialNode);
1489 if (layerNode.hasEffect(effectNode)) {
1490 qWarning() <<
"Duplicate effect found, skipping!";
1492 effectNode->className = (*rit)->metaObject()->className();
1493 layerNode.addEffect(*effectNode);
1498 const bool hasEffects = (layerNode.firstEffect !=
nullptr);
1500 const auto renderMode = view3D.renderMode();
1502 const bool progressiveAA = layerNode.isProgressiveAAEnabled();
1503 const bool temporalAA = layerNode.isTemporalAAEnabled();
1504 const bool superSamplingAA = layerNode.isSsaaEnabled();
1505 m_timeBasedAA = progressiveAA || temporalAA;
1506 m_postProcessingStack = hasEffects || m_timeBasedAA || superSamplingAA;
1507 m_useFBO = renderMode == QQuick3DViewport::RenderMode::Offscreen ||
1508 ((renderMode == QQuick3DViewport::RenderMode::Underlay || renderMode == QQuick3DViewport::RenderMode::Overlay)
1509 && m_postProcessingStack);
1518 if (m_useFBO && (layerNode.viewCount > 1) && !view3D.isXrViewInstance())
1519 layerNode.viewCount = 1;
1522 layerNode.resourceLoaders.clear();
1523 layerNode.resourceLoaders = resourceLoaders;
1525 layerNode.renderOverrides = QSSGRenderLayer::RenderOverridesT(view3D.renderOverrides().toInt());
1533 m_layer->removeChild(*node);
1538 if (m_layer->renderData && m_layer->renderData->lightmapBaker)
1543 bool bakeRequested =
false;
1544 bool denoiseRequested =
false;
1545 bool fromCmd =
false;
1546 QQuick3DLightmapBaker *lightmapBaker = view3D->maybeLightmapBaker();
1547 if (lightmapBaker && (lightmapBaker->m_bakingRequested || lightmapBaker->m_denoisingRequested)) {
1548 bakeRequested = std::exchange(lightmapBaker->m_bakingRequested,
false);
1549 denoiseRequested = std::exchange(lightmapBaker->m_denoisingRequested,
false);
1551 bakeRequested = m_lightmapBakingFromCmdRequested;
1552 denoiseRequested = m_lightmapDenoisingFromCmdRequested;
1553 fromCmd = bakeRequested;
1557 if (bakeRequested || denoiseRequested) {
1558 QSSGLightmapBaker::Context ctx;
1559 ctx.settings.bakeRequested = bakeRequested;
1560 ctx.settings.denoiseRequested = denoiseRequested;
1561 ctx.settings.quitWhenFinished = fromCmd;
1564 if (lightmapBaker) {
1565 QQuick3DLightmapBaker::Callback qq3dCallback = lightmapBaker->m_callback;
1566 QQuick3DLightmapBaker::BakingControl *qq3dBakingControl = lightmapBaker->m_bakingControl;
1567 QSSGLightmapper::Callback callback =
1569 qq3dBakingControl](
const QVariantMap &payload,
1570 QSSGLightmapper::BakingControl *qssgBakingControl) {
1571 qq3dCallback(payload, qq3dBakingControl);
1573 if (qq3dBakingControl->isCancelled() && !qssgBakingControl->cancelled)
1574 qssgBakingControl->cancelled =
true;
1576 ctx.callbacks.lightmapBakingOutput = callback;
1580 ctx.callbacks.triggerNewFrame = [view3D](
bool releaseResources) {
1581 if (releaseResources) {
1582 QMetaObject::invokeMethod(view3D->window(),
1583 &QQuickWindow::releaseResources,
1584 Qt::QueuedConnection);
1586 QMetaObject::invokeMethod(view3D, &QQuick3DViewport::update, Qt::QueuedConnection);
1588 ctx.callbacks.setCurrentlyBaking = [
this](
bool value) {
1589 m_sgContext->bufferManager()->setCurrentlyLightmapBaking(value);
1592 ctx.env.rhiCtx = m_sgContext->rhiContext().get();
1593 ctx.env.renderer = m_sgContext->renderer().get();
1594 ctx.env.lmOptions = lmOptions;
1595 m_layer->renderData->initializeLightmapBaking(ctx);
1599 static bool flagsChecked =
false;
1602 flagsChecked =
true;
1604 auto isLightmapFlagSet = [](
const QString &flag,
const char *envVar) {
1605 return QCoreApplication::arguments().contains(flag)
1606 || qEnvironmentVariableIntValue(envVar);
1609 m_lightmapBakingFromCmdRequested = isLightmapFlagSet(QStringLiteral(
"--bake-lightmaps"),
"QT_QUICK3D_BAKE_LIGHTMAPS");
1610 m_lightmapDenoisingFromCmdRequested = isLightmapFlagSet(QStringLiteral(
"--denoise-lightmaps"),
"QT_QUICK3D_DENOISE_LIGHTMAPS");
1612 if (m_lightmapBakingFromCmdRequested || m_lightmapDenoisingFromCmdRequested) {
1614 QMetaObject::invokeMethod(view3D, &QQuick3DViewport::update, Qt::QueuedConnection);
1624 m_layer->addChild(*node);
1629 return BlendState | StencilState | DepthState | ScissorState | ColorState | CullState | ViewportState | RenderTargetState;
1633inline QRect convertQtRectToGLViewport(
const QRectF &rect,
const QSize surfaceSize)
1635 const int x =
int(rect.x());
1636 const int y = surfaceSize.height() - (
int(rect.y()) +
int(rect.height()));
1637 const int width =
int(rect.width());
1638 const int height =
int(rect.height());
1639 return QRect(x, y, width, height);
1642inline void queryMainRenderPassDescriptorAndCommandBuffer(QQuickWindow *window, QSSGRhiContext *rhiCtx)
1644 if (rhiCtx->isValid()) {
1645 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
1650 int sampleCount = 1;
1652 QRhiSwapChain *swapchain = window->swapChain();
1654 rhiCtxD->setMainRenderPassDescriptor(swapchain->renderPassDescriptor());
1655 rhiCtxD->setCommandBuffer(swapchain->currentFrameCommandBuffer());
1656 rhiCtxD->setRenderTarget(swapchain->currentFrameRenderTarget());
1657 sampleCount = swapchain->sampleCount();
1659 QSGRendererInterface *rif = window->rendererInterface();
1661 QRhiCommandBuffer *cb =
static_cast<QRhiCommandBuffer *>(
1662 rif->getResource(window, QSGRendererInterface::RhiRedirectCommandBuffer));
1663 QRhiTextureRenderTarget *rt =
static_cast<QRhiTextureRenderTarget *>(
1664 rif->getResource(window, QSGRendererInterface::RhiRedirectRenderTarget));
1666 rhiCtxD->setMainRenderPassDescriptor(rt->renderPassDescriptor());
1667 rhiCtxD->setCommandBuffer(cb);
1668 rhiCtxD->setRenderTarget(rt);
1669 const auto descr = rt->description();
1670 const QRhiColorAttachment *color0 = descr.cbeginColorAttachments();
1671 if (color0 && color0->texture()) {
1672 sampleCount = color0->texture()->sampleCount();
1673 if (rt->resourceType() == QRhiResource::TextureRenderTarget) {
1674 const QRhiTextureRenderTargetDescription desc =
static_cast<QRhiTextureRenderTarget *>(rt)->description();
1675 for (
auto it = desc.cbeginColorAttachments(), end = desc.cendColorAttachments(); it != end; ++it) {
1676 if (it->multiViewCount() >= 2) {
1677 viewCount = it->multiViewCount();
1684 qWarning(
"Neither swapchain nor redirected command buffer and render target are available.");
1693 rhiCtxD->setMainPassSampleCount(sampleCount);
1701 rhiCtxD->setMainPassViewCount(viewCount);
1707inline void queryInlineRenderPassDescriptorAndCommandBuffer(QSGRenderNode *node, QSSGRhiContext *rhiCtx)
1709 QSGRenderNodePrivate *d = QSGRenderNodePrivate::get(node);
1710 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
1711 rhiCtxD->setMainRenderPassDescriptor(d->m_rt.rpDesc);
1712 rhiCtxD->setCommandBuffer(d->m_rt.cb);
1713 rhiCtxD->setRenderTarget(d->m_rt.rt);
1714 rhiCtxD->setMainPassSampleCount(d->m_rt.rt->sampleCount());
1715 rhiCtxD->setMainPassViewCount(1);
1729 if (!
renderer->m_sgContext->rhiContext()->isValid())
1731 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1733 renderer->renderStats()->startRenderPrepare();
1735 queryInlineRenderPassDescriptorAndCommandBuffer(
this,
renderer->m_sgContext->rhiContext().get());
1737 qreal dpr = window->effectiveDevicePixelRatio();
1738 const QSizeF itemSize =
renderer->surfaceSize() / dpr;
1739 QRectF viewport = matrix()->mapRect(QRectF(QPoint(0, 0), itemSize));
1740 viewport = QRectF(viewport.topLeft() * dpr, viewport.size() * dpr);
1741 const QRect vp = convertQtRectToGLViewport(viewport, window->size() * dpr);
1743 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1747 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32,
renderer->profilingId);
1749 renderer->renderStats()->endRenderPrepare();
1752void QQuick3DSGRenderNode::
render(
const QSGRenderNode::RenderState *state)
1756 const auto &rhiContext =
renderer->m_sgContext->rhiContext();
1758 if (rhiContext->isValid()) {
1760 renderer->renderStats()->startRender();
1761 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1762 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1764 queryInlineRenderPassDescriptorAndCommandBuffer(
this,
renderer->m_sgContext->rhiContext().get());
1767 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1768 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiContext)),
renderer->profilingId);
1782 return NoExternalRendering;
1786 : m_renderer(renderer)
1789 if (QSGRendererInterface::isApiRhiBased(window->rendererInterface()->graphicsApi())) {
1790 connect(window, &QQuickWindow::beforeRendering,
this, &QQuick3DSGDirectRenderer::prepare, Qt::DirectConnection);
1791 if (mode == Underlay)
1792 connect(window, &QQuickWindow::beforeRenderPassRecording,
this, &
QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1794 connect(window, &QQuickWindow::afterRenderPassRecording,
this, &
QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1805 m_viewport = viewport;
1810 if (m_isVisible == visible)
1812 m_isVisible = visible;
1818 renderPending =
true;
1819 requestFullUpdate(m_window);
1829 if (m_renderer->m_sgContext->rhiContext()->isValid())
1830 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1835 if (!m_isVisible || !m_renderer)
1838 if (m_renderer->m_sgContext->rhiContext()->isValid()) {
1840 if (m_renderer->m_postProcessingStack) {
1841 if (renderPending) {
1842 renderPending =
false;
1843 m_rhiTexture = m_renderer->renderToRhiTexture(m_window);
1846 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1847 const auto &quadRenderer = m_renderer->m_sgContext->renderer()->rhiQuadRenderer();
1848 quadRenderer->prepareQuad(m_renderer->m_sgContext->rhiContext().get(),
nullptr);
1849 if (m_renderer->m_requestedFramesCount > 0) {
1851 m_renderer->m_requestedFramesCount--;
1857 QQuick3DRenderStats *renderStats = m_renderer->renderStats();
1859 renderStats->startRenderPrepare();
1861 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1862 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1863 const QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->effectiveDevicePixelRatio());
1865 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1867 m_renderer->rhiPrepare(vp, m_window->effectiveDevicePixelRatio());
1868 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32, m_renderer->profilingId);
1871 renderStats->endRenderPrepare();
1878 if (!m_isVisible || !m_renderer)
1881 const auto &rhiContext = m_renderer->m_sgContext->rhiContext();
1883 if (rhiContext->isValid()) {
1894 if (m_renderer->m_postProcessingStack) {
1896 queryMainRenderPassDescriptorAndCommandBuffer(m_window, rhiContext.get());
1897 auto rhiCtx = m_renderer->m_sgContext->rhiContext().get();
1898 const auto &renderer = m_renderer->m_sgContext->renderer();
1899 QRhiCommandBuffer *cb = rhiContext->commandBuffer();
1900 cb->debugMarkBegin(QByteArrayLiteral(
"Post-processing result to main rt"));
1907 QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->effectiveDevicePixelRatio());
1909 const auto &shaderCache = m_renderer->m_sgContext->shaderCache();
1910 const auto &shaderPipeline = shaderCache->getBuiltInRhiShaders().getRhiSimpleQuadShader(m_renderer->m_layer->viewCount);
1912 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
1913 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge });
1914 QSSGRhiShaderResourceBindingList bindings;
1915 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, m_rhiTexture, sampler);
1916 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiContext.get());
1917 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
1919 QSSGRhiGraphicsPipelineState ps;
1920 ps.viewport = QRhiViewport(
float(vp.x()),
float(vp.y()),
float(vp.width()),
float(vp.height()));
1921 ps.samples = rhiCtx->mainPassSampleCount();
1922 ps.viewCount = m_renderer->m_layer->viewCount;
1923 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
1924 renderer->rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, rhiCtx->mainRenderPassDescriptor(), QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::PremulBlend);
1930 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1931 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1932 if (m_renderer->renderStats())
1933 m_renderer->renderStats()->startRender();
1935 queryMainRenderPassDescriptorAndCommandBuffer(m_window, rhiContext.get());
1939 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1940 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiContext)),
1941 m_renderer->profilingId);
1944 if (m_renderer->renderStats())
~QQuick3DSGDirectRenderer()
void setViewport(const QRectF &viewport)
void setVisibility(bool visible)
void render(const RenderState *state) override
This function is called by the renderer and should paint this node with directly invoking commands vi...
void releaseResources() override
This function is called when all custom graphics resources allocated by this node have to be freed im...
RenderingFlags flags() const override
void prepare() override
Called from the frame preparation phase.
QQuick3DSceneRenderer * renderer
StateFlags changedStates() const override
This function should return a mask where each bit represents graphics states changed by the \l render...
PickResultList syncPick(const QSSGRenderRay &ray)
QQuick3DSceneRenderer(const std::shared_ptr< QSSGRenderContextInterface > &rci)
void invalidateFramebufferObject()
void rhiPrepare(const QRect &viewport, qreal displayPixelRatio)
PickResultList syncPickSubset(const QSSGRenderRay &ray, QVarLengthArray< QSSGRenderNode * > subset)
void synchronize(QQuick3DViewport *view3D, const QSize &size, float dpr)
std::optional< QSSGRenderRay > getRayFromViewportPos(const QPointF &pos)
PickResultList syncPickAll(const QSSGRenderRay &ray)
void setGlobalPickingEnabled(bool isEnabled)
QQuick3DRenderStats * renderStats()
QList< const QSSGRenderNode * > syncPickInFrustum(const QSSGFrustum &frustum)
void releaseCachedResources()
friend class QSSGLayerRenderData
SGFramebufferObjectNode()
~SGFramebufferObjectNode() override
QQuick3DSceneRenderer * renderer
void handleScreenChange()
QSGTexture * texture() const override
Returns a pointer to the texture object.
void preprocess() override
Override this function to do processing on the node before it is rendered.
QQuick3DViewport * quickFbo
Combined button and popup list for selecting options.
Q_TRACE_POINT(qtcore, QCoreApplication_postEvent_exit)
Q_TRACE_POINT(qtcore, QFactoryLoader_update, const QString &fileName)
Q_TRACE_POINT(qtquick3d, QSSG_renderFrame_entry, int width, int height)
static void bfs(In *inExtension, QList< Out * > &outList)
static const QVector2D s_ProgressiveAABlendFactors[QSSGLayerRenderData::MAX_AA_LEVELS]
static QVector3D tonemapRgb(const QVector3D &c, QQuick3DSceneEnvironment::QQuick3DEnvironmentTonemapModes tonemapMode)
static bool dumpRenderTimes()
Q_TRACE_POINT(qtquick3d, QSSG_synchronize_entry, QQuick3DViewport *view3D, const QSize &size, float dpr)
static const QVector2D s_TemporalAABlendFactors
static void requestFullUpdate(QQuickWindow *window)