18#include "extensions/qquick3drenderextensions.h"
19#include <QtQuick3DUtils/private/qquick3dprofiler_p.h>
21#include <QtQuick3DRuntimeRender/private/qssgrendererutil_p.h>
22#include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
24#include <QtQuick/private/qquickwindow_p.h>
25#include <QtQuick/private/qsgdefaultrendercontext_p.h>
26#include <QtQuick/private/qsgtexture_p.h>
27#include <QtQuick/private/qsgplaintexture_p.h>
28#include <QtQuick/private/qsgrendernode_p.h>
30#include <QtQuick3DRuntimeRender/private/qssgrendereffect_p.h>
31#include <QtQuick3DRuntimeRender/private/qssgrhieffectsystem_p.h>
32#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
33#include <QtQuick3DRuntimeRender/private/qssgrhiquadrenderer_p.h>
34#include <QtQuick3DRuntimeRender/private/qssgrhicontext_p.h>
35#include <QtQuick3DRuntimeRender/private/qssgcputonemapper_p.h>
36#include <QtQuick3DRuntimeRender/private/qssgrenderroot_p.h>
37#include <QtQuick3DRuntimeRender/private/qssgrenderuserpass_p.h>
39#include <QtQuick3DUtils/private/qssgutils_p.h>
40#include <QtQuick3DUtils/private/qssgassert_p.h>
43#include <qtquick3d_tracepoints_p.h>
45#include <QtCore/QObject>
46#include <QtCore/qqueue.h>
50Q_TRACE_PREFIX(qtquick3d,
52 "class QQuick3DViewport;"
56Q_TRACE_POINT(qtquick3d, QSSG_prepareFrame_entry,
int width,
int height);
67 static bool val = (qEnvironmentVariableIntValue(
"QT_QUICK3D_DUMP_RENDERTIMES") > 0);
71#if QT_CONFIG(qml_debug)
73static inline quint64 statDrawCallCount(
const QSSGRhiContextStats &stats)
76 const QSSGRhiContextStats::PerLayerInfo &info(stats.perLayerInfo[stats.layerKey]);
77 for (
const auto &pass : info.renderPasses)
78 count += QSSGRhiContextStats::totalDrawCallCountForPass(pass);
79 count += QSSGRhiContextStats::totalDrawCallCountForPass(info.externalRenderPass);
83#define STAT_PAYLOAD(stats)
84 (statDrawCallCount(stats) | (quint64(stats.perLayerInfo[stats.layerKey].renderPasses.size()) << 32
))
88template <
typename In,
typename Out>
89static void bfs(In *inExtension, QList<Out *> &outList)
91 QSSG_ASSERT(inExtension,
return);
93 QQueue<In *> queue { { inExtension } };
94 while (queue.size() > 0) {
95 if (
auto cur = queue.dequeue()) {
96 if (
auto *ext =
static_cast<Out *>(QQuick3DObjectPrivate::get(cur)->spatialNode))
97 outList.push_back(ext);
98 for (
auto &chld : cur->childItems())
99 queue.enqueue(qobject_cast<In *>(chld));
109 , devicePixelRatio(1)
111 qsgnode_set_description(
this, QStringLiteral(
"fbonode"));
112 setFlag(QSGNode::UsePreprocess,
true);
124 markDirty(DirtyMaterial);
129 return QSGSimpleTextureNode::texture();
142 if (QThread::currentThread() == QCoreApplication::instance()->thread())
145 QCoreApplication::postEvent(window,
new QEvent(QEvent::Type(QQuickWindowPrivate::FullUpdateRequest)));
152 renderer->renderStats()->startRender();
156 if (
renderer->m_sgContext->rhiContext()->isValid()) {
157 QRhiTexture *rhiTexture =
renderer->renderToRhiTexture(window);
158 bool needsNewWrapper =
false;
159 if (!texture() || (texture()->textureSize() != renderer->surfaceSize()
160 || texture()->rhiTexture() != rhiTexture))
162 needsNewWrapper =
true;
164 if (needsNewWrapper) {
166 QSGPlainTexture *t =
new QSGPlainTexture;
167 t->setOwnsTexture(
false);
168 t->setHasAlphaChannel(
true);
169 t->setTexture(rhiTexture);
170 t->setTextureSize(
renderer->surfaceSize());
175 markDirty(QSGNode::DirtyMaterial);
176 emit textureChanged();
181 if (
renderer->m_requestedFramesCount > 0) {
183 requestFullUpdate(window);
191 if (!qFuzzyCompare(window->effectiveDevicePixelRatio(), devicePixelRatio)) {
205 const auto &rhiCtx = m_sgContext->rhiContext();
206 auto *rhi = rhiCtx->rhi();
208 QSSGRhiContextStats::get(*rhiCtx).cleanupLayerInfo(m_layer);
209 m_sgContext->bufferManager()->releaseResourcesForLayer(m_layer);
216 removeNodeFromLayer(m_sceneRootNode);
222 winAttacment->queueForCleanup(m_layer);
230 releaseAaDependentRhiResources();
231 delete m_effectSystem;
236 const auto &rhiCtx = m_sgContext->rhiContext();
237 if (!rhiCtx->isValid())
240 delete m_textureRenderTarget;
241 m_textureRenderTarget =
nullptr;
243 delete m_textureRenderPassDescriptor;
244 m_textureRenderPassDescriptor =
nullptr;
246 delete m_depthStencilBuffer;
247 m_depthStencilBuffer =
nullptr;
249 delete m_multiViewDepthStencilBuffer;
250 m_multiViewDepthStencilBuffer =
nullptr;
252 delete m_msaaRenderBufferLegacy;
253 m_msaaRenderBufferLegacy =
nullptr;
255 delete m_msaaRenderTexture;
256 m_msaaRenderTexture =
nullptr;
258 delete m_msaaMultiViewRenderBuffer;
259 m_msaaMultiViewRenderBuffer =
nullptr;
261 delete m_ssaaTexture;
262 m_ssaaTexture =
nullptr;
264 delete m_ssaaTextureToTextureRenderTarget;
265 m_ssaaTextureToTextureRenderTarget =
nullptr;
267 delete m_ssaaTextureToTextureRenderPassDescriptor;
268 m_ssaaTextureToTextureRenderPassDescriptor =
nullptr;
270 delete m_temporalAATexture;
271 m_temporalAATexture =
nullptr;
272 delete m_temporalAARenderTarget;
273 m_temporalAARenderTarget =
nullptr;
274 delete m_temporalAARenderPassDescriptor;
275 m_temporalAARenderPassDescriptor =
nullptr;
277 delete m_prevTempAATexture;
278 m_prevTempAATexture =
nullptr;
283 QVector2D(0.500000f, 0.500000f),
284 QVector2D(0.333333f, 0.666667f),
285 QVector2D(0.250000f, 0.750000f),
286 QVector2D(0.200000f, 0.800000f),
287 QVector2D(0.166667f, 0.833333f),
288 QVector2D(0.142857f, 0.857143f),
289 QVector2D(0.125000f, 0.875000f),
290 QVector2D(0.111111f, 0.888889f),
300 QRhiTexture *currentTexture = m_texture;
304 m_renderStats->startRenderPrepare();
306 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
308 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
309 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
311 rhiCtxD->setMainRenderPassDescriptor(m_textureRenderPassDescriptor);
312 rhiCtxD->setRenderTarget(m_textureRenderTarget);
314 QRhiCommandBuffer *cb =
nullptr;
315 QRhiSwapChain *swapchain = qw->swapChain();
317 cb = swapchain->currentFrameCommandBuffer();
318 rhiCtxD->setCommandBuffer(cb);
320 QSGRendererInterface *rif = qw->rendererInterface();
321 cb =
static_cast<QRhiCommandBuffer *>(
322 rif->getResource(qw, QSGRendererInterface::RhiRedirectCommandBuffer));
324 rhiCtxD->setCommandBuffer(cb);
326 qWarning(
"Neither swapchain nor redirected command buffer are available.");
327 return currentTexture;
333 rhiCtxD->setMainPassSampleCount(m_msaaRenderBufferLegacy ? m_msaaRenderBufferLegacy->sampleCount() :
334 (m_msaaRenderTexture ? m_msaaRenderTexture->sampleCount() :
335 (m_msaaMultiViewRenderBuffer ? m_msaaMultiViewRenderBuffer->sampleCount() : 1)));
339 int ssaaAdjustedWidth = m_surfaceSize.width();
340 int ssaaAdjustedHeight = m_surfaceSize.height();
341 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
342 ssaaAdjustedWidth *= m_layer->ssaaMultiplier;
343 ssaaAdjustedHeight *= m_layer->ssaaMultiplier;
346 Q_TRACE(QSSG_prepareFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
348 float dpr = m_sgContext->renderer()->dpr();
349 const QRect vp = QRect(0, 0, ssaaAdjustedWidth, ssaaAdjustedHeight);
354 m_renderStats->endRenderPrepare();
356 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, profilingId);
358 Q_TRACE(QSSG_prepareFrame_exit);
360 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
361 Q_TRACE(QSSG_renderFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
363 QColor clearColor = Qt::transparent;
364 if (m_backgroundMode == QSSGRenderLayer::Background::Color
365 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBoxCubeMap && !m_layer->skyBoxCubeMap)
366 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBox && !m_layer->lightProbe))
370 clearColor = m_layer->firstEffect ? m_linearBackgroundColor : m_tonemappedBackgroundColor;
375 cb->beginPass(m_textureRenderTarget, clearColor, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
376 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
377 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(m_textureRenderTarget));
380 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
381 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, QByteArrayLiteral(
"main"));
383 const bool temporalAA = m_layer->temporalAAIsActive;
384 const bool progressiveAA = m_layer->progressiveAAIsActive;
385 const bool superSamplingAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA;
386 QRhi *rhi = rhiCtx->rhi();
388 currentTexture = superSamplingAA ? m_ssaaTexture : m_texture;
391 if (m_effectSystem && m_layer->firstEffect && !m_layer->renderedCameras.isEmpty()) {
392 const auto &renderer = m_sgContext->renderer();
394 Q_ASSERT(theRenderData);
395 QRhiTexture *theDepthTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::DepthTexture)->texture;
396 QRhiTexture *theNormalTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::NormalTexture)->texture;
397 QRhiTexture *theMotionVectorTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::MotionVectorTexture)->texture;
399 currentTexture = m_effectSystem->process(*m_layer,
403 theMotionVectorTexture);
406 if ((progressiveAA || temporalAA) && m_prevTempAATexture) {
407 cb->debugMarkBegin(QByteArrayLiteral(
"Temporal AA"));
408 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
409 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"Temporal AA"));
410 QRhiTexture *blendResult;
411 uint *aaIndex = progressiveAA ? &m_layer->progAAPassIndex : &m_layer->tempAAPassIndex;
414 if ((temporalAA && m_layer->temporalAAMode != QSSGRenderLayer::TAAMode::MotionVector) ||
416 (temporalAA && m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector ?
417 quint32(QSSGLayerRenderData::MAX_AA_LEVELS) :
418 quint32(m_layer->antialiasingQuality))) {
419 const auto &renderer = m_sgContext->renderer();
421 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
422 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ m_layer,
nullptr,
nullptr, 0 }));
423 QRhiBuffer *&ubuf = dcd.ubuf;
424 const int ubufSize = 2 *
sizeof(
float);
426 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
429 int idx = *aaIndex - 1;
431 const QSize textureSize = currentTexture->pixelSize();
432 QVector2D bufferData;
434 bufferData = s_ProgressiveAABlendFactors[idx];
435 else if (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::Default)
436 bufferData = s_TemporalAABlendFactors;
438 bufferData = QVector2D(1.0f / qMax(textureSize.width(), 1), 1.0f / qMax(textureSize.height(), 1));
440 rub->updateDynamicBuffer(ubuf, 0, 2 *
sizeof(
float), &bufferData);
441 QSSGRhiGraphicsPipelineState ps;
442 ps.viewport = QRhiViewport(0, 0,
float(textureSize.width()),
float(textureSize.height()));
444 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
445 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
446 QSSGRhiShaderResourceBindingList bindings;
447 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
448 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
449 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, m_prevTempAATexture, sampler);
450 if (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector) {
452 Q_ASSERT(theRenderData);
453 QRhiTexture *theDepthTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::DepthTexture)->texture;
454 QRhiTexture *theMotionVectorTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::MotionVectorTexture)->texture;
455 bindings.addTexture(3, QRhiShaderResourceBinding::FragmentStage, theDepthTexture, sampler);
456 bindings.addTexture(4, QRhiShaderResourceBinding::FragmentStage, theMotionVectorTexture, sampler);
457 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiTemporalAAShader().get());
462 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiProgressiveAAShader().get());
465 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
466 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx, rub);
467 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_temporalAARenderTarget, QSSGRhiQuadRenderer::UvCoords);
468 blendResult = m_temporalAATexture;
470 blendResult = m_prevTempAATexture;
474 blendResult = currentTexture;
477 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
479 if ((temporalAA && m_layer->temporalAAMode != QSSGRenderLayer::TAAMode::MotionVector) ||
481 (temporalAA && m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector ?
482 quint32(QSSGLayerRenderData::MAX_AA_LEVELS) :
483 quint32(m_layer->antialiasingQuality))) {
484 auto *rub = rhi->nextResourceUpdateBatch();
485 if (progressiveAA || m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector)
486 rub->copyTexture(m_prevTempAATexture, blendResult);
488 rub->copyTexture(m_prevTempAATexture, currentTexture);
489 cb->resourceUpdate(rub);
494 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"temporal_aa"));
496 currentTexture = blendResult;
499 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
509 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
510 const auto &renderer = m_sgContext->renderer();
512 cb->debugMarkBegin(QByteArrayLiteral(
"SSAA downsample"));
513 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
515 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"SSAA downsample"));
517 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
524 const auto &shaderPipeline = m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiSupersampleResolveShader(m_layer->viewCount);
526 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
527 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
528 QSSGRhiShaderResourceBindingList bindings;
529 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
530 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
532 QSSGRhiGraphicsPipelineState ps;
533 ps.viewport = QRhiViewport(0, 0,
float(m_surfaceSize.width()),
float(m_surfaceSize.height()));
534 ps.viewCount = m_layer->viewCount;
535 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
537 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_ssaaTextureToTextureRenderTarget, QSSGRhiQuadRenderer::UvCoords);
539 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"ssaa_downsample"));
541 currentTexture = m_texture;
544 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
545 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiCtx)),
549 Q_TRACE(QSSG_renderFrame_exit);
553 return currentTexture;
558 m_sgContext->renderer()->beginFrame(*m_layer);
563 m_sgContext->renderer()->endFrame(*m_layer);
571 const auto &renderer = m_sgContext->renderer();
573 renderer->setDpr(displayPixelRatio);
575 renderer->setViewport(viewport);
577 renderer->prepareLayerForRender(*m_layer);
581 const bool renderReady = !m_layer->renderData->renderedCameras.isEmpty();
583 renderer->rhiPrepare(*m_layer);
594 m_sgContext->renderer()->rhiRender(*m_layer);
600#if QT_CONFIG(quick_shadereffect)
601static QRhiTexture::Format toRhiTextureFormat(QQuickShaderEffectSource::Format format)
604 case QQuickShaderEffectSource::RGBA8:
605 return QRhiTexture::RGBA8;
606 case QQuickShaderEffectSource::RGBA16F:
607 return QRhiTexture::RGBA16F;
608 case QQuickShaderEffectSource::RGBA32F:
609 return QRhiTexture::RGBA32F;
611 return QRhiTexture::RGBA8;
616static QVector3D tonemapRgb(
const QVector3D &c, QQuick3DSceneEnvironment::QQuick3DEnvironmentTonemapModes tonemapMode)
618 switch (tonemapMode) {
619 case QQuick3DSceneEnvironment::TonemapModeLinear:
620 return QSSGTonemapper::tonemapLinearToSrgb(c);
621 case QQuick3DSceneEnvironment::TonemapModeHejlDawson:
622 return QSSGTonemapper::tonemapHejlDawson(c);
623 case QQuick3DSceneEnvironment::TonemapModeAces:
624 return QSSGTonemapper::tonemapAces(c);
625 case QQuick3DSceneEnvironment::TonemapModeFilmic:
626 return QSSGTonemapper::tonemapFilmic(c);
635 Q_TRACE_SCOPE(QSSG_synchronize, view3D, size, dpr);
637 Q_ASSERT(view3D !=
nullptr);
638 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
639 Q_ASSERT(rhiCtx !=
nullptr);
643 m_layer =
new QSSGRenderLayer();
645 bool newRenderStats =
false;
646 if (!m_renderStats) {
647 m_renderStats = view3D->renderStats();
648 newRenderStats =
true;
652 m_renderStats->startSync();
654 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DSynchronizeFrame);
656 m_sgContext->renderer()->setDpr(dpr);
657 bool layerSizeIsDirty = m_surfaceSize != size;
658 m_surfaceSize = size;
660 QQuick3DSceneEnvironment *environment = view3D->environment();
661 if (environment->lightmapper()) {
662 QQuick3DLightmapper *lightmapper = environment->lightmapper();
663 lmOptions.opacityThreshold = lightmapper->opacityThreshold();
664 lmOptions.bias = lightmapper->bias();
665 lmOptions.useAdaptiveBias = lightmapper->isAdaptiveBiasEnabled();
666 lmOptions.indirectLightEnabled = lightmapper->isIndirectLightEnabled();
667 lmOptions.indirectLightSamples = lightmapper->samples();
668 lmOptions.indirectLightWorkgroupSize = lightmapper->indirectLightWorkgroupSize();
669 lmOptions.indirectLightBounces = lightmapper->bounces();
670 lmOptions.indirectLightFactor = lightmapper->indirectLightFactor();
671 lmOptions.sigma = lightmapper->denoiseSigma();
672 lmOptions.texelsPerUnit = lightmapper->texelsPerUnit();
678 const QQmlContext *context = qmlContext(view3D);
679 const QUrl originalSource = environment->lightmapper() ? environment->lightmapper()->source()
680 : QUrl::fromLocalFile(QStringLiteral(
"lightmaps.bin"));
681 const auto resolvedUrl = context ? context->resolvedUrl(originalSource) : originalSource;
682 const auto qmlSource = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
683 const QString lightmapSource = qmlSource.isEmpty() ? originalSource.path() : qmlSource;
684 lmOptions.source = lightmapSource;
685 m_layer->lightmapSource = lightmapSource;
688 m_sgContext->bufferManager()->setLightmapSource(lightmapSource);
692 QSet<QSSGRenderGraphObject *> resourceLoaders;
693 QQuick3DWindowAttachment::SyncResult requestSharedUpdate = QQuick3DWindowAttachment::SyncResultFlag::None;
694 if (
auto window = view3D->window()) {
695 if (!winAttacment || winAttacment->window() != window)
696 winAttacment = QQuick3DSceneManager::getOrSetWindowAttachment(*window);
698 if (winAttacment && winAttacment->rci() != m_sgContext)
699 winAttacment->setRci(m_sgContext);
701 QSSGRenderRoot *rootNode = winAttacment->rootNode();
702 if (m_layer->rootNode != rootNode) {
703 Q_ASSERT(m_layer->rootNode ==
nullptr);
704 rootNode->addChild(*m_layer);
705 rootNode->setStartVersion(m_layer->h.version());
706 m_layer->ref(rootNode);
710 requestSharedUpdate |= winAttacment->synchronize(resourceLoaders);
714 QQuick3DNode *importScene = view3D->importScene();
716 QQuick3DSceneManager *importSceneManager = QQuick3DObjectPrivate::get(importScene)->sceneManager;
719 if (
auto window = importSceneManager->window(); window && window != view3D->window()) {
720 if (
auto winAttacment = importSceneManager->wattached) {
722 auto rci = winAttacment->rci();
723 const bool inlineSync = (rci && rci->rhi() && (rci->rhi()->thread() == m_sgContext->rhi()->thread()));
727 winAttacment->synchronize(resourceLoaders);
728 }
else if (rci && !window->isExposed()) {
730 winAttacment->synchronize(resourceLoaders);
731 }
else if (!rci || (requestSharedUpdate & QQuick3DWindowAttachment::SyncResultFlag::SharedResourcesDirty)) {
736 winAttacment->requestUpdate();
749 m_layer->viewCount = rhiCtx->mainPassViewCount();
750 updateLayerNode(*m_layer, *view3D, resourceLoaders.values());
754 m_requestedFramesCount = 0;
755 if (m_layer->isProgressiveAAEnabled() || m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector) {
762 m_requestedFramesCount = (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector ? 45 :
763 int(m_layer->antialiasingQuality) + 1);
764 }
else if (m_layer->isTemporalAAEnabled()) {
769 m_requestedFramesCount = (m_aaIsDirty || m_temporalIsDirty) ? QSSGLayerRenderData::MAX_TEMPORAL_AA_LEVELS : 1;
774 for (QSSGRenderEffect *effectNode = m_layer->firstEffect; effectNode; effectNode = effectNode->m_nextEffect)
775 effectNode->finalizeShaders(*m_layer, m_sgContext.get());
778 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
779 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses))
780 userPass->finalizeShaders(*m_sgContext);
784 m_renderStats->setRhiContext(rhiCtx, m_layer);
786 static const auto getStageIndex = [](
const QSSGRenderExtension &ext) -> size_t {
787 const QSSGRenderExtension::RenderMode mode = ext.mode();
788 const QSSGRenderExtension::RenderStage stage = ext.stage();
791 if (mode == QSSGRenderExtension::RenderMode::Standalone)
792 return size_t(QSSGRenderLayer::RenderExtensionStage::TextureProviders);
795 case QSSGRenderExtension::RenderStage::PreColor:
796 return size_t(QSSGRenderLayer::RenderExtensionStage::Overlay);
797 case QSSGRenderExtension::RenderStage::PostColor:
798 return size_t(QSSGRenderLayer::RenderExtensionStage::Underlay);
801 Q_UNREACHABLE_RETURN(size_t(QSSGRenderLayer::RenderExtensionStage::Underlay));
807 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
808 const bool rebuildExtensionLists = (requestSharedUpdate & QQuick3DWindowAttachment::SyncResultFlag::ExtensionsDiry)
809 || view3D->extensionListDirty()
810 || sm->autoRegisteredExtensionsDirty;
815 if (rebuildExtensionLists) {
817 for (size_t i = 0; i != size_t(QSSGRenderLayer::RenderExtensionStage::Count); ++i)
818 m_layer->renderExtensions[i].clear();
821 const auto &extensions = view3D->extensionList();
822 for (
const auto &ext : extensions) {
823 const auto type = QQuick3DObjectPrivate::get(ext)->type;
824 if (QSSGRenderGraphObject::isExtension(type)) {
825 if (type == QSSGRenderGraphObject::Type::RenderExtension) {
826 if (
auto *renderExt = qobject_cast<QQuick3DRenderExtension *>(ext)) {
827 if (QSSGRenderExtension *ssgExt =
static_cast<QSSGRenderExtension *>(QQuick3DObjectPrivate::get(renderExt)->spatialNode)) {
828 const auto stage = getStageIndex(*ssgExt);
829 auto &list = m_layer->renderExtensions[size_t(stage)];
830 bfs(qobject_cast<QQuick3DRenderExtension *>(ext), list);
837 view3D->clearExtensionListDirty();
841 if (sm->autoRegisteredExtensionsDirty) {
842 for (QSSGRenderExtension *ae : std::as_const(sm->autoRegisteredExtensions))
843 m_layer->renderExtensions[getStageIndex(*ae)].push_back(ae);
844 sm->autoRegisteredExtensionsDirty =
false;
848 bool postProcessingNeeded = m_layer->firstEffect;
849 bool postProcessingWasActive = m_effectSystem;
850 QSSGRenderTextureFormat::Format effectOutputFormatOverride = QSSGRenderTextureFormat::Unknown;
851 if (postProcessingNeeded) {
852 QSSGRenderEffect *lastEffect = m_layer->firstEffect;
853 while (lastEffect->m_nextEffect)
854 lastEffect = lastEffect->m_nextEffect;
855 effectOutputFormatOverride = QSSGRhiEffectSystem::overriddenOutputFormat(lastEffect);
857 const auto layerTextureFormat = [effectOutputFormatOverride, view3D](QRhi *rhi,
bool postProc) {
858 if (effectOutputFormatOverride != QSSGRenderTextureFormat::Unknown)
859 return QSSGBufferManager::toRhiFormat(effectOutputFormatOverride);
874 const QRhiTexture::Format preferredPostProcFormat = QRhiTexture::RGBA16F;
875 if (postProc && rhi->isTextureFormatSupported(preferredPostProcFormat))
876 return preferredPostProcFormat;
878#if QT_CONFIG(quick_shadereffect)
879 const QRhiTexture::Format preferredView3DFormat = toRhiTextureFormat(view3D->renderFormat());
880 if (rhi->isTextureFormatSupported(preferredView3DFormat))
881 return preferredView3DFormat;
884 return QRhiTexture::RGBA8;
886 bool postProcessingStateDirty = postProcessingNeeded != postProcessingWasActive;
889 m_backgroundMode = QSSGRenderLayer::Background(view3D->environment()->backgroundMode());
893 QColor currentUserBackgroundColor = view3D->environment()->clearColor();
894 if (m_userBackgroundColor != currentUserBackgroundColor) {
895 m_userBackgroundColor = currentUserBackgroundColor;
896 m_linearBackgroundColor = QSSGUtils::color::sRGBToLinearColor(m_userBackgroundColor);
897 const QVector3D tc = tonemapRgb(QVector3D(m_linearBackgroundColor.redF(),
898 m_linearBackgroundColor.greenF(),
899 m_linearBackgroundColor.blueF()),
900 view3D->environment()->tonemapMode());
901 m_tonemappedBackgroundColor = QColor::fromRgbF(tc.x(), tc.y(), tc.z(), m_linearBackgroundColor.alphaF());
903 m_layer->scissorRect = QRect(view3D->environment()->scissorRect().topLeft() * dpr,
904 view3D->environment()->scissorRect().size() * dpr);
910 auto sceneRootNode =
static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(view3D->scene())->spatialNode);
911 if (sceneRootNode != m_sceneRootNode) {
913 removeNodeFromLayer(m_sceneRootNode);
916 addNodeToLayer(sceneRootNode);
918 m_sceneRootNode = sceneRootNode;
922 QSSGRenderNode *importSceneRootNode =
nullptr;
924 importSceneRootNode =
static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(importScene)->spatialNode);
926 if (importSceneRootNode != m_importSceneRootNode) {
927 if (m_importSceneRootNode)
928 m_layer->removeImportScene(*m_importSceneRootNode);
930 if (importSceneRootNode) {
934 QObject *sceneParent = importScene->parent();
935 bool isEmbedded =
false;
936 while (sceneParent) {
937 if (sceneParent == view3D) {
941 sceneParent = sceneParent->parent();
944 m_layer->setImportScene(*importSceneRootNode);
947 m_importSceneRootNode = importSceneRootNode;
955 QSSGRenderRoot *rootNode = winAttacment->rootNode();
956 if (rootNode->isDirty(QSSGRenderRoot::DirtyFlag::TreeDirty)) {
958 for (QSSGRenderNode &layer : rootNode->children) {
959 if (QSSG_GUARD_X(layer.type == QSSGRenderGraphObject::Type::Layer,
"Layer type mismatch"))
960 static_cast<QSSGRenderLayer &>(layer).markDirty(QSSGRenderLayer::DirtyFlag::TreeDirty);
965 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
966 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses)) {
967 if (
const auto *fo = sm->lookUpNode(userPass); fo && fo->parentItem()) {
968 const auto *pi = fo->parentItem();
969 if (
const QSSGRenderGraphObject *parentNode = QQuick3DObjectPrivate::get(pi)->spatialNode; parentNode && QSSGRenderGraphObject::isNodeType(parentNode->type))
970 userPass->setDependencyIndex(
static_cast<
const QSSGRenderNode *>(parentNode)->h.index());
972 userPass->setDependencyIndex(0);
979 maybeSetupLightmapBaking(view3D);
981 if (m_useFBO && rhiCtx->isValid()) {
982 QRhi *rhi = rhiCtx->rhi();
983 const QSize renderSize = m_layer->isSsaaEnabled() ? m_surfaceSize * m_layer->ssaaMultiplier : m_surfaceSize;
987 if (layerSizeIsDirty || postProcessingStateDirty) {
988 m_texture->setPixelSize(m_surfaceSize);
989 m_texture->setFormat(layerTextureFormat(rhi, postProcessingNeeded));
1001 if (postProcessingStateDirty && (m_layer->antialiasingMode != QSSGRenderLayer::AAMode::NoAA || m_layer->isTemporalAAEnabled())) {
1002 releaseAaDependentRhiResources();
1004 if (m_ssaaTexture) {
1005 m_ssaaTexture->setPixelSize(renderSize);
1006 m_ssaaTexture->create();
1008 if (m_depthStencilBuffer) {
1009 m_depthStencilBuffer->setPixelSize(renderSize);
1010 m_depthStencilBuffer->create();
1012 if (m_multiViewDepthStencilBuffer) {
1013 m_multiViewDepthStencilBuffer->setPixelSize(renderSize);
1014 m_multiViewDepthStencilBuffer->create();
1016 if (m_msaaRenderBufferLegacy) {
1017 m_msaaRenderBufferLegacy->setPixelSize(renderSize);
1018 m_msaaRenderBufferLegacy->create();
1020 if (m_msaaRenderTexture) {
1021 m_msaaRenderTexture->setPixelSize(renderSize);
1022 m_msaaRenderTexture->create();
1024 if (m_msaaMultiViewRenderBuffer) {
1025 m_msaaMultiViewRenderBuffer->setPixelSize(renderSize);
1026 m_msaaMultiViewRenderBuffer->create();
1032 if (postProcessingStateDirty) {
1033 delete m_textureRenderPassDescriptor;
1034 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
1035 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
1037 m_textureRenderTarget->create();
1038 if (m_ssaaTextureToTextureRenderTarget)
1039 m_ssaaTextureToTextureRenderTarget->create();
1041 if (m_temporalAATexture) {
1042 m_temporalAATexture->setPixelSize(renderSize);
1043 m_temporalAATexture->create();
1045 if (m_prevTempAATexture) {
1046 m_prevTempAATexture->setPixelSize(renderSize);
1047 m_prevTempAATexture->create();
1049 if (m_temporalAARenderTarget)
1050 m_temporalAARenderTarget->create();
1053 }
else if (m_aaIsDirty && rhi->backend() == QRhi::Metal) {
1054 m_texture->create();
1058 releaseAaDependentRhiResources();
1061 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget
1062 | QRhiTexture::UsedAsTransferSource;
1063 const QRhiTexture::Format textureFormat = layerTextureFormat(rhi, postProcessingNeeded);
1066 if (m_layer->viewCount >= 2)
1067 m_texture = rhi->newTextureArray(textureFormat, m_layer->viewCount, m_surfaceSize, 1, textureFlags);
1069 m_texture = rhi->newTexture(textureFormat, m_surfaceSize, 1, textureFlags);
1070 m_texture->create();
1073 if (!m_ssaaTexture && m_layer->isSsaaEnabled()) {
1074 if (m_layer->viewCount >= 2)
1075 m_ssaaTexture = rhi->newTextureArray(textureFormat, m_layer->viewCount, renderSize, 1, textureFlags);
1077 m_ssaaTexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1078 m_ssaaTexture->create();
1081 if (m_timeBasedAA && !m_temporalAATexture) {
1082 m_temporalAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1083 m_temporalAATexture->create();
1084 m_prevTempAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1085 m_prevTempAATexture->create();
1089 if (m_aaIsDirty || layerSizeIsDirty)
1090 m_layer->tempAAPassIndex = m_layer->progAAPassIndex = 0;
1094 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::MSAA) {
1095 if (rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer)) {
1096 m_samples = qMax(1,
int(m_layer->antialiasingQuality));
1102 const QVector<
int> supported = rhi->supportedSampleCounts();
1103 if (!supported.contains(m_samples)) {
1104 if (!supported.isEmpty()) {
1105 auto it = std::lower_bound(supported.cbegin(), supported.cend(), m_samples);
1106 m_samples = it == supported.cend() ? supported.last() : *it;
1112 static bool warned =
false;
1115 qWarning(
"Multisample renderbuffers are not supported, disabling MSAA for Offscreen View3D");
1121 if (m_layer->viewCount >= 2) {
1122 if (!m_multiViewDepthStencilBuffer) {
1123 const auto format = rhi->isTextureFormatSupported(QRhiTexture::D24S8) ? QRhiTexture::D24S8 : QRhiTexture::D32FS8;
1124 m_multiViewDepthStencilBuffer = rhi->newTextureArray(format, m_layer->viewCount, renderSize,
1125 m_samples, QRhiTexture::RenderTarget);
1126 m_multiViewDepthStencilBuffer->create();
1129 if (!m_depthStencilBuffer) {
1130 m_depthStencilBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, renderSize, m_samples);
1131 m_depthStencilBuffer->create();
1135 if (!m_textureRenderTarget) {
1136 QRhiTextureRenderTargetDescription rtDesc;
1137 QRhiColorAttachment att;
1138 if (m_samples > 1) {
1139 if (m_layer->viewCount >= 2) {
1140 m_msaaMultiViewRenderBuffer = rhi->newTextureArray(textureFormat, m_layer->viewCount, renderSize, m_samples, QRhiTexture::RenderTarget);
1141 m_msaaMultiViewRenderBuffer->create();
1142 att.setTexture(m_msaaMultiViewRenderBuffer);
1144 if (!rhi->isFeatureSupported(QRhi::MultisampleTexture)) {
1146 m_msaaRenderBufferLegacy = rhi->newRenderBuffer(QRhiRenderBuffer::Color, renderSize, m_samples, {}, m_texture->format());
1147 m_msaaRenderBufferLegacy->create();
1148 att.setRenderBuffer(m_msaaRenderBufferLegacy);
1155 m_msaaRenderTexture = rhi->newTexture(textureFormat, renderSize, m_samples, QRhiTexture::RenderTarget);
1156 m_msaaRenderTexture->create();
1157 att.setTexture(m_msaaRenderTexture);
1160 att.setResolveTexture(m_texture);
1162 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA)
1163 att.setTexture(m_ssaaTexture);
1165 att.setTexture(m_texture);
1167 att.setMultiViewCount(m_layer->viewCount);
1168 rtDesc.setColorAttachments({ att });
1169 if (m_depthStencilBuffer)
1170 rtDesc.setDepthStencilBuffer(m_depthStencilBuffer);
1171 if (m_multiViewDepthStencilBuffer)
1172 rtDesc.setDepthTexture(m_multiViewDepthStencilBuffer);
1174 m_textureRenderTarget = rhi->newTextureRenderTarget(rtDesc);
1175 m_textureRenderTarget->setName(QByteArrayLiteral(
"View3D"));
1176 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
1177 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
1178 m_textureRenderTarget->create();
1181 if (!m_ssaaTextureToTextureRenderTarget && m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
1182 QRhiColorAttachment att(m_texture);
1183 att.setMultiViewCount(m_layer->viewCount);
1184 m_ssaaTextureToTextureRenderTarget = rhi->newTextureRenderTarget(QRhiTextureRenderTargetDescription({ att }));
1185 m_ssaaTextureToTextureRenderTarget->setName(QByteArrayLiteral(
"SSAA texture"));
1186 m_ssaaTextureToTextureRenderPassDescriptor = m_ssaaTextureToTextureRenderTarget->newCompatibleRenderPassDescriptor();
1187 m_ssaaTextureToTextureRenderTarget->setRenderPassDescriptor(m_ssaaTextureToTextureRenderPassDescriptor);
1188 m_ssaaTextureToTextureRenderTarget->create();
1191 if (m_layer->firstEffect) {
1192 if (!m_effectSystem)
1193 m_effectSystem =
new QSSGRhiEffectSystem(m_sgContext);
1194 m_effectSystem->setup(renderSize);
1195 }
else if (m_effectSystem) {
1196 delete m_effectSystem;
1197 m_effectSystem =
nullptr;
1200 if (m_timeBasedAA && !m_temporalAARenderTarget) {
1201 m_temporalAARenderTarget = rhi->newTextureRenderTarget({ m_temporalAATexture });
1202 m_temporalAARenderTarget->setName(QByteArrayLiteral(
"Temporal AA texture"));
1203 m_temporalAARenderPassDescriptor = m_temporalAARenderTarget->newCompatibleRenderPassDescriptor();
1204 m_temporalAARenderTarget->setRenderPassDescriptor(m_temporalAARenderPassDescriptor);
1205 m_temporalAARenderTarget->create();
1208 m_textureNeedsFlip = rhi->isYUpInFramebuffer();
1209 m_aaIsDirty =
false;
1213 m_renderStats->endSync(dumpRenderTimes());
1215 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DSynchronizeFrame, quint64(m_surfaceSize.width()) | quint64(m_surfaceSize.height()) << 32, profilingId);
1221 fboNode->invalidatePending =
true;
1226 if (m_layer && m_layer->renderData) {
1227 if (
const auto &mgr = m_layer->renderData->getShadowMapManager())
1228 mgr->releaseCachedResources();
1229 if (
const auto &mgr = m_layer->renderData->getReflectionMapManager())
1230 mgr->releaseCachedResources();
1236 if (!m_layer || !m_layer->renderData)
1237 return std::nullopt;
1239 QMutexLocker locker(&m_layer->renderedCamerasMutex);
1241 if (m_layer->renderedCameras.isEmpty())
1242 return std::nullopt;
1244 QMatrix4x4 globalTransform = m_layer->renderData->getGlobalTransform(*m_layer->renderedCameras[0]);
1246 const QVector2D viewportSize(m_surfaceSize.width(), m_surfaceSize.height());
1247 const QVector2D position(
float(pos.x()),
float(pos.y()));
1248 const QRectF viewportRect(QPointF{}, QSizeF(m_surfaceSize));
1252 QVector2D correctCoords(position.x(), viewportSize.y() - position.y());
1253 QVector2D theLocalMouse = QSSGUtils::rect::toRectRelative(viewportRect, correctCoords);
1254 if ((theLocalMouse.x() < 0.0f || theLocalMouse.x() >= viewportSize.x() || theLocalMouse.y() < 0.0f
1255 || theLocalMouse.y() >= viewportSize.y()))
1256 return std::nullopt;
1258 return m_layer->renderedCameras[0]->unproject(globalTransform, theLocalMouse, viewportRect);
1261std::optional<QSSGRenderPickResult>
QQuick3DSceneRenderer::syncPickClosestPoint(
const QVector3D ¢er,
float radiusSquared, QSSGRenderNode *node)
1264 return std::nullopt;
1266 return QSSGRendererPrivate::syncPickClosestPoint(*m_sgContext,
1268 center, radiusSquared,
1275 return QQuick3DSceneRenderer::PickResultList();
1277 return QSSGRendererPrivate::syncPick(*m_sgContext,
1285 return QQuick3DSceneRenderer::PickResultList();
1287 return QSSGRendererPrivate::syncPick(*m_sgContext,
1294 QVarLengthArray<QSSGRenderNode *> subset)
1297 return QQuick3DSceneRenderer::PickResultList();
1299 return QSSGRendererPrivate::syncPickSubset(*m_layer,
1300 *m_sgContext->bufferManager(),
1308 return QQuick3DSceneRenderer::PickResultList();
1310 return QSSGRendererPrivate::syncPickAll(*m_sgContext,
1320 return QSSGRendererPrivate::syncPickInFrustum(*m_sgContext, *m_layer, frustum);
1325 QSSGRendererPrivate::setGlobalPickingEnabled(*m_sgContext->renderer(), isEnabled);
1330 return m_renderStats;
1333void QQuick3DRenderLayerHelpers::updateLayerNodeHelper(
const QQuick3DViewport &view3D,
1334 const std::shared_ptr<QSSGRenderContextInterface>& rci,
1335 QSSGRenderLayer &layerNode,
1337 bool &temporalIsDirty)
1339 QList<QSSGRenderGraphObject *> resourceLoaders;
1341 QQuick3DSceneRenderer dummyRenderer(rci);
1344 dummyRenderer.updateLayerNode(layerNode, view3D, resourceLoaders);
1346 aaIsDirty = dummyRenderer.m_aaIsDirty;
1347 temporalIsDirty = dummyRenderer.m_temporalIsDirty;
1351 const QQuick3DViewport &view3D,
1352 const QList<QSSGRenderGraphObject *> &resourceLoaders)
1354 QQuick3DSceneEnvironment *environment = view3D.environment();
1355 const auto &effects = environment->effectList();
1357 QSSGRenderLayer::AAMode aaMode = QSSGRenderLayer::AAMode(environment->antialiasingMode());
1358 if (aaMode != layerNode.antialiasingMode) {
1359 layerNode.antialiasingMode = aaMode;
1360 layerNode.progAAPassIndex = 0;
1363 QSSGRenderLayer::AAQuality aaQuality = QSSGRenderLayer::AAQuality(environment->antialiasingQuality());
1364 if (aaQuality != layerNode.antialiasingQuality) {
1365 layerNode.antialiasingQuality = aaQuality;
1366 layerNode.ssaaMultiplier = QSSGRenderLayer::ssaaMultiplierForQuality(aaQuality);
1371 const bool temporalAARequested = environment->temporalAAEnabled();
1372 const bool wasTaaEnabled = layerNode.isTemporalAAEnabled();
1373 layerNode.temporalAAMode = temporalAARequested ? QSSGRenderLayer::TAAMode(environment->m_temporalAAMode + 1)
1374 : QSSGRenderLayer::TAAMode::Off;
1377 if (wasTaaEnabled != layerNode.isTemporalAAEnabled()) {
1378 layerNode.tempAAPassIndex = 0;
1380 m_temporalIsDirty =
true;
1383 layerNode.temporalAAStrength = environment->temporalAAStrength();
1385 layerNode.specularAAEnabled = environment->specularAAEnabled();
1387 layerNode.background = QSSGRenderLayer::Background(environment->backgroundMode());
1388 layerNode.clearColor = QVector3D(
float(environment->clearColor().redF()),
1389 float(environment->clearColor().greenF()),
1390 float(environment->clearColor().blueF()));
1392 layerNode.gridEnabled = environment->gridEnabled();
1393 layerNode.gridScale = environment->gridScale();
1394 layerNode.gridFlags = environment->gridFlags();
1396 layerNode.aoStrength = environment->aoStrength();
1397 layerNode.aoDistance = environment->aoDistance();
1398 layerNode.aoSoftness = environment->aoSoftness();
1399 layerNode.aoEnabled = environment->aoEnabled();
1400 layerNode.aoBias = environment->aoBias();
1401 layerNode.aoSamplerate = environment->aoSampleRate();
1402 layerNode.aoDither = environment->aoDither();
1405 if (environment->lightProbe())
1406 layerNode.lightProbe = environment->lightProbe()->getRenderImage();
1408 layerNode.lightProbe =
nullptr;
1409 if (view3D.environment()->skyBoxCubeMap())
1410 layerNode.skyBoxCubeMap = view3D.environment()->skyBoxCubeMap()->getRenderImage();
1412 layerNode.skyBoxCubeMap =
nullptr;
1414 layerNode.lightProbeSettings.probeExposure = environment->probeExposure();
1416 layerNode.lightProbeSettings.probeHorizon = qMin(environment->probeHorizon() - 1.0f, -0.001f);
1417 layerNode.setProbeOrientation(environment->probeOrientation());
1419 QQuick3DViewport::updateCameraForLayer(view3D, layerNode);
1421 layerNode.layerFlags.setFlag(QSSGRenderLayer::LayerFlag::EnableDepthTest, environment->depthTestEnabled());
1422 layerNode.layerFlags.setFlag(QSSGRenderLayer::LayerFlag::EnableDepthPrePass, environment->depthPrePassEnabled());
1424 layerNode.tonemapMode = QQuick3DSceneRenderer::getTonemapMode(*environment);
1425 layerNode.skyboxBlurAmount = environment->skyboxBlurAmount();
1426 if (
auto debugSettings = view3D.environment()->debugSettings()) {
1427 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode(debugSettings->materialOverride());
1428 layerNode.wireframeMode = debugSettings->wireframeEnabled();
1429 layerNode.drawDirectionalLightShadowBoxes = debugSettings->drawDirectionalLightShadowBoxes();
1430 layerNode.drawPointLightShadowBoxes = debugSettings->drawPointLightShadowBoxes();
1431 layerNode.drawShadowCastingBounds = debugSettings->drawShadowCastingBounds();
1432 layerNode.drawShadowReceivingBounds = debugSettings->drawShadowReceivingBounds();
1433 layerNode.drawCascades = debugSettings->drawCascades();
1434 layerNode.drawSceneCascadeIntersection = debugSettings->drawSceneCascadeIntersection();
1435 layerNode.disableShadowCameraUpdate = debugSettings->disableShadowCameraUpdate();
1436 layerNode.drawCulledObjects = debugSettings->drawCulledObjects();
1438 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode::None;
1439 layerNode.wireframeMode =
false;
1442 if (environment->fog() && environment->fog()->isEnabled()) {
1443 layerNode.fog.enabled =
true;
1444 const QQuick3DFog *fog = environment->fog();
1445 layerNode.fog.color = QSSGUtils::color::sRGBToLinear(fog->color()).toVector3D();
1446 layerNode.fog.density = fog->density();
1447 layerNode.fog.depthEnabled = fog->isDepthEnabled();
1448 layerNode.fog.depthBegin = fog->depthNear();
1449 layerNode.fog.depthEnd = fog->depthFar();
1450 layerNode.fog.depthCurve = fog->depthCurve();
1451 layerNode.fog.heightEnabled = fog->isHeightEnabled();
1452 layerNode.fog.heightMin = fog->leastIntenseY();
1453 layerNode.fog.heightMax = fog->mostIntenseY();
1454 layerNode.fog.heightCurve = fog->heightCurve();
1455 layerNode.fog.transmitEnabled = fog->isTransmitEnabled();
1456 layerNode.fog.transmitCurve = fog->transmitCurve();
1458 layerNode.fog.enabled =
false;
1460 const auto method =
static_cast<QSSGRenderLayer::OITMethod>(environment->oitMethod());
1461 layerNode.oitMethodDirty = method != layerNode.oitMethod;
1462 layerNode.oitMethod = method;
1467 layerNode.firstEffect =
nullptr;
1468 auto rit = effects.crbegin();
1469 const auto rend = effects.crend();
1470 for (; rit != rend; ++rit) {
1471 QQuick3DObjectPrivate *p = QQuick3DObjectPrivate::get(*rit);
1472 QSSGRenderEffect *effectNode =
static_cast<QSSGRenderEffect *>(p->spatialNode);
1474 if (layerNode.hasEffect(effectNode)) {
1475 qWarning() <<
"Duplicate effect found, skipping!";
1477 effectNode->className = (*rit)->metaObject()->className();
1478 layerNode.addEffect(*effectNode);
1483 const bool hasEffects = (layerNode.firstEffect !=
nullptr);
1485 const auto renderMode = view3D.renderMode();
1487 const bool progressiveAA = layerNode.isProgressiveAAEnabled();
1488 const bool temporalAA = layerNode.isTemporalAAEnabled();
1489 const bool superSamplingAA = layerNode.isSsaaEnabled();
1490 m_timeBasedAA = progressiveAA || temporalAA;
1491 m_postProcessingStack = hasEffects || m_timeBasedAA || superSamplingAA;
1492 m_useFBO = renderMode == QQuick3DViewport::RenderMode::Offscreen ||
1493 ((renderMode == QQuick3DViewport::RenderMode::Underlay || renderMode == QQuick3DViewport::RenderMode::Overlay)
1494 && m_postProcessingStack);
1503 if (m_useFBO && (layerNode.viewCount > 1) && !view3D.isXrViewInstance())
1504 layerNode.viewCount = 1;
1507 layerNode.resourceLoaders.clear();
1508 layerNode.resourceLoaders = resourceLoaders;
1510 layerNode.renderOverrides = QSSGRenderLayer::RenderOverridesT(view3D.renderOverrides().toInt());
1518 m_layer->removeChild(*node);
1523 if (m_layer->renderData && m_layer->renderData->lightmapBaker)
1528 bool bakeRequested =
false;
1529 bool denoiseRequested =
false;
1530 bool fromCmd =
false;
1531 QQuick3DLightmapBaker *lightmapBaker = view3D->maybeLightmapBaker();
1532 if (lightmapBaker && (lightmapBaker->m_bakingRequested || lightmapBaker->m_denoisingRequested)) {
1533 bakeRequested = std::exchange(lightmapBaker->m_bakingRequested,
false);
1534 denoiseRequested = std::exchange(lightmapBaker->m_denoisingRequested,
false);
1536 bakeRequested = m_lightmapBakingFromCmdRequested;
1537 denoiseRequested = m_lightmapDenoisingFromCmdRequested;
1538 fromCmd = bakeRequested;
1542 if (bakeRequested || denoiseRequested) {
1543 QSSGLightmapBaker::Context ctx;
1544 ctx.settings.bakeRequested = bakeRequested;
1545 ctx.settings.denoiseRequested = denoiseRequested;
1546 ctx.settings.quitWhenFinished = fromCmd;
1549 if (lightmapBaker) {
1550 QQuick3DLightmapBaker::Callback qq3dCallback = lightmapBaker->m_callback;
1551 QQuick3DLightmapBaker::BakingControl *qq3dBakingControl = lightmapBaker->m_bakingControl;
1552 QSSGLightmapper::Callback callback =
1554 qq3dBakingControl](
const QVariantMap &payload,
1555 QSSGLightmapper::BakingControl *qssgBakingControl) {
1556 qq3dCallback(payload, qq3dBakingControl);
1558 if (qq3dBakingControl->isCancelled() && !qssgBakingControl->cancelled)
1559 qssgBakingControl->cancelled =
true;
1561 ctx.callbacks.lightmapBakingOutput = callback;
1565 ctx.callbacks.triggerNewFrame = [view3D](
bool releaseResources) {
1566 if (releaseResources) {
1567 QMetaObject::invokeMethod(view3D->window(),
1568 &QQuickWindow::releaseResources,
1569 Qt::QueuedConnection);
1571 QMetaObject::invokeMethod(view3D, &QQuick3DViewport::update, Qt::QueuedConnection);
1573 ctx.callbacks.setCurrentlyBaking = [
this](
bool value) {
1574 m_sgContext->bufferManager()->setCurrentlyLightmapBaking(value);
1577 ctx.env.rhiCtx = m_sgContext->rhiContext().get();
1578 ctx.env.renderer = m_sgContext->renderer().get();
1579 ctx.env.lmOptions = lmOptions;
1580 m_layer->renderData->initializeLightmapBaking(ctx);
1584 static bool flagsChecked =
false;
1587 flagsChecked =
true;
1589 auto isLightmapFlagSet = [](
const QString &flag,
const char *envVar) {
1590 return QCoreApplication::arguments().contains(flag)
1591 || qEnvironmentVariableIntValue(envVar);
1594 m_lightmapBakingFromCmdRequested = isLightmapFlagSet(QStringLiteral(
"--bake-lightmaps"),
"QT_QUICK3D_BAKE_LIGHTMAPS");
1595 m_lightmapDenoisingFromCmdRequested = isLightmapFlagSet(QStringLiteral(
"--denoise-lightmaps"),
"QT_QUICK3D_DENOISE_LIGHTMAPS");
1597 if (m_lightmapBakingFromCmdRequested || m_lightmapDenoisingFromCmdRequested) {
1599 QMetaObject::invokeMethod(view3D, &QQuick3DViewport::update, Qt::QueuedConnection);
1609 m_layer->addChild(*node);
1614 return BlendState | StencilState | DepthState | ScissorState | ColorState | CullState | ViewportState | RenderTargetState;
1618inline QRect convertQtRectToGLViewport(
const QRectF &rect,
const QSize surfaceSize)
1620 const int x =
int(rect.x());
1621 const int y = surfaceSize.height() - (
int(rect.y()) +
int(rect.height()));
1622 const int width =
int(rect.width());
1623 const int height =
int(rect.height());
1624 return QRect(x, y, width, height);
1627inline void queryMainRenderPassDescriptorAndCommandBuffer(QQuickWindow *window, QSSGRhiContext *rhiCtx)
1629 if (rhiCtx->isValid()) {
1630 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
1635 int sampleCount = 1;
1637 QRhiSwapChain *swapchain = window->swapChain();
1639 rhiCtxD->setMainRenderPassDescriptor(swapchain->renderPassDescriptor());
1640 rhiCtxD->setCommandBuffer(swapchain->currentFrameCommandBuffer());
1641 rhiCtxD->setRenderTarget(swapchain->currentFrameRenderTarget());
1642 sampleCount = swapchain->sampleCount();
1644 QSGRendererInterface *rif = window->rendererInterface();
1646 QRhiCommandBuffer *cb =
static_cast<QRhiCommandBuffer *>(
1647 rif->getResource(window, QSGRendererInterface::RhiRedirectCommandBuffer));
1648 QRhiTextureRenderTarget *rt =
static_cast<QRhiTextureRenderTarget *>(
1649 rif->getResource(window, QSGRendererInterface::RhiRedirectRenderTarget));
1651 rhiCtxD->setMainRenderPassDescriptor(rt->renderPassDescriptor());
1652 rhiCtxD->setCommandBuffer(cb);
1653 rhiCtxD->setRenderTarget(rt);
1654 const auto descr = rt->description();
1655 const QRhiColorAttachment *color0 = descr.cbeginColorAttachments();
1656 if (color0 && color0->texture()) {
1657 sampleCount = color0->texture()->sampleCount();
1658 if (rt->resourceType() == QRhiResource::TextureRenderTarget) {
1659 const QRhiTextureRenderTargetDescription desc =
static_cast<QRhiTextureRenderTarget *>(rt)->description();
1660 for (
auto it = desc.cbeginColorAttachments(), end = desc.cendColorAttachments(); it != end; ++it) {
1661 if (it->multiViewCount() >= 2) {
1662 viewCount = it->multiViewCount();
1669 qWarning(
"Neither swapchain nor redirected command buffer and render target are available.");
1678 rhiCtxD->setMainPassSampleCount(sampleCount);
1686 rhiCtxD->setMainPassViewCount(viewCount);
1692inline void queryInlineRenderPassDescriptorAndCommandBuffer(QSGRenderNode *node, QSSGRhiContext *rhiCtx)
1694 QSGRenderNodePrivate *d = QSGRenderNodePrivate::get(node);
1695 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
1696 rhiCtxD->setMainRenderPassDescriptor(d->m_rt.rpDesc);
1697 rhiCtxD->setCommandBuffer(d->m_rt.cb);
1698 rhiCtxD->setRenderTarget(d->m_rt.rt);
1699 rhiCtxD->setMainPassSampleCount(d->m_rt.rt->sampleCount());
1700 rhiCtxD->setMainPassViewCount(1);
1714 if (!
renderer->m_sgContext->rhiContext()->isValid())
1716 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1718 queryInlineRenderPassDescriptorAndCommandBuffer(
this,
renderer->m_sgContext->rhiContext().get());
1720 qreal dpr = window->effectiveDevicePixelRatio();
1721 const QSizeF itemSize =
renderer->surfaceSize() / dpr;
1722 QRectF viewport = matrix()->mapRect(QRectF(QPoint(0, 0), itemSize));
1723 viewport = QRectF(viewport.topLeft() * dpr, viewport.size() * dpr);
1724 const QRect vp = convertQtRectToGLViewport(viewport, window->size() * dpr);
1726 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1730 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32,
renderer->profilingId);
1733void QQuick3DSGRenderNode::
render(
const QSGRenderNode::RenderState *state)
1737 const auto &rhiContext =
renderer->m_sgContext->rhiContext();
1739 if (rhiContext->isValid()) {
1740 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1741 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1743 queryInlineRenderPassDescriptorAndCommandBuffer(
this,
renderer->m_sgContext->rhiContext().get());
1746 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1747 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiContext)),
renderer->profilingId);
1759 return NoExternalRendering;
1763 : m_renderer(renderer)
1766 if (QSGRendererInterface::isApiRhiBased(window->rendererInterface()->graphicsApi())) {
1767 connect(window, &QQuickWindow::beforeRendering,
this, &QQuick3DSGDirectRenderer::prepare, Qt::DirectConnection);
1768 if (mode == Underlay)
1769 connect(window, &QQuickWindow::beforeRenderPassRecording,
this, &
QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1771 connect(window, &QQuickWindow::afterRenderPassRecording,
this, &
QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1782 m_viewport = viewport;
1787 if (m_isVisible == visible)
1789 m_isVisible = visible;
1795 renderPending =
true;
1796 requestFullUpdate(m_window);
1806 if (m_renderer->m_sgContext->rhiContext()->isValid())
1807 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1812 if (!m_isVisible || !m_renderer)
1815 if (m_renderer->m_sgContext->rhiContext()->isValid()) {
1817 if (m_renderer->m_postProcessingStack) {
1818 if (renderPending) {
1819 renderPending =
false;
1820 m_rhiTexture = m_renderer->renderToRhiTexture(m_window);
1823 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1824 const auto &quadRenderer = m_renderer->m_sgContext->renderer()->rhiQuadRenderer();
1825 quadRenderer->prepareQuad(m_renderer->m_sgContext->rhiContext().get(),
nullptr);
1826 if (m_renderer->m_requestedFramesCount > 0) {
1828 m_renderer->m_requestedFramesCount--;
1834 QQuick3DRenderStats *renderStats = m_renderer->renderStats();
1836 renderStats->startRender();
1837 renderStats->startRenderPrepare();
1840 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1841 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1842 const QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->effectiveDevicePixelRatio());
1844 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1846 m_renderer->rhiPrepare(vp, m_window->effectiveDevicePixelRatio());
1847 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32, m_renderer->profilingId);
1850 renderStats->endRenderPrepare();
1857 if (!m_isVisible || !m_renderer)
1860 const auto &rhiContext = m_renderer->m_sgContext->rhiContext();
1862 if (rhiContext->isValid()) {
1873 if (m_renderer->m_postProcessingStack) {
1875 queryMainRenderPassDescriptorAndCommandBuffer(m_window, rhiContext.get());
1876 auto rhiCtx = m_renderer->m_sgContext->rhiContext().get();
1877 const auto &renderer = m_renderer->m_sgContext->renderer();
1878 QRhiCommandBuffer *cb = rhiContext->commandBuffer();
1879 cb->debugMarkBegin(QByteArrayLiteral(
"Post-processing result to main rt"));
1886 QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->effectiveDevicePixelRatio());
1888 const auto &shaderCache = m_renderer->m_sgContext->shaderCache();
1889 const auto &shaderPipeline = shaderCache->getBuiltInRhiShaders().getRhiSimpleQuadShader(m_renderer->m_layer->viewCount);
1891 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
1892 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge });
1893 QSSGRhiShaderResourceBindingList bindings;
1894 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, m_rhiTexture, sampler);
1895 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiContext.get());
1896 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
1898 QSSGRhiGraphicsPipelineState ps;
1899 ps.viewport = QRhiViewport(
float(vp.x()),
float(vp.y()),
float(vp.width()),
float(vp.height()));
1900 ps.samples = rhiCtx->mainPassSampleCount();
1901 ps.viewCount = m_renderer->m_layer->viewCount;
1902 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
1903 renderer->rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, rhiCtx->mainRenderPassDescriptor(), QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::PremulBlend);
1909 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1910 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1912 queryMainRenderPassDescriptorAndCommandBuffer(m_window, rhiContext.get());
1916 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1917 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiContext)),
1918 m_renderer->profilingId);
1921 if (m_renderer->renderStats())
~QQuick3DSGDirectRenderer()
void setViewport(const QRectF &viewport)
void setVisibility(bool visible)
void render(const RenderState *state) override
This function is called by the renderer and should paint this node with directly invoking commands vi...
void releaseResources() override
This function is called when all custom graphics resources allocated by this node have to be freed im...
RenderingFlags flags() const override
void prepare() override
Called from the frame preparation phase.
QQuick3DSceneRenderer * renderer
StateFlags changedStates() const override
This function should return a mask where each bit represents graphics states changed by the \l render...
PickResultList syncPick(const QSSGRenderRay &ray)
QQuick3DSceneRenderer(const std::shared_ptr< QSSGRenderContextInterface > &rci)
void invalidateFramebufferObject()
void rhiPrepare(const QRect &viewport, qreal displayPixelRatio)
PickResultList syncPickSubset(const QSSGRenderRay &ray, QVarLengthArray< QSSGRenderNode * > subset)
void synchronize(QQuick3DViewport *view3D, const QSize &size, float dpr)
std::optional< QSSGRenderRay > getRayFromViewportPos(const QPointF &pos)
PickResultList syncPickAll(const QSSGRenderRay &ray)
void setGlobalPickingEnabled(bool isEnabled)
QQuick3DRenderStats * renderStats()
QList< const QSSGRenderNode * > syncPickInFrustum(const QSSGFrustum &frustum)
void releaseCachedResources()
friend class QSSGLayerRenderData
SGFramebufferObjectNode()
~SGFramebufferObjectNode() override
QQuick3DSceneRenderer * renderer
void handleScreenChange()
QSGTexture * texture() const override
Returns a pointer to the texture object.
void preprocess() override
Override this function to do processing on the node before it is rendered.
QQuick3DViewport * quickFbo
Combined button and popup list for selecting options.
Q_TRACE_POINT(qtcore, QCoreApplication_postEvent_exit)
Q_TRACE_POINT(qtcore, QFactoryLoader_update, const QString &fileName)
Q_TRACE_POINT(qtquick3d, QSSG_renderFrame_entry, int width, int height)
static void bfs(In *inExtension, QList< Out * > &outList)
static const QVector2D s_ProgressiveAABlendFactors[QSSGLayerRenderData::MAX_AA_LEVELS]
static QVector3D tonemapRgb(const QVector3D &c, QQuick3DSceneEnvironment::QQuick3DEnvironmentTonemapModes tonemapMode)
static bool dumpRenderTimes()
Q_TRACE_POINT(qtquick3d, QSSG_synchronize_entry, QQuick3DViewport *view3D, const QSize &size, float dpr)
static const QVector2D s_TemporalAABlendFactors
static void requestFullUpdate(QQuickWindow *window)