16#include "extensions/qquick3drenderextensions.h"
17#include <QtQuick3DUtils/private/qquick3dprofiler_p.h>
19#include <QtQuick3DRuntimeRender/private/qssgrendererutil_p.h>
20#include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
22#include <QtQuick/private/qquickwindow_p.h>
23#include <QtQuick/private/qsgdefaultrendercontext_p.h>
24#include <QtQuick/private/qsgtexture_p.h>
25#include <QtQuick/private/qsgplaintexture_p.h>
26#include <QtQuick/private/qsgrendernode_p.h>
28#include <QtQuick3DRuntimeRender/private/qssgrendereffect_p.h>
29#include <QtQuick3DRuntimeRender/private/qssgrhieffectsystem_p.h>
30#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
31#include <QtQuick3DRuntimeRender/private/qssgrhiquadrenderer_p.h>
32#include <QtQuick3DRuntimeRender/private/qssgrhicontext_p.h>
33#include <QtQuick3DRuntimeRender/private/qssgcputonemapper_p.h>
34#include <QtQuick3DRuntimeRender/private/qssgrenderroot_p.h>
35#include <QtQuick3DUtils/private/qssgutils_p.h>
36#include <QtQuick3DUtils/private/qssgassert_p.h>
39#include <qtquick3d_tracepoints_p.h>
41#include <QtCore/QObject>
42#include <QtCore/qqueue.h>
46Q_TRACE_PREFIX(qtquick3d,
48 "class QQuick3DViewport;"
52Q_TRACE_POINT(qtquick3d, QSSG_prepareFrame_entry,
int width,
int height);
63 static bool val = (qEnvironmentVariableIntValue(
"QT_QUICK3D_DUMP_RENDERTIMES") > 0);
67#if QT_CONFIG(qml_debug)
69static inline quint64 statDrawCallCount(
const QSSGRhiContextStats &stats)
72 const QSSGRhiContextStats::PerLayerInfo &info(stats.perLayerInfo[stats.layerKey]);
73 for (
const auto &pass : info.renderPasses)
74 count += QSSGRhiContextStats::totalDrawCallCountForPass(pass);
75 count += QSSGRhiContextStats::totalDrawCallCountForPass(info.externalRenderPass);
79#define STAT_PAYLOAD(stats)
80 (statDrawCallCount(stats) | (quint64(stats.perLayerInfo[stats.layerKey].renderPasses.size()) << 32
))
84template <
typename In,
typename Out>
85static void bfs(In *inExtension, QList<Out *> &outList)
87 QSSG_ASSERT(inExtension,
return);
89 QQueue<In *> queue { { inExtension } };
90 while (queue.size() > 0) {
91 if (
auto cur = queue.dequeue()) {
92 if (
auto *ext =
static_cast<Out *>(QQuick3DObjectPrivate::get(cur)->spatialNode))
93 outList.push_back(ext);
94 for (
auto &chld : cur->childItems())
95 queue.enqueue(qobject_cast<In *>(chld));
105 , devicePixelRatio(1)
107 qsgnode_set_description(
this, QStringLiteral(
"fbonode"));
108 setFlag(QSGNode::UsePreprocess,
true);
120 markDirty(DirtyMaterial);
125 return QSGSimpleTextureNode::texture();
138 if (QThread::currentThread() == QCoreApplication::instance()->thread())
141 QCoreApplication::postEvent(window,
new QEvent(QEvent::Type(QQuickWindowPrivate::FullUpdateRequest)));
148 renderer->renderStats()->startRender();
152 if (
renderer->m_sgContext->rhiContext()->isValid()) {
153 QRhiTexture *rhiTexture = renderer->renderToRhiTexture(window);
154 bool needsNewWrapper =
false;
155 if (!texture() || (texture()->textureSize() != renderer->surfaceSize()
156 || texture()->rhiTexture() != rhiTexture))
158 needsNewWrapper =
true;
160 if (needsNewWrapper) {
162 QSGPlainTexture *t =
new QSGPlainTexture;
163 t->setOwnsTexture(
false);
164 t->setHasAlphaChannel(
true);
165 t->setTexture(rhiTexture);
166 t->setTextureSize(
renderer->surfaceSize());
171 markDirty(QSGNode::DirtyMaterial);
172 emit textureChanged();
177 if (
renderer->m_requestedFramesCount > 0) {
179 requestFullUpdate(window);
187 if (!qFuzzyCompare(window->effectiveDevicePixelRatio(), devicePixelRatio)) {
201 const auto &rhiCtx = m_sgContext->rhiContext();
202 QSSGRhiContextStats::get(*rhiCtx).cleanupLayerInfo(m_layer);
203 m_sgContext->bufferManager()->releaseResourcesForLayer(m_layer);
210 removeNodeFromLayer(m_sceneRootNode);
216 winAttacment->queueForCleanup(m_layer);
224 releaseAaDependentRhiResources();
225 delete m_effectSystem;
230 const auto &rhiCtx = m_sgContext->rhiContext();
231 if (!rhiCtx->isValid())
234 delete m_textureRenderTarget;
235 m_textureRenderTarget =
nullptr;
237 delete m_textureRenderPassDescriptor;
238 m_textureRenderPassDescriptor =
nullptr;
240 delete m_depthStencilBuffer;
241 m_depthStencilBuffer =
nullptr;
243 delete m_multiViewDepthStencilBuffer;
244 m_multiViewDepthStencilBuffer =
nullptr;
246 delete m_msaaRenderBufferLegacy;
247 m_msaaRenderBufferLegacy =
nullptr;
249 delete m_msaaRenderTexture;
250 m_msaaRenderTexture =
nullptr;
252 delete m_msaaMultiViewRenderBuffer;
253 m_msaaMultiViewRenderBuffer =
nullptr;
255 delete m_ssaaTexture;
256 m_ssaaTexture =
nullptr;
258 delete m_ssaaTextureToTextureRenderTarget;
259 m_ssaaTextureToTextureRenderTarget =
nullptr;
261 delete m_ssaaTextureToTextureRenderPassDescriptor;
262 m_ssaaTextureToTextureRenderPassDescriptor =
nullptr;
264 delete m_temporalAATexture;
265 m_temporalAATexture =
nullptr;
266 delete m_temporalAARenderTarget;
267 m_temporalAARenderTarget =
nullptr;
268 delete m_temporalAARenderPassDescriptor;
269 m_temporalAARenderPassDescriptor =
nullptr;
271 delete m_prevTempAATexture;
272 m_prevTempAATexture =
nullptr;
277 QVector2D(0.500000f, 0.500000f),
278 QVector2D(0.333333f, 0.666667f),
279 QVector2D(0.250000f, 0.750000f),
280 QVector2D(0.200000f, 0.800000f),
281 QVector2D(0.166667f, 0.833333f),
282 QVector2D(0.142857f, 0.857143f),
283 QVector2D(0.125000f, 0.875000f),
284 QVector2D(0.111111f, 0.888889f),
294 QRhiTexture *currentTexture = m_texture;
298 m_renderStats->startRenderPrepare();
300 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
302 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
303 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
305 rhiCtxD->setMainRenderPassDescriptor(m_textureRenderPassDescriptor);
306 rhiCtxD->setRenderTarget(m_textureRenderTarget);
308 QRhiCommandBuffer *cb =
nullptr;
309 QRhiSwapChain *swapchain = qw->swapChain();
311 cb = swapchain->currentFrameCommandBuffer();
312 rhiCtxD->setCommandBuffer(cb);
314 QSGRendererInterface *rif = qw->rendererInterface();
315 cb =
static_cast<QRhiCommandBuffer *>(
316 rif->getResource(qw, QSGRendererInterface::RhiRedirectCommandBuffer));
318 rhiCtxD->setCommandBuffer(cb);
320 qWarning(
"Neither swapchain nor redirected command buffer are available.");
321 return currentTexture;
327 rhiCtxD->setMainPassSampleCount(m_msaaRenderBufferLegacy ? m_msaaRenderBufferLegacy->sampleCount() :
328 (m_msaaRenderTexture ? m_msaaRenderTexture->sampleCount() :
329 (m_msaaMultiViewRenderBuffer ? m_msaaMultiViewRenderBuffer->sampleCount() : 1)));
333 int ssaaAdjustedWidth = m_surfaceSize.width();
334 int ssaaAdjustedHeight = m_surfaceSize.height();
335 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
336 ssaaAdjustedWidth *= m_layer->ssaaMultiplier;
337 ssaaAdjustedHeight *= m_layer->ssaaMultiplier;
340 Q_TRACE(QSSG_prepareFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
342 float dpr = m_sgContext->renderer()->dpr();
343 const QRect vp = QRect(0, 0, ssaaAdjustedWidth, ssaaAdjustedHeight);
348 m_renderStats->endRenderPrepare();
350 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, profilingId);
352 Q_TRACE(QSSG_prepareFrame_exit);
354 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
355 Q_TRACE(QSSG_renderFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
357 QColor clearColor = Qt::transparent;
358 if (m_backgroundMode == QSSGRenderLayer::Background::Color
359 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBoxCubeMap && !m_layer->skyBoxCubeMap)
360 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBox && !m_layer->lightProbe))
364 clearColor = m_layer->firstEffect ? m_linearBackgroundColor : m_tonemappedBackgroundColor;
369 cb->beginPass(m_textureRenderTarget, clearColor, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
370 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
371 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(m_textureRenderTarget));
374 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
375 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, QByteArrayLiteral(
"main"));
377 const bool temporalAA = m_layer->temporalAAIsActive;
378 const bool progressiveAA = m_layer->progressiveAAIsActive;
379 const bool superSamplingAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA;
380 QRhi *rhi = rhiCtx->rhi();
382 currentTexture = superSamplingAA ? m_ssaaTexture : m_texture;
385 if (m_effectSystem && m_layer->firstEffect && !m_layer->renderedCameras.isEmpty()) {
386 const auto &renderer = m_sgContext->renderer();
388 Q_ASSERT(theRenderData);
389 QRhiTexture *theDepthTexture = theRenderData->getRenderResult(QSSGFrameData::RenderResult::DepthTexture)->texture;
390 QRhiTexture *theNormalTexture = theRenderData->getRenderResult(QSSGFrameData::RenderResult::NormalTexture)->texture;
391 currentTexture = m_effectSystem->process(*m_layer,
401 if ((progressiveAA || temporalAA) && m_prevTempAATexture) {
402 cb->debugMarkBegin(QByteArrayLiteral(
"Temporal AA"));
403 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
404 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"Temporal AA"));
405 QRhiTexture *blendResult;
406 uint *aaIndex = progressiveAA ? &m_layer->progAAPassIndex : &m_layer->tempAAPassIndex;
409 if (temporalAA || *aaIndex < quint32(m_layer->antialiasingQuality)) {
410 const auto &renderer = m_sgContext->renderer();
415 const auto &shaderPipeline = m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiProgressiveAAShader();
416 QRhiResourceUpdateBatch *rub =
nullptr;
418 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ m_layer,
nullptr,
nullptr, 0 }));
419 QRhiBuffer *&ubuf = dcd.ubuf;
420 const int ubufSize = 2 *
sizeof(
float);
422 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
426 rub = rhi->nextResourceUpdateBatch();
427 int idx = *aaIndex - 1;
428 const QVector2D *blendFactors = progressiveAA ? &s_ProgressiveAABlendFactors[idx] : &s_TemporalAABlendFactors;
429 rub->updateDynamicBuffer(ubuf, 0, 2 *
sizeof(
float), blendFactors);
430 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx, rub);
432 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
433 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
434 QSSGRhiShaderResourceBindingList bindings;
435 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
436 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
437 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, m_prevTempAATexture, sampler);
439 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
441 QSSGRhiGraphicsPipelineState ps;
442 const QSize textureSize = currentTexture->pixelSize();
443 ps.viewport = QRhiViewport(0, 0,
float(textureSize.width()),
float(textureSize.height()));
444 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
446 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_temporalAARenderTarget, QSSGRhiQuadRenderer::UvCoords);
447 blendResult = m_temporalAATexture;
449 blendResult = m_prevTempAATexture;
453 blendResult = currentTexture;
456 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
458 if (temporalAA || (*aaIndex < quint32(m_layer->antialiasingQuality))) {
459 auto *rub = rhi->nextResourceUpdateBatch();
461 rub->copyTexture(m_prevTempAATexture, blendResult);
463 rub->copyTexture(m_prevTempAATexture, currentTexture);
464 cb->resourceUpdate(rub);
469 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"temporal_aa"));
471 currentTexture = blendResult;
474 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
484 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
485 const auto &renderer = m_sgContext->renderer();
487 cb->debugMarkBegin(QByteArrayLiteral(
"SSAA downsample"));
488 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
490 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"SSAA downsample"));
492 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
499 const auto &shaderPipeline = m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiSupersampleResolveShader(m_layer->viewCount);
501 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
502 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
503 QSSGRhiShaderResourceBindingList bindings;
504 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
505 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
507 QSSGRhiGraphicsPipelineState ps;
508 ps.viewport = QRhiViewport(0, 0,
float(m_surfaceSize.width()),
float(m_surfaceSize.height()));
509 ps.viewCount = m_layer->viewCount;
510 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
512 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_ssaaTextureToTextureRenderTarget, QSSGRhiQuadRenderer::UvCoords);
514 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"ssaa_downsample"));
516 currentTexture = m_texture;
519 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
520 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiCtx)),
524 Q_TRACE(QSSG_renderFrame_exit);
528 return currentTexture;
533 m_sgContext->renderer()->beginFrame(*m_layer);
538 m_sgContext->renderer()->endFrame(*m_layer);
546 const auto &renderer = m_sgContext->renderer();
548 renderer->setDpr(displayPixelRatio);
550 renderer->setViewport(viewport);
552 renderer->prepareLayerForRender(*m_layer);
556 const bool renderReady = !m_layer->renderData->renderedCameras.isEmpty();
558 renderer->rhiPrepare(*m_layer);
569 m_sgContext->renderer()->rhiRender(*m_layer);
575#if QT_CONFIG(quick_shadereffect)
576static QRhiTexture::Format toRhiTextureFormat(QQuickShaderEffectSource::Format format)
579 case QQuickShaderEffectSource::RGBA8:
580 return QRhiTexture::RGBA8;
581 case QQuickShaderEffectSource::RGBA16F:
582 return QRhiTexture::RGBA16F;
583 case QQuickShaderEffectSource::RGBA32F:
584 return QRhiTexture::RGBA32F;
586 return QRhiTexture::RGBA8;
591static QVector3D tonemapRgb(
const QVector3D &c, QQuick3DSceneEnvironment::QQuick3DEnvironmentTonemapModes tonemapMode)
593 switch (tonemapMode) {
594 case QQuick3DSceneEnvironment::TonemapModeLinear:
595 return QSSGTonemapper::tonemapLinearToSrgb(c);
596 case QQuick3DSceneEnvironment::TonemapModeHejlDawson:
597 return QSSGTonemapper::tonemapHejlDawson(c);
598 case QQuick3DSceneEnvironment::TonemapModeAces:
599 return QSSGTonemapper::tonemapAces(c);
600 case QQuick3DSceneEnvironment::TonemapModeFilmic:
601 return QSSGTonemapper::tonemapFilmic(c);
610 Q_TRACE_SCOPE(QSSG_synchronize, view3D, size, dpr);
612 Q_ASSERT(view3D !=
nullptr);
613 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
614 Q_ASSERT(rhiCtx !=
nullptr);
618 m_layer =
new QSSGRenderLayer();
620 bool newRenderStats =
false;
621 if (!m_renderStats) {
622 m_renderStats = view3D->renderStats();
623 newRenderStats =
true;
627 m_renderStats->startSync();
629 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DSynchronizeFrame);
631 m_sgContext->renderer()->setDpr(dpr);
632 bool layerSizeIsDirty = m_surfaceSize != size;
633 m_surfaceSize = size;
635 QQuick3DSceneEnvironment *environment = view3D->environment();
636 if (environment->lightmapper()) {
637 QQuick3DLightmapper *lightmapper = environment->lightmapper();
638 lmOptions.opacityThreshold = lightmapper->opacityThreshold();
639 lmOptions.bias = lightmapper->bias();
640 lmOptions.useAdaptiveBias = lightmapper->isAdaptiveBiasEnabled();
641 lmOptions.indirectLightEnabled = lightmapper->isIndirectLightEnabled();
642 lmOptions.indirectLightSamples = lightmapper->samples();
643 lmOptions.indirectLightWorkgroupSize = lightmapper->indirectLightWorkgroupSize();
644 lmOptions.indirectLightBounces = lightmapper->bounces();
645 lmOptions.indirectLightFactor = lightmapper->indirectLightFactor();
646 lmOptions.sigma = lightmapper->denoiseSigma();
647 lmOptions.texelsPerUnit = lightmapper->texelsPerUnit();
653 const QQmlContext *context = qmlContext(view3D);
654 const QUrl originalSource = environment->lightmapper() ? environment->lightmapper()->source()
655 : QUrl::fromLocalFile(QStringLiteral(
"lightmaps.bin"));
656 const auto resolvedUrl = context ? context->resolvedUrl(originalSource) : originalSource;
657 const auto qmlSource = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
658 const QString lightmapSource = qmlSource.isEmpty() ? originalSource.path() : qmlSource;
659 lmOptions.source = lightmapSource;
660 m_layer->lightmapSource = lightmapSource;
663 m_sgContext->bufferManager()->setLightmapSource(lightmapSource);
667 QSet<QSSGRenderGraphObject *> resourceLoaders;
668 QQuick3DWindowAttachment::SyncResult requestSharedUpdate = QQuick3DWindowAttachment::SyncResultFlag::None;
669 if (
auto window = view3D->window()) {
670 if (!winAttacment || winAttacment->window() != window)
671 winAttacment = QQuick3DSceneManager::getOrSetWindowAttachment(*window);
673 if (winAttacment && winAttacment->rci() != m_sgContext)
674 winAttacment->setRci(m_sgContext);
676 QSSGRenderRoot *rootNode = winAttacment->rootNode();
677 if (m_layer->rootNode != rootNode) {
678 Q_ASSERT(m_layer->rootNode ==
nullptr);
679 rootNode->addChild(*m_layer);
680 rootNode->setStartVersion(m_layer->h.version());
681 m_layer->ref(rootNode);
685 requestSharedUpdate |= winAttacment->synchronize(resourceLoaders);
689 QQuick3DNode *importScene = view3D->importScene();
691 QQuick3DSceneManager *importSceneManager = QQuick3DObjectPrivate::get(importScene)->sceneManager;
694 if (
auto window = importSceneManager->window(); window && window != view3D->window()) {
695 if (
auto winAttacment = importSceneManager->wattached) {
697 auto rci = winAttacment->rci();
698 const bool inlineSync = (rci && rci->rhi() && (rci->rhi()->thread() == m_sgContext->rhi()->thread()));
702 winAttacment->synchronize(resourceLoaders);
703 }
else if (rci && !window->isExposed()) {
705 winAttacment->synchronize(resourceLoaders);
706 }
else if (!rci || (requestSharedUpdate & QQuick3DWindowAttachment::SyncResultFlag::SharedResourcesDirty)) {
711 winAttacment->requestUpdate();
724 m_layer->viewCount = rhiCtx->mainPassViewCount();
725 updateLayerNode(*m_layer, *view3D, resourceLoaders.values());
729 m_requestedFramesCount = 0;
730 if (m_layer->isProgressiveAAEnabled()) {
734 m_requestedFramesCount =
int(m_layer->antialiasingQuality) + 1;
735 }
else if (m_layer->isTemporalAAEnabled()) {
740 m_requestedFramesCount = (m_aaIsDirty || m_temporalIsDirty) ? QSSGLayerRenderData::MAX_TEMPORAL_AA_LEVELS : 1;
745 for (QSSGRenderEffect *effectNode = m_layer->firstEffect; effectNode; effectNode = effectNode->m_nextEffect)
746 effectNode->finalizeShaders(*m_layer, m_sgContext.get());
749 m_renderStats->setRhiContext(rhiCtx, m_layer);
752 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm && sm->textureExtensionsDirty) {
753 m_layer->renderExtensions[size_t(QSSGRenderLayer::RenderExtensionStage::TextureProviders)] = sm->textureProviderExtensions;
754 sm->textureExtensionsDirty =
false;
758 if ((requestSharedUpdate & QQuick3DWindowAttachment::SyncResultFlag::ExtensionsDiry) || view3D->extensionListDirty()) {
761 for (size_t i = size_t(QSSGRenderLayer::RenderExtensionStage::Underlay); i != size_t(QSSGRenderLayer::RenderExtensionStage::Count); ++i)
762 m_layer->renderExtensions[i].clear();
765 const auto &extensions = view3D->extensionList();
766 for (
const auto &ext : extensions) {
767 const auto type = QQuick3DObjectPrivate::get(ext)->type;
768 if (QSSGRenderGraphObject::isExtension(type)) {
769 if (type == QSSGRenderGraphObject::Type::RenderExtension) {
770 if (
auto *renderExt = qobject_cast<QQuick3DRenderExtension *>(ext)) {
771 if (QQuick3DObjectPrivate::get(renderExt)->spatialNode) {
772 const auto stage =
static_cast<QSSGRenderExtension *>(QQuick3DObjectPrivate::get(renderExt)->spatialNode)->stage();
773 QSSG_ASSERT(size_t(stage) < std::size(m_layer->renderExtensions),
continue);
774 auto &list = m_layer->renderExtensions[size_t(stage)];
775 bfs(qobject_cast<QQuick3DRenderExtension *>(ext), list);
782 view3D->clearExtensionListDirty();
785 bool postProcessingNeeded = m_layer->firstEffect;
786 bool postProcessingWasActive = m_effectSystem;
787 QSSGRenderTextureFormat::Format effectOutputFormatOverride = QSSGRenderTextureFormat::Unknown;
788 if (postProcessingNeeded) {
789 QSSGRenderEffect *lastEffect = m_layer->firstEffect;
790 while (lastEffect->m_nextEffect)
791 lastEffect = lastEffect->m_nextEffect;
792 effectOutputFormatOverride = QSSGRhiEffectSystem::overriddenOutputFormat(lastEffect);
794 const auto layerTextureFormat = [effectOutputFormatOverride, view3D](QRhi *rhi,
bool postProc) {
795 if (effectOutputFormatOverride != QSSGRenderTextureFormat::Unknown)
796 return QSSGBufferManager::toRhiFormat(effectOutputFormatOverride);
811 const QRhiTexture::Format preferredPostProcFormat = QRhiTexture::RGBA16F;
812 if (postProc && rhi->isTextureFormatSupported(preferredPostProcFormat))
813 return preferredPostProcFormat;
815#if QT_CONFIG(quick_shadereffect)
816 const QRhiTexture::Format preferredView3DFormat = toRhiTextureFormat(view3D->renderFormat());
817 if (rhi->isTextureFormatSupported(preferredView3DFormat))
818 return preferredView3DFormat;
821 return QRhiTexture::RGBA8;
823 bool postProcessingStateDirty = postProcessingNeeded != postProcessingWasActive;
826 m_backgroundMode = QSSGRenderLayer::Background(view3D->environment()->backgroundMode());
830 QColor currentUserBackgroundColor = view3D->environment()->clearColor();
831 if (m_userBackgroundColor != currentUserBackgroundColor) {
832 m_userBackgroundColor = currentUserBackgroundColor;
833 m_linearBackgroundColor = QSSGUtils::color::sRGBToLinearColor(m_userBackgroundColor);
834 const QVector3D tc = tonemapRgb(QVector3D(m_linearBackgroundColor.redF(),
835 m_linearBackgroundColor.greenF(),
836 m_linearBackgroundColor.blueF()),
837 view3D->environment()->tonemapMode());
838 m_tonemappedBackgroundColor = QColor::fromRgbF(tc.x(), tc.y(), tc.z(), m_linearBackgroundColor.alphaF());
840 m_layer->scissorRect = QRect(view3D->environment()->scissorRect().topLeft() * dpr,
841 view3D->environment()->scissorRect().size() * dpr);
847 auto sceneRootNode =
static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(view3D->scene())->spatialNode);
848 if (sceneRootNode != m_sceneRootNode) {
850 removeNodeFromLayer(m_sceneRootNode);
853 addNodeToLayer(sceneRootNode);
855 m_sceneRootNode = sceneRootNode;
859 QSSGRenderNode *importSceneRootNode =
nullptr;
861 importSceneRootNode =
static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(importScene)->spatialNode);
863 if (importSceneRootNode != m_importSceneRootNode) {
864 if (m_importSceneRootNode)
865 m_layer->removeImportScene(*m_importSceneRootNode);
867 if (importSceneRootNode) {
871 QObject *sceneParent = importScene->parent();
872 bool isEmbedded =
false;
873 while (sceneParent) {
874 if (sceneParent == view3D) {
878 sceneParent = sceneParent->parent();
881 m_layer->setImportScene(*importSceneRootNode);
884 m_importSceneRootNode = importSceneRootNode;
892 QSSGRenderRoot *rootNode = winAttacment->rootNode();
893 if (rootNode->isDirty(QSSGRenderRoot::DirtyFlag::TreeDirty)) {
895 for (QSSGRenderNode &layer : rootNode->children) {
896 if (QSSG_GUARD_X(layer.type == QSSGRenderGraphObject::Type::Layer,
"Layer type mismatch"))
897 static_cast<QSSGRenderLayer &>(layer).markDirty(QSSGRenderLayer::DirtyFlag::TreeDirty);
902 maybeSetupLightmapBaking(view3D);
904 if (m_useFBO && rhiCtx->isValid()) {
905 QRhi *rhi = rhiCtx->rhi();
906 const QSize renderSize = m_layer->isSsaaEnabled() ? m_surfaceSize * m_layer->ssaaMultiplier : m_surfaceSize;
910 if (layerSizeIsDirty || postProcessingStateDirty) {
911 m_texture->setPixelSize(m_surfaceSize);
912 m_texture->setFormat(layerTextureFormat(rhi, postProcessingNeeded));
924 if (postProcessingStateDirty && (m_layer->antialiasingMode != QSSGRenderLayer::AAMode::NoAA || m_layer->isTemporalAAEnabled())) {
925 releaseAaDependentRhiResources();
928 m_ssaaTexture->setPixelSize(renderSize);
929 m_ssaaTexture->create();
931 if (m_depthStencilBuffer) {
932 m_depthStencilBuffer->setPixelSize(renderSize);
933 m_depthStencilBuffer->create();
935 if (m_multiViewDepthStencilBuffer) {
936 m_multiViewDepthStencilBuffer->setPixelSize(renderSize);
937 m_multiViewDepthStencilBuffer->create();
939 if (m_msaaRenderBufferLegacy) {
940 m_msaaRenderBufferLegacy->setPixelSize(renderSize);
941 m_msaaRenderBufferLegacy->create();
943 if (m_msaaRenderTexture) {
944 m_msaaRenderTexture->setPixelSize(renderSize);
945 m_msaaRenderTexture->create();
947 if (m_msaaMultiViewRenderBuffer) {
948 m_msaaMultiViewRenderBuffer->setPixelSize(renderSize);
949 m_msaaMultiViewRenderBuffer->create();
955 if (postProcessingStateDirty) {
956 delete m_textureRenderPassDescriptor;
957 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
958 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
960 m_textureRenderTarget->create();
961 if (m_ssaaTextureToTextureRenderTarget)
962 m_ssaaTextureToTextureRenderTarget->create();
964 if (m_temporalAATexture) {
965 m_temporalAATexture->setPixelSize(renderSize);
966 m_temporalAATexture->create();
968 if (m_prevTempAATexture) {
969 m_prevTempAATexture->setPixelSize(renderSize);
970 m_prevTempAATexture->create();
972 if (m_temporalAARenderTarget)
973 m_temporalAARenderTarget->create();
976 }
else if (m_aaIsDirty && rhi->backend() == QRhi::Metal) {
981 releaseAaDependentRhiResources();
984 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget
985 | QRhiTexture::UsedAsTransferSource;
986 const QRhiTexture::Format textureFormat = layerTextureFormat(rhi, postProcessingNeeded);
989 if (m_layer->viewCount >= 2)
990 m_texture = rhi->newTextureArray(textureFormat, m_layer->viewCount, m_surfaceSize, 1, textureFlags);
992 m_texture = rhi->newTexture(textureFormat, m_surfaceSize, 1, textureFlags);
996 if (!m_ssaaTexture && m_layer->isSsaaEnabled()) {
997 if (m_layer->viewCount >= 2)
998 m_ssaaTexture = rhi->newTextureArray(textureFormat, m_layer->viewCount, renderSize, 1, textureFlags);
1000 m_ssaaTexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1001 m_ssaaTexture->create();
1004 if (m_timeBasedAA && !m_temporalAATexture) {
1005 m_temporalAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1006 m_temporalAATexture->create();
1007 m_prevTempAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1008 m_prevTempAATexture->create();
1012 if (m_aaIsDirty || layerSizeIsDirty)
1013 m_layer->tempAAPassIndex = m_layer->progAAPassIndex = 0;
1017 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::MSAA) {
1018 if (rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer)) {
1019 m_samples = qMax(1,
int(m_layer->antialiasingQuality));
1025 const QVector<
int> supported = rhi->supportedSampleCounts();
1026 if (!supported.contains(m_samples)) {
1027 if (!supported.isEmpty()) {
1028 auto it = std::lower_bound(supported.cbegin(), supported.cend(), m_samples);
1029 m_samples = it == supported.cend() ? supported.last() : *it;
1035 static bool warned =
false;
1038 qWarning(
"Multisample renderbuffers are not supported, disabling MSAA for Offscreen View3D");
1044 if (m_layer->viewCount >= 2) {
1045 if (!m_multiViewDepthStencilBuffer) {
1046 const auto format = rhi->isTextureFormatSupported(QRhiTexture::D24S8) ? QRhiTexture::D24S8 : QRhiTexture::D32FS8;
1047 m_multiViewDepthStencilBuffer = rhi->newTextureArray(format, m_layer->viewCount, renderSize,
1048 m_samples, QRhiTexture::RenderTarget);
1049 m_multiViewDepthStencilBuffer->create();
1052 if (!m_depthStencilBuffer) {
1053 m_depthStencilBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, renderSize, m_samples);
1054 m_depthStencilBuffer->create();
1058 if (!m_textureRenderTarget) {
1059 QRhiTextureRenderTargetDescription rtDesc;
1060 QRhiColorAttachment att;
1061 if (m_samples > 1) {
1062 if (m_layer->viewCount >= 2) {
1063 m_msaaMultiViewRenderBuffer = rhi->newTextureArray(textureFormat, m_layer->viewCount, renderSize, m_samples, QRhiTexture::RenderTarget);
1064 m_msaaMultiViewRenderBuffer->create();
1065 att.setTexture(m_msaaMultiViewRenderBuffer);
1067 if (!rhi->isFeatureSupported(QRhi::MultisampleTexture)) {
1069 m_msaaRenderBufferLegacy = rhi->newRenderBuffer(QRhiRenderBuffer::Color, renderSize, m_samples, {}, m_texture->format());
1070 m_msaaRenderBufferLegacy->create();
1071 att.setRenderBuffer(m_msaaRenderBufferLegacy);
1078 m_msaaRenderTexture = rhi->newTexture(textureFormat, renderSize, m_samples, QRhiTexture::RenderTarget);
1079 m_msaaRenderTexture->create();
1080 att.setTexture(m_msaaRenderTexture);
1083 att.setResolveTexture(m_texture);
1085 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA)
1086 att.setTexture(m_ssaaTexture);
1088 att.setTexture(m_texture);
1090 att.setMultiViewCount(m_layer->viewCount);
1091 rtDesc.setColorAttachments({ att });
1092 if (m_depthStencilBuffer)
1093 rtDesc.setDepthStencilBuffer(m_depthStencilBuffer);
1094 if (m_multiViewDepthStencilBuffer)
1095 rtDesc.setDepthTexture(m_multiViewDepthStencilBuffer);
1097 m_textureRenderTarget = rhi->newTextureRenderTarget(rtDesc);
1098 m_textureRenderTarget->setName(QByteArrayLiteral(
"View3D"));
1099 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
1100 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
1101 m_textureRenderTarget->create();
1104 if (!m_ssaaTextureToTextureRenderTarget && m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
1105 QRhiColorAttachment att(m_texture);
1106 att.setMultiViewCount(m_layer->viewCount);
1107 m_ssaaTextureToTextureRenderTarget = rhi->newTextureRenderTarget(QRhiTextureRenderTargetDescription({ att }));
1108 m_ssaaTextureToTextureRenderTarget->setName(QByteArrayLiteral(
"SSAA texture"));
1109 m_ssaaTextureToTextureRenderPassDescriptor = m_ssaaTextureToTextureRenderTarget->newCompatibleRenderPassDescriptor();
1110 m_ssaaTextureToTextureRenderTarget->setRenderPassDescriptor(m_ssaaTextureToTextureRenderPassDescriptor);
1111 m_ssaaTextureToTextureRenderTarget->create();
1114 if (m_layer->firstEffect) {
1115 if (!m_effectSystem)
1116 m_effectSystem =
new QSSGRhiEffectSystem(m_sgContext);
1117 m_effectSystem->setup(renderSize);
1118 }
else if (m_effectSystem) {
1119 delete m_effectSystem;
1120 m_effectSystem =
nullptr;
1123 if (m_timeBasedAA && !m_temporalAARenderTarget) {
1124 m_temporalAARenderTarget = rhi->newTextureRenderTarget({ m_temporalAATexture });
1125 m_temporalAARenderTarget->setName(QByteArrayLiteral(
"Temporal AA texture"));
1126 m_temporalAARenderPassDescriptor = m_temporalAARenderTarget->newCompatibleRenderPassDescriptor();
1127 m_temporalAARenderTarget->setRenderPassDescriptor(m_temporalAARenderPassDescriptor);
1128 m_temporalAARenderTarget->create();
1131 m_textureNeedsFlip = rhi->isYUpInFramebuffer();
1132 m_aaIsDirty =
false;
1136 m_renderStats->endSync(dumpRenderTimes());
1138 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DSynchronizeFrame, quint64(m_surfaceSize.width()) | quint64(m_surfaceSize.height()) << 32, profilingId);
1144 fboNode->invalidatePending =
true;
1149 if (m_layer && m_layer->renderData) {
1150 if (
const auto &mgr = m_layer->renderData->getShadowMapManager())
1151 mgr->releaseCachedResources();
1152 if (
const auto &mgr = m_layer->renderData->getReflectionMapManager())
1153 mgr->releaseCachedResources();
1159 if (!m_layer || !m_layer->renderData)
1160 return std::nullopt;
1162 QMutexLocker locker(&m_layer->renderedCamerasMutex);
1164 if (m_layer->renderedCameras.isEmpty())
1165 return std::nullopt;
1167 QMatrix4x4 globalTransform = m_layer->renderData->getGlobalTransform(*m_layer->renderedCameras[0]);
1169 const QVector2D viewportSize(m_surfaceSize.width(), m_surfaceSize.height());
1170 const QVector2D position(
float(pos.x()),
float(pos.y()));
1171 const QRectF viewportRect(QPointF{}, QSizeF(m_surfaceSize));
1175 QVector2D correctCoords(position.x(), viewportSize.y() - position.y());
1176 QVector2D theLocalMouse = QSSGUtils::rect::toRectRelative(viewportRect, correctCoords);
1177 if ((theLocalMouse.x() < 0.0f || theLocalMouse.x() >= viewportSize.x() || theLocalMouse.y() < 0.0f
1178 || theLocalMouse.y() >= viewportSize.y()))
1179 return std::nullopt;
1181 return m_layer->renderedCameras[0]->unproject(globalTransform, theLocalMouse, viewportRect);
1187 return QQuick3DSceneRenderer::PickResultList();
1189 return QSSGRendererPrivate::syncPick(*m_sgContext,
1197 return QQuick3DSceneRenderer::PickResultList();
1199 return QSSGRendererPrivate::syncPick(*m_sgContext,
1206 QVarLengthArray<QSSGRenderNode *> subset)
1209 return QQuick3DSceneRenderer::PickResultList();
1211 return QSSGRendererPrivate::syncPickSubset(*m_layer,
1212 *m_sgContext->bufferManager(),
1220 return QQuick3DSceneRenderer::PickResultList();
1222 return QSSGRendererPrivate::syncPickAll(*m_sgContext,
1229 QSSGRendererPrivate::setGlobalPickingEnabled(*m_sgContext->renderer(), isEnabled);
1234 return m_renderStats;
1237void QQuick3DRenderLayerHelpers::updateLayerNodeHelper(
const QQuick3DViewport &view3D,
1238 const std::shared_ptr<QSSGRenderContextInterface>& rci,
1239 QSSGRenderLayer &layerNode,
1241 bool &temporalIsDirty)
1243 QList<QSSGRenderGraphObject *> resourceLoaders;
1245 QQuick3DSceneRenderer dummyRenderer(rci);
1248 dummyRenderer.updateLayerNode(layerNode, view3D, resourceLoaders);
1250 aaIsDirty = dummyRenderer.m_aaIsDirty;
1251 temporalIsDirty = dummyRenderer.m_temporalIsDirty;
1255 const QQuick3DViewport &view3D,
1256 const QList<QSSGRenderGraphObject *> &resourceLoaders)
1258 QQuick3DSceneEnvironment *environment = view3D.environment();
1259 const auto &effects = environment->effectList();
1261 QSSGRenderLayer::AAMode aaMode = QSSGRenderLayer::AAMode(environment->antialiasingMode());
1262 if (aaMode != layerNode.antialiasingMode) {
1263 layerNode.antialiasingMode = aaMode;
1264 layerNode.progAAPassIndex = 0;
1267 QSSGRenderLayer::AAQuality aaQuality = QSSGRenderLayer::AAQuality(environment->antialiasingQuality());
1268 if (aaQuality != layerNode.antialiasingQuality) {
1269 layerNode.antialiasingQuality = aaQuality;
1270 layerNode.ssaaMultiplier = QSSGRenderLayer::ssaaMultiplierForQuality(aaQuality);
1275 const bool temporalAARequested = environment->temporalAAEnabled();
1276 const bool wasTaaEnabled = layerNode.isTemporalAAEnabled();
1277 layerNode.temporalAAMode = temporalAARequested ? QSSGRenderLayer::TAAMode::On
1278 : QSSGRenderLayer::TAAMode::Off;
1281 if (wasTaaEnabled != layerNode.isTemporalAAEnabled()) {
1282 layerNode.tempAAPassIndex = 0;
1284 m_temporalIsDirty =
true;
1287 layerNode.temporalAAStrength = environment->temporalAAStrength();
1289 layerNode.specularAAEnabled = environment->specularAAEnabled();
1291 layerNode.background = QSSGRenderLayer::Background(environment->backgroundMode());
1292 layerNode.clearColor = QVector3D(
float(environment->clearColor().redF()),
1293 float(environment->clearColor().greenF()),
1294 float(environment->clearColor().blueF()));
1296 layerNode.gridEnabled = environment->gridEnabled();
1297 layerNode.gridScale = environment->gridScale();
1298 layerNode.gridFlags = environment->gridFlags();
1300 layerNode.aoStrength = environment->aoStrength();
1301 layerNode.aoDistance = environment->aoDistance();
1302 layerNode.aoSoftness = environment->aoSoftness();
1303 layerNode.aoEnabled = environment->aoEnabled();
1304 layerNode.aoBias = environment->aoBias();
1305 layerNode.aoSamplerate = environment->aoSampleRate();
1306 layerNode.aoDither = environment->aoDither();
1309 if (environment->lightProbe())
1310 layerNode.lightProbe = environment->lightProbe()->getRenderImage();
1312 layerNode.lightProbe =
nullptr;
1313 if (view3D.environment()->skyBoxCubeMap())
1314 layerNode.skyBoxCubeMap = view3D.environment()->skyBoxCubeMap()->getRenderImage();
1316 layerNode.skyBoxCubeMap =
nullptr;
1318 layerNode.lightProbeSettings.probeExposure = environment->probeExposure();
1320 layerNode.lightProbeSettings.probeHorizon = qMin(environment->probeHorizon() - 1.0f, -0.001f);
1321 layerNode.setProbeOrientation(environment->probeOrientation());
1323 QQuick3DViewport::updateCameraForLayer(view3D, layerNode);
1325 layerNode.layerFlags.setFlag(QSSGRenderLayer::LayerFlag::EnableDepthTest, environment->depthTestEnabled());
1326 layerNode.layerFlags.setFlag(QSSGRenderLayer::LayerFlag::EnableDepthPrePass, environment->depthPrePassEnabled());
1328 layerNode.tonemapMode = QQuick3DSceneRenderer::getTonemapMode(*environment);
1329 layerNode.skyboxBlurAmount = environment->skyboxBlurAmount();
1330 if (
auto debugSettings = view3D.environment()->debugSettings()) {
1331 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode(debugSettings->materialOverride());
1332 layerNode.wireframeMode = debugSettings->wireframeEnabled();
1333 layerNode.drawDirectionalLightShadowBoxes = debugSettings->drawDirectionalLightShadowBoxes();
1334 layerNode.drawPointLightShadowBoxes = debugSettings->drawPointLightShadowBoxes();
1335 layerNode.drawShadowCastingBounds = debugSettings->drawShadowCastingBounds();
1336 layerNode.drawShadowReceivingBounds = debugSettings->drawShadowReceivingBounds();
1337 layerNode.drawCascades = debugSettings->drawCascades();
1338 layerNode.drawSceneCascadeIntersection = debugSettings->drawSceneCascadeIntersection();
1339 layerNode.disableShadowCameraUpdate = debugSettings->disableShadowCameraUpdate();
1340 layerNode.drawCulledObjects = debugSettings->drawCulledObjects();
1342 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode::None;
1343 layerNode.wireframeMode =
false;
1346 if (environment->fog() && environment->fog()->isEnabled()) {
1347 layerNode.fog.enabled =
true;
1348 const QQuick3DFog *fog = environment->fog();
1349 layerNode.fog.color = QSSGUtils::color::sRGBToLinear(fog->color()).toVector3D();
1350 layerNode.fog.density = fog->density();
1351 layerNode.fog.depthEnabled = fog->isDepthEnabled();
1352 layerNode.fog.depthBegin = fog->depthNear();
1353 layerNode.fog.depthEnd = fog->depthFar();
1354 layerNode.fog.depthCurve = fog->depthCurve();
1355 layerNode.fog.heightEnabled = fog->isHeightEnabled();
1356 layerNode.fog.heightMin = fog->leastIntenseY();
1357 layerNode.fog.heightMax = fog->mostIntenseY();
1358 layerNode.fog.heightCurve = fog->heightCurve();
1359 layerNode.fog.transmitEnabled = fog->isTransmitEnabled();
1360 layerNode.fog.transmitCurve = fog->transmitCurve();
1362 layerNode.fog.enabled =
false;
1364 const auto method =
static_cast<QSSGRenderLayer::OITMethod>(environment->oitMethod());
1365 layerNode.oitMethodDirty = method != layerNode.oitMethod;
1366 layerNode.oitMethod = method;
1371 layerNode.firstEffect =
nullptr;
1372 auto rit = effects.crbegin();
1373 const auto rend = effects.crend();
1374 for (; rit != rend; ++rit) {
1375 QQuick3DObjectPrivate *p = QQuick3DObjectPrivate::get(*rit);
1376 QSSGRenderEffect *effectNode =
static_cast<QSSGRenderEffect *>(p->spatialNode);
1378 if (layerNode.hasEffect(effectNode)) {
1379 qWarning() <<
"Duplicate effect found, skipping!";
1381 effectNode->className = (*rit)->metaObject()->className();
1382 layerNode.addEffect(*effectNode);
1387 const bool hasEffects = (layerNode.firstEffect !=
nullptr);
1389 const auto renderMode = view3D.renderMode();
1391 const bool progressiveAA = layerNode.isProgressiveAAEnabled();
1392 const bool temporalAA = layerNode.isTemporalAAEnabled();
1393 const bool superSamplingAA = layerNode.isSsaaEnabled();
1394 m_timeBasedAA = progressiveAA || temporalAA;
1395 m_postProcessingStack = hasEffects || m_timeBasedAA || superSamplingAA;
1396 m_useFBO = renderMode == QQuick3DViewport::RenderMode::Offscreen ||
1397 ((renderMode == QQuick3DViewport::RenderMode::Underlay || renderMode == QQuick3DViewport::RenderMode::Overlay)
1398 && m_postProcessingStack);
1407 if (m_useFBO && (layerNode.viewCount > 1) && !view3D.isXrViewInstance())
1408 layerNode.viewCount = 1;
1411 layerNode.resourceLoaders.clear();
1412 layerNode.resourceLoaders = resourceLoaders;
1420 m_layer->removeChild(*node);
1425 if (m_layer->renderData && m_layer->renderData->lightmapBaker)
1430 bool bakeRequested =
false;
1431 bool denoiseRequested =
false;
1432 bool fromCmd =
false;
1433 QQuick3DLightmapBaker *lightmapBaker = view3D->maybeLightmapBaker();
1434 if (lightmapBaker && (lightmapBaker->m_bakingRequested || lightmapBaker->m_denoisingRequested)) {
1435 bakeRequested = std::exchange(lightmapBaker->m_bakingRequested,
false);
1436 denoiseRequested = std::exchange(lightmapBaker->m_denoisingRequested,
false);
1438 bakeRequested = m_lightmapBakingFromCmdRequested;
1439 denoiseRequested = m_lightmapDenoisingFromCmdRequested;
1440 fromCmd = bakeRequested;
1444 if (bakeRequested || denoiseRequested) {
1445 QSSGLightmapBaker::Context ctx;
1446 ctx.settings.bakeRequested = bakeRequested;
1447 ctx.settings.denoiseRequested = denoiseRequested;
1448 ctx.settings.quitWhenFinished = fromCmd;
1451 if (lightmapBaker) {
1452 QQuick3DLightmapBaker::Callback qq3dCallback = lightmapBaker->m_callback;
1453 QQuick3DLightmapBaker::BakingControl *qq3dBakingControl = lightmapBaker->m_bakingControl;
1454 QSSGLightmapper::Callback callback =
1456 qq3dBakingControl](
const QVariantMap &payload,
1457 QSSGLightmapper::BakingControl *qssgBakingControl) {
1458 qq3dCallback(payload, qq3dBakingControl);
1460 if (qq3dBakingControl->isCancelled() && !qssgBakingControl->cancelled)
1461 qssgBakingControl->cancelled =
true;
1463 ctx.callbacks.lightmapBakingOutput = callback;
1467 ctx.callbacks.triggerNewFrame = [view3D](
bool releaseResources) {
1468 if (releaseResources) {
1469 QMetaObject::invokeMethod(view3D->window(),
1470 &QQuickWindow::releaseResources,
1471 Qt::QueuedConnection);
1473 QMetaObject::invokeMethod(view3D, &QQuick3DViewport::update, Qt::QueuedConnection);
1475 ctx.callbacks.setCurrentlyBaking = [
this](
bool value) {
1476 m_sgContext->bufferManager()->setCurrentlyLightmapBaking(value);
1479 ctx.env.rhiCtx = m_sgContext->rhiContext().get();
1480 ctx.env.renderer = m_sgContext->renderer().get();
1481 ctx.env.lmOptions = lmOptions;
1482 m_layer->renderData->initializeLightmapBaking(ctx);
1486 static bool flagsChecked =
false;
1489 flagsChecked =
true;
1491 auto isLightmapFlagSet = [](
const QString &flag,
const char *envVar) {
1492 return QCoreApplication::arguments().contains(flag)
1493 || qEnvironmentVariableIntValue(envVar);
1496 m_lightmapBakingFromCmdRequested = isLightmapFlagSet(QStringLiteral(
"--bake-lightmaps"),
"QT_QUICK3D_BAKE_LIGHTMAPS");
1497 m_lightmapDenoisingFromCmdRequested = isLightmapFlagSet(QStringLiteral(
"--denoise-lightmaps"),
"QT_QUICK3D_DENOISE_LIGHTMAPS");
1499 if (m_lightmapBakingFromCmdRequested || m_lightmapDenoisingFromCmdRequested) {
1501 QMetaObject::invokeMethod(view3D, &QQuick3DViewport::update, Qt::QueuedConnection);
1511 m_layer->addChild(*node);
1516 return BlendState | StencilState | DepthState | ScissorState | ColorState | CullState | ViewportState | RenderTargetState;
1520inline QRect convertQtRectToGLViewport(
const QRectF &rect,
const QSize surfaceSize)
1522 const int x =
int(rect.x());
1523 const int y = surfaceSize.height() - (
int(rect.y()) +
int(rect.height()));
1524 const int width =
int(rect.width());
1525 const int height =
int(rect.height());
1526 return QRect(x, y, width, height);
1529inline void queryMainRenderPassDescriptorAndCommandBuffer(QQuickWindow *window, QSSGRhiContext *rhiCtx)
1531 if (rhiCtx->isValid()) {
1532 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
1537 int sampleCount = 1;
1539 QRhiSwapChain *swapchain = window->swapChain();
1541 rhiCtxD->setMainRenderPassDescriptor(swapchain->renderPassDescriptor());
1542 rhiCtxD->setCommandBuffer(swapchain->currentFrameCommandBuffer());
1543 rhiCtxD->setRenderTarget(swapchain->currentFrameRenderTarget());
1544 sampleCount = swapchain->sampleCount();
1546 QSGRendererInterface *rif = window->rendererInterface();
1548 QRhiCommandBuffer *cb =
static_cast<QRhiCommandBuffer *>(
1549 rif->getResource(window, QSGRendererInterface::RhiRedirectCommandBuffer));
1550 QRhiTextureRenderTarget *rt =
static_cast<QRhiTextureRenderTarget *>(
1551 rif->getResource(window, QSGRendererInterface::RhiRedirectRenderTarget));
1553 rhiCtxD->setMainRenderPassDescriptor(rt->renderPassDescriptor());
1554 rhiCtxD->setCommandBuffer(cb);
1555 rhiCtxD->setRenderTarget(rt);
1556 const QRhiColorAttachment *color0 = rt->description().cbeginColorAttachments();
1557 if (color0 && color0->texture()) {
1558 sampleCount = color0->texture()->sampleCount();
1559 if (rt->resourceType() == QRhiResource::TextureRenderTarget) {
1560 const QRhiTextureRenderTargetDescription desc =
static_cast<QRhiTextureRenderTarget *>(rt)->description();
1561 for (
auto it = desc.cbeginColorAttachments(), end = desc.cendColorAttachments(); it != end; ++it) {
1562 if (it->multiViewCount() >= 2) {
1563 viewCount = it->multiViewCount();
1570 qWarning(
"Neither swapchain nor redirected command buffer and render target are available.");
1579 rhiCtxD->setMainPassSampleCount(sampleCount);
1587 rhiCtxD->setMainPassViewCount(viewCount);
1593inline void queryInlineRenderPassDescriptorAndCommandBuffer(QSGRenderNode *node, QSSGRhiContext *rhiCtx)
1595 QSGRenderNodePrivate *d = QSGRenderNodePrivate::get(node);
1596 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
1597 rhiCtxD->setMainRenderPassDescriptor(d->m_rt.rpDesc);
1598 rhiCtxD->setCommandBuffer(d->m_rt.cb);
1599 rhiCtxD->setRenderTarget(d->m_rt.rt);
1600 rhiCtxD->setMainPassSampleCount(d->m_rt.rt->sampleCount());
1601 rhiCtxD->setMainPassViewCount(1);
1615 if (!
renderer->m_sgContext->rhiContext()->isValid())
1617 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1619 queryInlineRenderPassDescriptorAndCommandBuffer(
this,
renderer->m_sgContext->rhiContext().get());
1621 qreal dpr = window->effectiveDevicePixelRatio();
1622 const QSizeF itemSize =
renderer->surfaceSize() / dpr;
1623 QRectF viewport = matrix()->mapRect(QRectF(QPoint(0, 0), itemSize));
1624 viewport = QRectF(viewport.topLeft() * dpr, viewport.size() * dpr);
1625 const QRect vp = convertQtRectToGLViewport(viewport, window->size() * dpr);
1627 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1631 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32, renderer->profilingId);
1634void QQuick3DSGRenderNode::
render(
const QSGRenderNode::RenderState *state)
1638 const auto &rhiContext =
renderer->m_sgContext->rhiContext();
1640 if (rhiContext->isValid()) {
1641 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1642 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1644 queryInlineRenderPassDescriptorAndCommandBuffer(
this,
renderer->m_sgContext->rhiContext().get());
1647 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1648 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiContext)), renderer->profilingId);
1660 return NoExternalRendering;
1664 : m_renderer(renderer)
1667 if (QSGRendererInterface::isApiRhiBased(window->rendererInterface()->graphicsApi())) {
1668 connect(window, &QQuickWindow::beforeRendering,
this, &QQuick3DSGDirectRenderer::prepare, Qt::DirectConnection);
1669 if (mode == Underlay)
1670 connect(window, &QQuickWindow::beforeRenderPassRecording,
this, &QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1672 connect(window, &QQuickWindow::afterRenderPassRecording,
this, &QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1683 m_viewport = viewport;
1688 if (m_isVisible == visible)
1690 m_isVisible = visible;
1696 renderPending =
true;
1697 requestFullUpdate(m_window);
1707 if (m_renderer->m_sgContext->rhiContext()->isValid())
1708 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1713 if (!m_isVisible || !m_renderer)
1716 if (m_renderer->m_sgContext->rhiContext()->isValid()) {
1718 if (m_renderer->m_postProcessingStack) {
1719 if (renderPending) {
1720 renderPending =
false;
1721 m_rhiTexture = m_renderer->renderToRhiTexture(m_window);
1724 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1725 const auto &quadRenderer = m_renderer->m_sgContext->renderer()->rhiQuadRenderer();
1726 quadRenderer->prepareQuad(m_renderer->m_sgContext->rhiContext().get(),
nullptr);
1727 if (m_renderer->m_requestedFramesCount > 0) {
1729 m_renderer->m_requestedFramesCount--;
1735 QQuick3DRenderStats *renderStats = m_renderer->renderStats();
1737 renderStats->startRender();
1738 renderStats->startRenderPrepare();
1741 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1742 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1743 const QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->effectiveDevicePixelRatio());
1745 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1747 m_renderer->rhiPrepare(vp, m_window->effectiveDevicePixelRatio());
1748 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32, m_renderer->profilingId);
1751 renderStats->endRenderPrepare();
1758 if (!m_isVisible || !m_renderer)
1761 const auto &rhiContext = m_renderer->m_sgContext->rhiContext();
1763 if (rhiContext->isValid()) {
1774 if (m_renderer->m_postProcessingStack) {
1776 queryMainRenderPassDescriptorAndCommandBuffer(m_window, rhiContext.get());
1777 auto rhiCtx = m_renderer->m_sgContext->rhiContext().get();
1778 const auto &renderer = m_renderer->m_sgContext->renderer();
1779 QRhiCommandBuffer *cb = rhiContext->commandBuffer();
1780 cb->debugMarkBegin(QByteArrayLiteral(
"Post-processing result to main rt"));
1787 QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->effectiveDevicePixelRatio());
1789 const auto &shaderCache = m_renderer->m_sgContext->shaderCache();
1790 const auto &shaderPipeline = shaderCache->getBuiltInRhiShaders().getRhiSimpleQuadShader(m_renderer->m_layer->viewCount);
1792 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
1793 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge });
1794 QSSGRhiShaderResourceBindingList bindings;
1795 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, m_rhiTexture, sampler);
1796 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiContext.get());
1797 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
1799 QSSGRhiGraphicsPipelineState ps;
1800 ps.viewport = QRhiViewport(
float(vp.x()),
float(vp.y()),
float(vp.width()),
float(vp.height()));
1801 ps.samples = rhiCtx->mainPassSampleCount();
1802 ps.viewCount = m_renderer->m_layer->viewCount;
1803 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
1804 renderer->rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, rhiCtx->mainRenderPassDescriptor(), QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::PremulBlend);
1810 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1811 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1813 queryMainRenderPassDescriptorAndCommandBuffer(m_window, rhiContext.get());
1817 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1818 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiContext)),
1819 m_renderer->profilingId);
1822 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()
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
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)