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);
1184std::optional<QSSGRenderPickResult>
QQuick3DSceneRenderer::syncPickClosestPoint(
const QVector3D ¢er,
float radiusSquared, QSSGRenderNode *node)
1187 return std::nullopt;
1189 return QSSGRendererPrivate::syncPickClosestPoint(*m_sgContext,
1191 center, radiusSquared,
1198 return QQuick3DSceneRenderer::PickResultList();
1200 return QSSGRendererPrivate::syncPick(*m_sgContext,
1208 return QQuick3DSceneRenderer::PickResultList();
1210 return QSSGRendererPrivate::syncPick(*m_sgContext,
1217 QVarLengthArray<QSSGRenderNode *> subset)
1220 return QQuick3DSceneRenderer::PickResultList();
1222 return QSSGRendererPrivate::syncPickSubset(*m_layer,
1223 *m_sgContext->bufferManager(),
1231 return QQuick3DSceneRenderer::PickResultList();
1233 return QSSGRendererPrivate::syncPickAll(*m_sgContext,
1240 QSSGRendererPrivate::setGlobalPickingEnabled(*m_sgContext->renderer(), isEnabled);
1245 return m_renderStats;
1248void QQuick3DRenderLayerHelpers::updateLayerNodeHelper(
const QQuick3DViewport &view3D,
1249 const std::shared_ptr<QSSGRenderContextInterface>& rci,
1250 QSSGRenderLayer &layerNode,
1252 bool &temporalIsDirty)
1254 QList<QSSGRenderGraphObject *> resourceLoaders;
1256 QQuick3DSceneRenderer dummyRenderer(rci);
1259 dummyRenderer.updateLayerNode(layerNode, view3D, resourceLoaders);
1261 aaIsDirty = dummyRenderer.m_aaIsDirty;
1262 temporalIsDirty = dummyRenderer.m_temporalIsDirty;
1266 const QQuick3DViewport &view3D,
1267 const QList<QSSGRenderGraphObject *> &resourceLoaders)
1269 QQuick3DSceneEnvironment *environment = view3D.environment();
1270 const auto &effects = environment->effectList();
1272 QSSGRenderLayer::AAMode aaMode = QSSGRenderLayer::AAMode(environment->antialiasingMode());
1273 if (aaMode != layerNode.antialiasingMode) {
1274 layerNode.antialiasingMode = aaMode;
1275 layerNode.progAAPassIndex = 0;
1278 QSSGRenderLayer::AAQuality aaQuality = QSSGRenderLayer::AAQuality(environment->antialiasingQuality());
1279 if (aaQuality != layerNode.antialiasingQuality) {
1280 layerNode.antialiasingQuality = aaQuality;
1281 layerNode.ssaaMultiplier = QSSGRenderLayer::ssaaMultiplierForQuality(aaQuality);
1286 const bool temporalAARequested = environment->temporalAAEnabled();
1287 const bool wasTaaEnabled = layerNode.isTemporalAAEnabled();
1288 layerNode.temporalAAMode = temporalAARequested ? QSSGRenderLayer::TAAMode::On
1289 : QSSGRenderLayer::TAAMode::Off;
1292 if (wasTaaEnabled != layerNode.isTemporalAAEnabled()) {
1293 layerNode.tempAAPassIndex = 0;
1295 m_temporalIsDirty =
true;
1298 layerNode.temporalAAStrength = environment->temporalAAStrength();
1300 layerNode.specularAAEnabled = environment->specularAAEnabled();
1302 layerNode.background = QSSGRenderLayer::Background(environment->backgroundMode());
1303 layerNode.clearColor = QVector3D(
float(environment->clearColor().redF()),
1304 float(environment->clearColor().greenF()),
1305 float(environment->clearColor().blueF()));
1307 layerNode.gridEnabled = environment->gridEnabled();
1308 layerNode.gridScale = environment->gridScale();
1309 layerNode.gridFlags = environment->gridFlags();
1311 layerNode.aoStrength = environment->aoStrength();
1312 layerNode.aoDistance = environment->aoDistance();
1313 layerNode.aoSoftness = environment->aoSoftness();
1314 layerNode.aoEnabled = environment->aoEnabled();
1315 layerNode.aoBias = environment->aoBias();
1316 layerNode.aoSamplerate = environment->aoSampleRate();
1317 layerNode.aoDither = environment->aoDither();
1320 if (environment->lightProbe())
1321 layerNode.lightProbe = environment->lightProbe()->getRenderImage();
1323 layerNode.lightProbe =
nullptr;
1324 if (view3D.environment()->skyBoxCubeMap())
1325 layerNode.skyBoxCubeMap = view3D.environment()->skyBoxCubeMap()->getRenderImage();
1327 layerNode.skyBoxCubeMap =
nullptr;
1329 layerNode.lightProbeSettings.probeExposure = environment->probeExposure();
1331 layerNode.lightProbeSettings.probeHorizon = qMin(environment->probeHorizon() - 1.0f, -0.001f);
1332 layerNode.setProbeOrientation(environment->probeOrientation());
1334 QQuick3DViewport::updateCameraForLayer(view3D, layerNode);
1336 layerNode.layerFlags.setFlag(QSSGRenderLayer::LayerFlag::EnableDepthTest, environment->depthTestEnabled());
1337 layerNode.layerFlags.setFlag(QSSGRenderLayer::LayerFlag::EnableDepthPrePass, environment->depthPrePassEnabled());
1339 layerNode.tonemapMode = QQuick3DSceneRenderer::getTonemapMode(*environment);
1340 layerNode.skyboxBlurAmount = environment->skyboxBlurAmount();
1341 if (
auto debugSettings = view3D.environment()->debugSettings()) {
1342 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode(debugSettings->materialOverride());
1343 layerNode.wireframeMode = debugSettings->wireframeEnabled();
1344 layerNode.drawDirectionalLightShadowBoxes = debugSettings->drawDirectionalLightShadowBoxes();
1345 layerNode.drawPointLightShadowBoxes = debugSettings->drawPointLightShadowBoxes();
1346 layerNode.drawShadowCastingBounds = debugSettings->drawShadowCastingBounds();
1347 layerNode.drawShadowReceivingBounds = debugSettings->drawShadowReceivingBounds();
1348 layerNode.drawCascades = debugSettings->drawCascades();
1349 layerNode.drawSceneCascadeIntersection = debugSettings->drawSceneCascadeIntersection();
1350 layerNode.disableShadowCameraUpdate = debugSettings->disableShadowCameraUpdate();
1351 layerNode.drawCulledObjects = debugSettings->drawCulledObjects();
1353 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode::None;
1354 layerNode.wireframeMode =
false;
1357 if (environment->fog() && environment->fog()->isEnabled()) {
1358 layerNode.fog.enabled =
true;
1359 const QQuick3DFog *fog = environment->fog();
1360 layerNode.fog.color = QSSGUtils::color::sRGBToLinear(fog->color()).toVector3D();
1361 layerNode.fog.density = fog->density();
1362 layerNode.fog.depthEnabled = fog->isDepthEnabled();
1363 layerNode.fog.depthBegin = fog->depthNear();
1364 layerNode.fog.depthEnd = fog->depthFar();
1365 layerNode.fog.depthCurve = fog->depthCurve();
1366 layerNode.fog.heightEnabled = fog->isHeightEnabled();
1367 layerNode.fog.heightMin = fog->leastIntenseY();
1368 layerNode.fog.heightMax = fog->mostIntenseY();
1369 layerNode.fog.heightCurve = fog->heightCurve();
1370 layerNode.fog.transmitEnabled = fog->isTransmitEnabled();
1371 layerNode.fog.transmitCurve = fog->transmitCurve();
1373 layerNode.fog.enabled =
false;
1375 const auto method =
static_cast<QSSGRenderLayer::OITMethod>(environment->oitMethod());
1376 layerNode.oitMethodDirty = method != layerNode.oitMethod;
1377 layerNode.oitMethod = method;
1382 layerNode.firstEffect =
nullptr;
1383 auto rit = effects.crbegin();
1384 const auto rend = effects.crend();
1385 for (; rit != rend; ++rit) {
1386 QQuick3DObjectPrivate *p = QQuick3DObjectPrivate::get(*rit);
1387 QSSGRenderEffect *effectNode =
static_cast<QSSGRenderEffect *>(p->spatialNode);
1389 if (layerNode.hasEffect(effectNode)) {
1390 qWarning() <<
"Duplicate effect found, skipping!";
1392 effectNode->className = (*rit)->metaObject()->className();
1393 layerNode.addEffect(*effectNode);
1398 const bool hasEffects = (layerNode.firstEffect !=
nullptr);
1400 const auto renderMode = view3D.renderMode();
1402 const bool progressiveAA = layerNode.isProgressiveAAEnabled();
1403 const bool temporalAA = layerNode.isTemporalAAEnabled();
1404 const bool superSamplingAA = layerNode.isSsaaEnabled();
1405 m_timeBasedAA = progressiveAA || temporalAA;
1406 m_postProcessingStack = hasEffects || m_timeBasedAA || superSamplingAA;
1407 m_useFBO = renderMode == QQuick3DViewport::RenderMode::Offscreen ||
1408 ((renderMode == QQuick3DViewport::RenderMode::Underlay || renderMode == QQuick3DViewport::RenderMode::Overlay)
1409 && m_postProcessingStack);
1418 if (m_useFBO && (layerNode.viewCount > 1) && !view3D.isXrViewInstance())
1419 layerNode.viewCount = 1;
1422 layerNode.resourceLoaders.clear();
1423 layerNode.resourceLoaders = resourceLoaders;
1431 m_layer->removeChild(*node);
1436 if (m_layer->renderData && m_layer->renderData->lightmapBaker)
1441 bool bakeRequested =
false;
1442 bool denoiseRequested =
false;
1443 bool fromCmd =
false;
1444 QQuick3DLightmapBaker *lightmapBaker = view3D->maybeLightmapBaker();
1445 if (lightmapBaker && (lightmapBaker->m_bakingRequested || lightmapBaker->m_denoisingRequested)) {
1446 bakeRequested = std::exchange(lightmapBaker->m_bakingRequested,
false);
1447 denoiseRequested = std::exchange(lightmapBaker->m_denoisingRequested,
false);
1449 bakeRequested = m_lightmapBakingFromCmdRequested;
1450 denoiseRequested = m_lightmapDenoisingFromCmdRequested;
1451 fromCmd = bakeRequested;
1455 if (bakeRequested || denoiseRequested) {
1456 QSSGLightmapBaker::Context ctx;
1457 ctx.settings.bakeRequested = bakeRequested;
1458 ctx.settings.denoiseRequested = denoiseRequested;
1459 ctx.settings.quitWhenFinished = fromCmd;
1462 if (lightmapBaker) {
1463 QQuick3DLightmapBaker::Callback qq3dCallback = lightmapBaker->m_callback;
1464 QQuick3DLightmapBaker::BakingControl *qq3dBakingControl = lightmapBaker->m_bakingControl;
1465 QSSGLightmapper::Callback callback =
1467 qq3dBakingControl](
const QVariantMap &payload,
1468 QSSGLightmapper::BakingControl *qssgBakingControl) {
1469 qq3dCallback(payload, qq3dBakingControl);
1471 if (qq3dBakingControl->isCancelled() && !qssgBakingControl->cancelled)
1472 qssgBakingControl->cancelled =
true;
1474 ctx.callbacks.lightmapBakingOutput = callback;
1478 ctx.callbacks.triggerNewFrame = [view3D](
bool releaseResources) {
1479 if (releaseResources) {
1480 QMetaObject::invokeMethod(view3D->window(),
1481 &QQuickWindow::releaseResources,
1482 Qt::QueuedConnection);
1484 QMetaObject::invokeMethod(view3D, &QQuick3DViewport::update, Qt::QueuedConnection);
1486 ctx.callbacks.setCurrentlyBaking = [
this](
bool value) {
1487 m_sgContext->bufferManager()->setCurrentlyLightmapBaking(value);
1490 ctx.env.rhiCtx = m_sgContext->rhiContext().get();
1491 ctx.env.renderer = m_sgContext->renderer().get();
1492 ctx.env.lmOptions = lmOptions;
1493 m_layer->renderData->initializeLightmapBaking(ctx);
1497 static bool flagsChecked =
false;
1500 flagsChecked =
true;
1502 auto isLightmapFlagSet = [](
const QString &flag,
const char *envVar) {
1503 return QCoreApplication::arguments().contains(flag)
1504 || qEnvironmentVariableIntValue(envVar);
1507 m_lightmapBakingFromCmdRequested = isLightmapFlagSet(QStringLiteral(
"--bake-lightmaps"),
"QT_QUICK3D_BAKE_LIGHTMAPS");
1508 m_lightmapDenoisingFromCmdRequested = isLightmapFlagSet(QStringLiteral(
"--denoise-lightmaps"),
"QT_QUICK3D_DENOISE_LIGHTMAPS");
1510 if (m_lightmapBakingFromCmdRequested || m_lightmapDenoisingFromCmdRequested) {
1512 QMetaObject::invokeMethod(view3D, &QQuick3DViewport::update, Qt::QueuedConnection);
1522 m_layer->addChild(*node);
1527 return BlendState | StencilState | DepthState | ScissorState | ColorState | CullState | ViewportState | RenderTargetState;
1531inline QRect convertQtRectToGLViewport(
const QRectF &rect,
const QSize surfaceSize)
1533 const int x =
int(rect.x());
1534 const int y = surfaceSize.height() - (
int(rect.y()) +
int(rect.height()));
1535 const int width =
int(rect.width());
1536 const int height =
int(rect.height());
1537 return QRect(x, y, width, height);
1540inline void queryMainRenderPassDescriptorAndCommandBuffer(QQuickWindow *window, QSSGRhiContext *rhiCtx)
1542 if (rhiCtx->isValid()) {
1543 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
1548 int sampleCount = 1;
1550 QRhiSwapChain *swapchain = window->swapChain();
1552 rhiCtxD->setMainRenderPassDescriptor(swapchain->renderPassDescriptor());
1553 rhiCtxD->setCommandBuffer(swapchain->currentFrameCommandBuffer());
1554 rhiCtxD->setRenderTarget(swapchain->currentFrameRenderTarget());
1555 sampleCount = swapchain->sampleCount();
1557 QSGRendererInterface *rif = window->rendererInterface();
1559 QRhiCommandBuffer *cb =
static_cast<QRhiCommandBuffer *>(
1560 rif->getResource(window, QSGRendererInterface::RhiRedirectCommandBuffer));
1561 QRhiTextureRenderTarget *rt =
static_cast<QRhiTextureRenderTarget *>(
1562 rif->getResource(window, QSGRendererInterface::RhiRedirectRenderTarget));
1564 rhiCtxD->setMainRenderPassDescriptor(rt->renderPassDescriptor());
1565 rhiCtxD->setCommandBuffer(cb);
1566 rhiCtxD->setRenderTarget(rt);
1567 const QRhiColorAttachment *color0 = rt->description().cbeginColorAttachments();
1568 if (color0 && color0->texture()) {
1569 sampleCount = color0->texture()->sampleCount();
1570 if (rt->resourceType() == QRhiResource::TextureRenderTarget) {
1571 const QRhiTextureRenderTargetDescription desc =
static_cast<QRhiTextureRenderTarget *>(rt)->description();
1572 for (
auto it = desc.cbeginColorAttachments(), end = desc.cendColorAttachments(); it != end; ++it) {
1573 if (it->multiViewCount() >= 2) {
1574 viewCount = it->multiViewCount();
1581 qWarning(
"Neither swapchain nor redirected command buffer and render target are available.");
1590 rhiCtxD->setMainPassSampleCount(sampleCount);
1598 rhiCtxD->setMainPassViewCount(viewCount);
1604inline void queryInlineRenderPassDescriptorAndCommandBuffer(QSGRenderNode *node, QSSGRhiContext *rhiCtx)
1606 QSGRenderNodePrivate *d = QSGRenderNodePrivate::get(node);
1607 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
1608 rhiCtxD->setMainRenderPassDescriptor(d->m_rt.rpDesc);
1609 rhiCtxD->setCommandBuffer(d->m_rt.cb);
1610 rhiCtxD->setRenderTarget(d->m_rt.rt);
1611 rhiCtxD->setMainPassSampleCount(d->m_rt.rt->sampleCount());
1612 rhiCtxD->setMainPassViewCount(1);
1626 if (!
renderer->m_sgContext->rhiContext()->isValid())
1628 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1630 queryInlineRenderPassDescriptorAndCommandBuffer(
this,
renderer->m_sgContext->rhiContext().get());
1632 qreal dpr = window->effectiveDevicePixelRatio();
1633 const QSizeF itemSize =
renderer->surfaceSize() / dpr;
1634 QRectF viewport = matrix()->mapRect(QRectF(QPoint(0, 0), itemSize));
1635 viewport = QRectF(viewport.topLeft() * dpr, viewport.size() * dpr);
1636 const QRect vp = convertQtRectToGLViewport(viewport, window->size() * dpr);
1638 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1642 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32, renderer->profilingId);
1645void QQuick3DSGRenderNode::
render(
const QSGRenderNode::RenderState *state)
1649 const auto &rhiContext =
renderer->m_sgContext->rhiContext();
1651 if (rhiContext->isValid()) {
1652 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1653 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1655 queryInlineRenderPassDescriptorAndCommandBuffer(
this,
renderer->m_sgContext->rhiContext().get());
1658 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1659 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiContext)), renderer->profilingId);
1671 return NoExternalRendering;
1675 : m_renderer(renderer)
1678 if (QSGRendererInterface::isApiRhiBased(window->rendererInterface()->graphicsApi())) {
1679 connect(window, &QQuickWindow::beforeRendering,
this, &QQuick3DSGDirectRenderer::prepare, Qt::DirectConnection);
1680 if (mode == Underlay)
1681 connect(window, &QQuickWindow::beforeRenderPassRecording,
this, &QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1683 connect(window, &QQuickWindow::afterRenderPassRecording,
this, &QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1694 m_viewport = viewport;
1699 if (m_isVisible == visible)
1701 m_isVisible = visible;
1707 renderPending =
true;
1708 requestFullUpdate(m_window);
1718 if (m_renderer->m_sgContext->rhiContext()->isValid())
1719 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1724 if (!m_isVisible || !m_renderer)
1727 if (m_renderer->m_sgContext->rhiContext()->isValid()) {
1729 if (m_renderer->m_postProcessingStack) {
1730 if (renderPending) {
1731 renderPending =
false;
1732 m_rhiTexture = m_renderer->renderToRhiTexture(m_window);
1735 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1736 const auto &quadRenderer = m_renderer->m_sgContext->renderer()->rhiQuadRenderer();
1737 quadRenderer->prepareQuad(m_renderer->m_sgContext->rhiContext().get(),
nullptr);
1738 if (m_renderer->m_requestedFramesCount > 0) {
1740 m_renderer->m_requestedFramesCount--;
1746 QQuick3DRenderStats *renderStats = m_renderer->renderStats();
1748 renderStats->startRender();
1749 renderStats->startRenderPrepare();
1752 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1753 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1754 const QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->effectiveDevicePixelRatio());
1756 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1758 m_renderer->rhiPrepare(vp, m_window->effectiveDevicePixelRatio());
1759 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32, m_renderer->profilingId);
1762 renderStats->endRenderPrepare();
1769 if (!m_isVisible || !m_renderer)
1772 const auto &rhiContext = m_renderer->m_sgContext->rhiContext();
1774 if (rhiContext->isValid()) {
1785 if (m_renderer->m_postProcessingStack) {
1787 queryMainRenderPassDescriptorAndCommandBuffer(m_window, rhiContext.get());
1788 auto rhiCtx = m_renderer->m_sgContext->rhiContext().get();
1789 const auto &renderer = m_renderer->m_sgContext->renderer();
1790 QRhiCommandBuffer *cb = rhiContext->commandBuffer();
1791 cb->debugMarkBegin(QByteArrayLiteral(
"Post-processing result to main rt"));
1798 QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->effectiveDevicePixelRatio());
1800 const auto &shaderCache = m_renderer->m_sgContext->shaderCache();
1801 const auto &shaderPipeline = shaderCache->getBuiltInRhiShaders().getRhiSimpleQuadShader(m_renderer->m_layer->viewCount);
1803 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
1804 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge });
1805 QSSGRhiShaderResourceBindingList bindings;
1806 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, m_rhiTexture, sampler);
1807 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiContext.get());
1808 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
1810 QSSGRhiGraphicsPipelineState ps;
1811 ps.viewport = QRhiViewport(
float(vp.x()),
float(vp.y()),
float(vp.width()),
float(vp.height()));
1812 ps.samples = rhiCtx->mainPassSampleCount();
1813 ps.viewCount = m_renderer->m_layer->viewCount;
1814 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
1815 renderer->rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, rhiCtx->mainRenderPassDescriptor(), QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::PremulBlend);
1821 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1822 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1824 queryMainRenderPassDescriptorAndCommandBuffer(m_window, rhiContext.get());
1828 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1829 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiContext)),
1830 m_renderer->profilingId);
1833 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
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)