18#include "extensions/qquick3drenderextensions.h"
19#include <QtQuick3DUtils/private/qquick3dprofiler_p.h>
21#include <QtQuick3DRuntimeRender/private/qssgrendererutil_p.h>
22#include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
24#include <QtQuick/private/qquickwindow_p.h>
25#include <QtQuick/private/qsgdefaultrendercontext_p.h>
26#include <QtQuick/private/qsgtexture_p.h>
27#include <QtQuick/private/qsgplaintexture_p.h>
28#include <QtQuick/private/qsgrendernode_p.h>
30#include <QtQuick3DRuntimeRender/private/qssgrendereffect_p.h>
31#include <QtQuick3DRuntimeRender/private/qssgrhieffectsystem_p.h>
32#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
33#include <QtQuick3DRuntimeRender/private/qssgrhiquadrenderer_p.h>
34#include <QtQuick3DRuntimeRender/private/qssgrhicontext_p.h>
35#include <QtQuick3DRuntimeRender/private/qssgcputonemapper_p.h>
36#include <QtQuick3DRuntimeRender/private/qssgrenderroot_p.h>
37#include <QtQuick3DRuntimeRender/private/qssgrenderuserpass_p.h>
39#include <QtQuick3DUtils/private/qssgutils_p.h>
40#include <QtQuick3DUtils/private/qssgassert_p.h>
43#include <qtquick3d_tracepoints_p.h>
45#include <QtCore/QObject>
46#include <QtCore/qqueue.h>
50Q_TRACE_PREFIX(qtquick3d,
52 "class QQuick3DViewport;"
56Q_TRACE_POINT(qtquick3d, QSSG_prepareFrame_entry,
int width,
int height);
67 static bool val = (qEnvironmentVariableIntValue(
"QT_QUICK3D_DUMP_RENDERTIMES") > 0);
71#if QT_CONFIG(qml_debug)
73static inline quint64 statDrawCallCount(
const QSSGRhiContextStats &stats)
76 const QSSGRhiContextStats::PerLayerInfo &info(stats.perLayerInfo[stats.layerKey]);
77 for (
const auto &pass : info.renderPasses)
78 count += QSSGRhiContextStats::totalDrawCallCountForPass(pass);
79 count += QSSGRhiContextStats::totalDrawCallCountForPass(info.externalRenderPass);
83#define STAT_PAYLOAD(stats)
84 (statDrawCallCount(stats) | (quint64(stats.perLayerInfo[stats.layerKey].renderPasses.size()) << 32
))
88template <
typename In,
typename Out>
89static void bfs(In *inExtension, QList<Out *> &outList)
91 QSSG_ASSERT(inExtension,
return);
93 QQueue<In *> queue { { inExtension } };
94 while (queue.size() > 0) {
95 if (
auto cur = queue.dequeue()) {
96 if (
auto *ext =
static_cast<Out *>(QQuick3DObjectPrivate::get(cur)->spatialNode))
97 outList.push_back(ext);
98 for (
auto &chld : cur->childItems())
99 queue.enqueue(qobject_cast<In *>(chld));
109 , devicePixelRatio(1)
111 qsgnode_set_description(
this, QStringLiteral(
"fbonode"));
112 setFlag(QSGNode::UsePreprocess,
true);
124 markDirty(DirtyMaterial);
129 return QSGSimpleTextureNode::texture();
142 if (QThread::currentThread() == QCoreApplication::instance()->thread())
145 QCoreApplication::postEvent(window,
new QEvent(QEvent::Type(QQuickWindowPrivate::FullUpdateRequest)));
152 renderer->renderStats()->startRender();
156 if (
renderer->m_sgContext->rhiContext()->isValid()) {
157 QRhiTexture *rhiTexture =
renderer->renderToRhiTexture(window);
158 bool needsNewWrapper =
false;
159 if (!texture() || (texture()->textureSize() != renderer->surfaceSize()
160 || texture()->rhiTexture() != rhiTexture))
162 needsNewWrapper =
true;
164 if (needsNewWrapper) {
166 QSGPlainTexture *t =
new QSGPlainTexture;
167 t->setOwnsTexture(
false);
168 t->setHasAlphaChannel(
true);
169 t->setTexture(rhiTexture);
170 t->setTextureSize(
renderer->surfaceSize());
175 markDirty(QSGNode::DirtyMaterial);
176 emit textureChanged();
181 if (
renderer->m_requestedFramesCount > 0) {
183 requestFullUpdate(window);
191 if (!qFuzzyCompare(window->effectiveDevicePixelRatio(), devicePixelRatio)) {
205 const auto &rhiCtx = m_sgContext->rhiContext();
206 auto *rhi = rhiCtx->rhi();
208 QSSGRhiContextStats::get(*rhiCtx).cleanupLayerInfo(m_layer);
209 m_sgContext->bufferManager()->releaseResourcesForLayer(m_layer);
219 if (m_sceneRootNode && winAttacment)
220 removeNodeFromLayer(m_sceneRootNode);
226 winAttacment->queueForCleanup(m_layer);
234 releaseAaDependentRhiResources();
235 delete m_effectSystem;
240 const auto &rhiCtx = m_sgContext->rhiContext();
241 if (!rhiCtx->isValid())
244 delete m_textureRenderTarget;
245 m_textureRenderTarget =
nullptr;
247 delete m_textureRenderPassDescriptor;
248 m_textureRenderPassDescriptor =
nullptr;
250 delete m_depthStencilBuffer;
251 m_depthStencilBuffer =
nullptr;
253 delete m_multiViewDepthStencilBuffer;
254 m_multiViewDepthStencilBuffer =
nullptr;
256 delete m_msaaRenderBufferLegacy;
257 m_msaaRenderBufferLegacy =
nullptr;
259 delete m_msaaRenderTexture;
260 m_msaaRenderTexture =
nullptr;
262 delete m_msaaMultiViewRenderBuffer;
263 m_msaaMultiViewRenderBuffer =
nullptr;
265 delete m_ssaaTexture;
266 m_ssaaTexture =
nullptr;
268 delete m_ssaaTextureToTextureRenderTarget;
269 m_ssaaTextureToTextureRenderTarget =
nullptr;
271 delete m_ssaaTextureToTextureRenderPassDescriptor;
272 m_ssaaTextureToTextureRenderPassDescriptor =
nullptr;
274 delete m_temporalAATexture;
275 m_temporalAATexture =
nullptr;
276 delete m_temporalAARenderTarget;
277 m_temporalAARenderTarget =
nullptr;
278 delete m_temporalAARenderPassDescriptor;
279 m_temporalAARenderPassDescriptor =
nullptr;
281 delete m_prevTempAATexture;
282 m_prevTempAATexture =
nullptr;
287 QVector2D(0.500000f, 0.500000f),
288 QVector2D(0.333333f, 0.666667f),
289 QVector2D(0.250000f, 0.750000f),
290 QVector2D(0.200000f, 0.800000f),
291 QVector2D(0.166667f, 0.833333f),
292 QVector2D(0.142857f, 0.857143f),
293 QVector2D(0.125000f, 0.875000f),
294 QVector2D(0.111111f, 0.888889f),
304 QRhiTexture *currentTexture = m_texture;
308 m_renderStats->startRenderPrepare();
310 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
312 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
313 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
315 rhiCtxD->setMainRenderPassDescriptor(m_textureRenderPassDescriptor);
316 rhiCtxD->setRenderTarget(m_textureRenderTarget);
318 QRhiCommandBuffer *cb =
nullptr;
319 QRhiSwapChain *swapchain = qw->swapChain();
321 cb = swapchain->currentFrameCommandBuffer();
322 rhiCtxD->setCommandBuffer(cb);
324 QSGRendererInterface *rif = qw->rendererInterface();
325 cb =
static_cast<QRhiCommandBuffer *>(
326 rif->getResource(qw, QSGRendererInterface::RhiRedirectCommandBuffer));
328 rhiCtxD->setCommandBuffer(cb);
330 qWarning(
"Neither swapchain nor redirected command buffer are available.");
331 return currentTexture;
337 rhiCtxD->setMainPassSampleCount(m_msaaRenderBufferLegacy ? m_msaaRenderBufferLegacy->sampleCount() :
338 (m_msaaRenderTexture ? m_msaaRenderTexture->sampleCount() :
339 (m_msaaMultiViewRenderBuffer ? m_msaaMultiViewRenderBuffer->sampleCount() : 1)));
343 int ssaaAdjustedWidth = m_surfaceSize.width();
344 int ssaaAdjustedHeight = m_surfaceSize.height();
345 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
346 ssaaAdjustedWidth *= m_layer->ssaaMultiplier;
347 ssaaAdjustedHeight *= m_layer->ssaaMultiplier;
350 Q_TRACE(QSSG_prepareFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
352 float dpr = m_sgContext->renderer()->dpr();
353 const QRect vp = QRect(0, 0, ssaaAdjustedWidth, ssaaAdjustedHeight);
358 m_renderStats->endRenderPrepare();
360 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, profilingId);
362 Q_TRACE(QSSG_prepareFrame_exit);
364 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
365 Q_TRACE(QSSG_renderFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
367 m_renderStats->startRender();
369 QColor clearColor = Qt::transparent;
370 if (m_backgroundMode == QSSGRenderLayer::Background::Color
371 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBoxCubeMap && !m_layer->skyBoxCubeMap)
372 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBox && !m_layer->lightProbe))
376 clearColor = m_layer->firstEffect ? m_linearBackgroundColor : m_tonemappedBackgroundColor;
381 cb->beginPass(m_textureRenderTarget, clearColor, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
382 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
383 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(m_textureRenderTarget));
386 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
387 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, QByteArrayLiteral(
"main"));
389 const bool temporalAA = m_layer->temporalAAIsActive;
390 const bool progressiveAA = m_layer->progressiveAAIsActive;
391 const bool superSamplingAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA;
392 QRhi *rhi = rhiCtx->rhi();
394 currentTexture = superSamplingAA ? m_ssaaTexture : m_texture;
397 if (m_effectSystem && m_layer->firstEffect && !m_layer->renderedCameras.isEmpty()) {
398 const auto &renderer = m_sgContext->renderer();
400 Q_ASSERT(theRenderData);
401 QRhiTexture *theDepthTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::DepthTexture)->texture;
402 QRhiTexture *theNormalTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::NormalTexture)->texture;
403 QRhiTexture *theMotionVectorTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::MotionVectorTexture)->texture;
405 currentTexture = m_effectSystem->process(*m_layer,
409 theMotionVectorTexture);
412 if ((progressiveAA || temporalAA) && m_prevTempAATexture) {
413 cb->debugMarkBegin(QByteArrayLiteral(
"Temporal AA"));
414 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
415 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"Temporal AA"));
416 QRhiTexture *blendResult;
417 uint *aaIndex = progressiveAA ? &m_layer->progAAPassIndex : &m_layer->tempAAPassIndex;
420 if ((temporalAA && m_layer->temporalAAMode != QSSGRenderLayer::TAAMode::MotionVector) ||
422 (temporalAA && m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector ?
423 quint32(QSSGLayerRenderData::MAX_AA_LEVELS) :
424 quint32(m_layer->antialiasingQuality))) {
425 const auto &renderer = m_sgContext->renderer();
427 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
428 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ m_layer,
nullptr,
nullptr, 0 }));
429 QRhiBuffer *&ubuf = dcd.ubuf;
430 const int ubufSize = 2 *
sizeof(
float);
432 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
435 int idx = *aaIndex - 1;
437 const QSize textureSize = currentTexture->pixelSize();
438 QVector2D bufferData;
440 bufferData = s_ProgressiveAABlendFactors[idx];
441 else if (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::Default)
442 bufferData = s_TemporalAABlendFactors;
444 bufferData = QVector2D(1.0f / qMax(textureSize.width(), 1), 1.0f / qMax(textureSize.height(), 1));
446 rub->updateDynamicBuffer(ubuf, 0, 2 *
sizeof(
float), &bufferData);
447 QSSGRhiGraphicsPipelineState ps;
448 ps.viewport = QRhiViewport(0, 0,
float(textureSize.width()),
float(textureSize.height()));
450 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
451 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
452 QSSGRhiShaderResourceBindingList bindings;
453 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
454 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
455 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, m_prevTempAATexture, sampler);
456 if (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector) {
458 Q_ASSERT(theRenderData);
459 QRhiTexture *theDepthTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::DepthTexture)->texture;
460 QRhiTexture *theMotionVectorTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::MotionVectorTexture)->texture;
461 bindings.addTexture(3, QRhiShaderResourceBinding::FragmentStage, theDepthTexture, sampler);
462 bindings.addTexture(4, QRhiShaderResourceBinding::FragmentStage, theMotionVectorTexture, sampler);
463 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiTemporalAAShader().get());
468 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiProgressiveAAShader().get());
471 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
472 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx, rub);
473 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_temporalAARenderTarget, QSSGRhiQuadRenderer::UvCoords);
474 blendResult = m_temporalAATexture;
476 blendResult = m_prevTempAATexture;
480 blendResult = currentTexture;
483 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
485 if ((temporalAA && m_layer->temporalAAMode != QSSGRenderLayer::TAAMode::MotionVector) ||
487 (temporalAA && m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector ?
488 quint32(QSSGLayerRenderData::MAX_AA_LEVELS) :
489 quint32(m_layer->antialiasingQuality))) {
490 auto *rub = rhi->nextResourceUpdateBatch();
491 if (progressiveAA || m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector)
492 rub->copyTexture(m_prevTempAATexture, blendResult);
494 rub->copyTexture(m_prevTempAATexture, currentTexture);
495 cb->resourceUpdate(rub);
500 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"temporal_aa"));
502 currentTexture = blendResult;
505 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
515 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
516 const auto &renderer = m_sgContext->renderer();
518 cb->debugMarkBegin(QByteArrayLiteral(
"SSAA downsample"));
519 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
521 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"SSAA downsample"));
523 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
530 const auto &shaderPipeline = m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiSupersampleResolveShader(m_layer->viewCount);
532 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
533 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
534 QSSGRhiShaderResourceBindingList bindings;
535 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
536 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
538 QSSGRhiGraphicsPipelineState ps;
539 ps.viewport = QRhiViewport(0, 0,
float(m_surfaceSize.width()),
float(m_surfaceSize.height()));
540 ps.viewCount = m_layer->viewCount;
541 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
543 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_ssaaTextureToTextureRenderTarget, QSSGRhiQuadRenderer::UvCoords);
545 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"ssaa_downsample"));
547 currentTexture = m_texture;
550 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
551 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiCtx)),
555 m_renderStats->endRender(dumpRenderTimes());
556 Q_TRACE(QSSG_renderFrame_exit);
559 return currentTexture;
564 m_sgContext->renderer()->beginFrame(*m_layer);
569 m_sgContext->renderer()->endFrame(*m_layer);
577 const auto &renderer = m_sgContext->renderer();
579 renderer->setDpr(displayPixelRatio);
581 renderer->setViewport(viewport);
583 renderer->prepareLayerForRender(*m_layer);
587 const bool renderReady = !m_layer->renderData->renderedCameras.isEmpty();
589 renderer->rhiPrepare(*m_layer);
600 m_sgContext->renderer()->rhiRender(*m_layer);
606#if QT_CONFIG(quick_shadereffect)
607static QRhiTexture::Format toRhiTextureFormat(QQuickShaderEffectSource::Format format)
610 case QQuickShaderEffectSource::RGBA8:
611 return QRhiTexture::RGBA8;
612 case QQuickShaderEffectSource::RGBA16F:
613 return QRhiTexture::RGBA16F;
614 case QQuickShaderEffectSource::RGBA32F:
615 return QRhiTexture::RGBA32F;
617 return QRhiTexture::RGBA8;
622static QVector3D tonemapRgb(
const QVector3D &c, QQuick3DSceneEnvironment::QQuick3DEnvironmentTonemapModes tonemapMode)
624 switch (tonemapMode) {
625 case QQuick3DSceneEnvironment::TonemapModeLinear:
626 return QSSGTonemapper::tonemapLinearToSrgb(c);
627 case QQuick3DSceneEnvironment::TonemapModeHejlDawson:
628 return QSSGTonemapper::tonemapHejlDawson(c);
629 case QQuick3DSceneEnvironment::TonemapModeAces:
630 return QSSGTonemapper::tonemapAces(c);
631 case QQuick3DSceneEnvironment::TonemapModeFilmic:
632 return QSSGTonemapper::tonemapFilmic(c);
641 Q_TRACE_SCOPE(QSSG_synchronize, view3D, size, dpr);
643 Q_ASSERT(view3D !=
nullptr);
644 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
645 Q_ASSERT(rhiCtx !=
nullptr);
649 m_layer =
new QSSGRenderLayer();
651 bool newRenderStats =
false;
652 if (!m_renderStats) {
653 m_renderStats = view3D->renderStats();
654 newRenderStats =
true;
658 m_renderStats->startSync();
660 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DSynchronizeFrame);
662 m_sgContext->renderer()->setDpr(dpr);
663 bool layerSizeIsDirty = m_surfaceSize != size;
664 m_surfaceSize = size;
666 QQuick3DSceneEnvironment *environment = view3D->environment();
667 if (environment->lightmapper()) {
668 QQuick3DLightmapper *lightmapper = environment->lightmapper();
669 lmOptions.opacityThreshold = lightmapper->opacityThreshold();
670 lmOptions.bias = lightmapper->bias();
671 lmOptions.useAdaptiveBias = lightmapper->isAdaptiveBiasEnabled();
672 lmOptions.indirectLightEnabled = lightmapper->isIndirectLightEnabled();
673 lmOptions.indirectLightSamples = lightmapper->samples();
674 lmOptions.indirectLightWorkgroupSize = lightmapper->indirectLightWorkgroupSize();
675 lmOptions.indirectLightBounces = lightmapper->bounces();
676 lmOptions.indirectLightFactor = lightmapper->indirectLightFactor();
677 lmOptions.sigma = lightmapper->denoiseSigma();
678 lmOptions.texelsPerUnit = lightmapper->texelsPerUnit();
684 const QQmlContext *context = qmlContext(view3D);
685 const QUrl originalSource = environment->lightmapper() ? environment->lightmapper()->source()
686 : QUrl::fromLocalFile(QStringLiteral(
"lightmaps.bin"));
687 const auto resolvedUrl = context ? context->resolvedUrl(originalSource) : originalSource;
688 const auto qmlSource = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
689 const QString lightmapSource = qmlSource.isEmpty() ? originalSource.path() : qmlSource;
690 lmOptions.source = lightmapSource;
691 m_layer->lightmapSource = lightmapSource;
694 m_sgContext->bufferManager()->setLightmapSource(lightmapSource);
698 QSet<QSSGRenderGraphObject *> resourceLoaders;
699 QQuick3DWindowAttachment::SyncResult requestSharedUpdate = QQuick3DWindowAttachment::SyncResultFlag::None;
700 if (
auto window = view3D->window()) {
701 if (!winAttacment || winAttacment->window() != window)
702 winAttacment = QQuick3DSceneManager::getOrSetWindowAttachment(*window);
704 if (winAttacment && winAttacment->rci() != m_sgContext)
705 winAttacment->setRci(m_sgContext);
707 QSSGRenderRoot *rootNode = winAttacment->rootNode();
708 if (m_layer->rootNode != rootNode) {
709 Q_ASSERT(m_layer->rootNode ==
nullptr);
710 rootNode->addChild(*m_layer);
711 rootNode->setStartVersion(m_layer->h.version());
712 m_layer->ref(rootNode);
716 requestSharedUpdate |= winAttacment->synchronize(resourceLoaders);
720 QQuick3DNode *importScene = view3D->importScene();
722 QQuick3DSceneManager *importSceneManager = QQuick3DObjectPrivate::get(importScene)->sceneManager;
725 if (
auto window = importSceneManager->window(); window && window != view3D->window()) {
726 if (
auto winAttacment = importSceneManager->wattached) {
728 auto rci = winAttacment->rci();
729 const bool inlineSync = (rci && rci->rhi() && (rci->rhi()->thread() == m_sgContext->rhi()->thread()));
733 winAttacment->synchronize(resourceLoaders);
734 }
else if (rci && !window->isExposed()) {
736 winAttacment->synchronize(resourceLoaders);
737 }
else if (!rci || (requestSharedUpdate & QQuick3DWindowAttachment::SyncResultFlag::SharedResourcesDirty)) {
742 winAttacment->requestUpdate();
755 m_layer->viewCount = rhiCtx->mainPassViewCount();
756 updateLayerNode(*m_layer, *view3D, resourceLoaders.values());
760 m_requestedFramesCount = 0;
761 if (m_layer->isProgressiveAAEnabled() || m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector) {
768 m_requestedFramesCount = (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector ? 45 :
769 int(m_layer->antialiasingQuality) + 1);
770 }
else if (m_layer->isTemporalAAEnabled()) {
775 m_requestedFramesCount = (m_aaIsDirty || m_temporalIsDirty) ? QSSGLayerRenderData::MAX_TEMPORAL_AA_LEVELS : 1;
780 for (QSSGRenderEffect *effectNode = m_layer->firstEffect; effectNode; effectNode = effectNode->m_nextEffect)
781 effectNode->finalizeShaders(*m_layer, m_sgContext.get());
784 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
785 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses))
786 userPass->finalizeShaders(*m_sgContext);
790 m_renderStats->setRhiContext(rhiCtx, m_layer);
792 static const auto getStageIndex = [](
const QSSGRenderExtension &ext) -> size_t {
793 const QSSGRenderExtension::RenderMode mode = ext.mode();
794 const QSSGRenderExtension::RenderStage stage = ext.stage();
797 if (mode == QSSGRenderExtension::RenderMode::Standalone)
798 return size_t(QSSGRenderLayer::RenderExtensionStage::TextureProviders);
801 case QSSGRenderExtension::RenderStage::PreColor:
802 return size_t(QSSGRenderLayer::RenderExtensionStage::Overlay);
803 case QSSGRenderExtension::RenderStage::PostColor:
804 return size_t(QSSGRenderLayer::RenderExtensionStage::Underlay);
807 Q_UNREACHABLE_RETURN(size_t(QSSGRenderLayer::RenderExtensionStage::Underlay));
813 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
814 const bool rebuildExtensionLists = (requestSharedUpdate & QQuick3DWindowAttachment::SyncResultFlag::ExtensionsDiry)
815 || view3D->extensionListDirty()
816 || sm->autoRegisteredExtensionsDirty;
821 if (rebuildExtensionLists) {
823 for (size_t i = 0; i != size_t(QSSGRenderLayer::RenderExtensionStage::Count); ++i)
824 m_layer->renderExtensions[i].clear();
827 const auto &extensions = view3D->extensionList();
828 for (
const auto &ext : extensions) {
829 const auto type = QQuick3DObjectPrivate::get(ext)->type;
830 if (QSSGRenderGraphObject::isExtension(type)) {
831 if (type == QSSGRenderGraphObject::Type::RenderExtension) {
832 if (
auto *renderExt = qobject_cast<QQuick3DRenderExtension *>(ext)) {
833 if (QSSGRenderExtension *ssgExt =
static_cast<QSSGRenderExtension *>(QQuick3DObjectPrivate::get(renderExt)->spatialNode)) {
834 const auto stage = getStageIndex(*ssgExt);
835 auto &list = m_layer->renderExtensions[size_t(stage)];
836 bfs(qobject_cast<QQuick3DRenderExtension *>(ext), list);
843 view3D->clearExtensionListDirty();
847 if (sm->autoRegisteredExtensionsDirty) {
848 for (QSSGRenderExtension *ae : std::as_const(sm->autoRegisteredExtensions))
849 m_layer->renderExtensions[getStageIndex(*ae)].push_back(ae);
850 sm->autoRegisteredExtensionsDirty =
false;
854 bool postProcessingNeeded = m_layer->firstEffect;
855 bool postProcessingWasActive = m_effectSystem;
856 QSSGRenderTextureFormat::Format effectOutputFormatOverride = QSSGRenderTextureFormat::Unknown;
857 if (postProcessingNeeded) {
858 QSSGRenderEffect *lastEffect = m_layer->firstEffect;
859 while (lastEffect->m_nextEffect)
860 lastEffect = lastEffect->m_nextEffect;
861 effectOutputFormatOverride = QSSGRhiEffectSystem::overriddenOutputFormat(lastEffect);
863 const auto layerTextureFormat = [effectOutputFormatOverride, view3D](QRhi *rhi,
bool postProc) {
864 if (effectOutputFormatOverride != QSSGRenderTextureFormat::Unknown)
865 return QSSGBufferManager::toRhiFormat(effectOutputFormatOverride);
880 const QRhiTexture::Format preferredPostProcFormat = QRhiTexture::RGBA16F;
881 if (postProc && rhi->isTextureFormatSupported(preferredPostProcFormat))
882 return preferredPostProcFormat;
884#if QT_CONFIG(quick_shadereffect)
885 const QRhiTexture::Format preferredView3DFormat = toRhiTextureFormat(view3D->renderFormat());
886 if (rhi->isTextureFormatSupported(preferredView3DFormat))
887 return preferredView3DFormat;
890 return QRhiTexture::RGBA8;
892 bool postProcessingStateDirty = postProcessingNeeded != postProcessingWasActive;
895 m_backgroundMode = QSSGRenderLayer::Background(view3D->environment()->backgroundMode());
899 QColor currentUserBackgroundColor = view3D->environment()->clearColor();
900 if (m_userBackgroundColor != currentUserBackgroundColor) {
901 m_userBackgroundColor = currentUserBackgroundColor;
902 m_linearBackgroundColor = QSSGUtils::color::sRGBToLinearColor(m_userBackgroundColor);
903 const QVector3D tc = tonemapRgb(QVector3D(m_linearBackgroundColor.redF(),
904 m_linearBackgroundColor.greenF(),
905 m_linearBackgroundColor.blueF()),
906 view3D->environment()->tonemapMode());
907 m_tonemappedBackgroundColor = QColor::fromRgbF(tc.x(), tc.y(), tc.z(), m_linearBackgroundColor.alphaF());
909 m_layer->scissorRect = QRect(view3D->environment()->scissorRect().topLeft() * dpr,
910 view3D->environment()->scissorRect().size() * dpr);
916 auto sceneRootNode =
static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(view3D->scene())->spatialNode);
917 if (sceneRootNode != m_sceneRootNode) {
919 removeNodeFromLayer(m_sceneRootNode);
922 addNodeToLayer(sceneRootNode);
924 m_sceneRootNode = sceneRootNode;
928 QSSGRenderNode *importSceneRootNode =
nullptr;
930 importSceneRootNode =
static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(importScene)->spatialNode);
932 if (importSceneRootNode != m_importSceneRootNode) {
933 if (m_importSceneRootNode)
934 m_layer->removeImportScene(*m_importSceneRootNode);
936 if (importSceneRootNode) {
940 QObject *sceneParent = importScene->parent();
941 bool isEmbedded =
false;
942 while (sceneParent) {
943 if (sceneParent == view3D) {
947 sceneParent = sceneParent->parent();
950 m_layer->setImportScene(*importSceneRootNode);
953 m_importSceneRootNode = importSceneRootNode;
961 QSSGRenderRoot *rootNode = winAttacment->rootNode();
962 if (rootNode->isDirty(QSSGRenderRoot::DirtyFlag::TreeDirty)) {
964 for (QSSGRenderNode &layer : rootNode->children) {
965 if (QSSG_GUARD_X(layer.type == QSSGRenderGraphObject::Type::Layer,
"Layer type mismatch"))
966 static_cast<QSSGRenderLayer &>(layer).markDirty(QSSGRenderLayer::DirtyFlag::TreeDirty);
971 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
972 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses)) {
973 if (
const auto *fo = sm->lookUpNode(userPass); fo && fo->parentItem()) {
974 const auto *pi = fo->parentItem();
975 if (
const QSSGRenderGraphObject *parentNode = QQuick3DObjectPrivate::get(pi)->spatialNode; parentNode && QSSGRenderGraphObject::isNodeType(parentNode->type))
976 userPass->setDependencyIndex(
static_cast<
const QSSGRenderNode *>(parentNode)->h.index());
978 userPass->setDependencyIndex(0);
985 maybeSetupLightmapBaking(view3D);
987 if (m_useFBO && rhiCtx->isValid()) {
988 QRhi *rhi = rhiCtx->rhi();
989 const QSize renderSize = m_layer->isSsaaEnabled() ? m_surfaceSize * m_layer->ssaaMultiplier : m_surfaceSize;
993 if (layerSizeIsDirty || postProcessingStateDirty) {
994 m_texture->setPixelSize(m_surfaceSize);
995 m_texture->setFormat(layerTextureFormat(rhi, postProcessingNeeded));
1007 if (postProcessingStateDirty && (m_layer->antialiasingMode != QSSGRenderLayer::AAMode::NoAA || m_layer->isTemporalAAEnabled())) {
1008 releaseAaDependentRhiResources();
1010 if (m_ssaaTexture) {
1011 m_ssaaTexture->setPixelSize(renderSize);
1012 m_ssaaTexture->create();
1014 if (m_depthStencilBuffer) {
1015 m_depthStencilBuffer->setPixelSize(renderSize);
1016 m_depthStencilBuffer->create();
1018 if (m_multiViewDepthStencilBuffer) {
1019 m_multiViewDepthStencilBuffer->setPixelSize(renderSize);
1020 m_multiViewDepthStencilBuffer->create();
1022 if (m_msaaRenderBufferLegacy) {
1023 m_msaaRenderBufferLegacy->setPixelSize(renderSize);
1024 m_msaaRenderBufferLegacy->create();
1026 if (m_msaaRenderTexture) {
1027 m_msaaRenderTexture->setPixelSize(renderSize);
1028 m_msaaRenderTexture->create();
1030 if (m_msaaMultiViewRenderBuffer) {
1031 m_msaaMultiViewRenderBuffer->setPixelSize(renderSize);
1032 m_msaaMultiViewRenderBuffer->create();
1038 if (postProcessingStateDirty) {
1039 delete m_textureRenderPassDescriptor;
1040 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
1041 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
1043 m_textureRenderTarget->create();
1044 if (m_ssaaTextureToTextureRenderTarget)
1045 m_ssaaTextureToTextureRenderTarget->create();
1047 if (m_temporalAATexture) {
1048 m_temporalAATexture->setPixelSize(renderSize);
1049 m_temporalAATexture->create();
1051 if (m_prevTempAATexture) {
1052 m_prevTempAATexture->setPixelSize(renderSize);
1053 m_prevTempAATexture->create();
1055 if (m_temporalAARenderTarget)
1056 m_temporalAARenderTarget->create();
1059 }
else if (m_aaIsDirty && rhi->backend() == QRhi::Metal) {
1060 m_texture->create();
1064 releaseAaDependentRhiResources();
1067 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget
1068 | QRhiTexture::UsedAsTransferSource;
1069 const QRhiTexture::Format textureFormat = layerTextureFormat(rhi, postProcessingNeeded);
1072 if (m_layer->viewCount >= 2)
1073 m_texture = rhi->newTextureArray(textureFormat, m_layer->viewCount, m_surfaceSize, 1, textureFlags);
1075 m_texture = rhi->newTexture(textureFormat, m_surfaceSize, 1, textureFlags);
1076 m_texture->create();
1079 if (!m_ssaaTexture && m_layer->isSsaaEnabled()) {
1080 if (m_layer->viewCount >= 2)
1081 m_ssaaTexture = rhi->newTextureArray(textureFormat, m_layer->viewCount, renderSize, 1, textureFlags);
1083 m_ssaaTexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1084 m_ssaaTexture->create();
1087 if (m_timeBasedAA && !m_temporalAATexture) {
1088 m_temporalAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1089 m_temporalAATexture->create();
1090 m_prevTempAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1091 m_prevTempAATexture->create();
1095 if (m_aaIsDirty || layerSizeIsDirty)
1096 m_layer->tempAAPassIndex = m_layer->progAAPassIndex = 0;
1100 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::MSAA) {
1101 if (rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer)) {
1102 m_samples = qMax(1,
int(m_layer->antialiasingQuality));
1108 const QVector<
int> supported = rhi->supportedSampleCounts();
1109 if (!supported.contains(m_samples)) {
1110 if (!supported.isEmpty()) {
1111 auto it = std::lower_bound(supported.cbegin(), supported.cend(), m_samples);
1112 m_samples = it == supported.cend() ? supported.last() : *it;
1118 static bool warned =
false;
1121 qWarning(
"Multisample renderbuffers are not supported, disabling MSAA for Offscreen View3D");
1127 if (m_layer->viewCount >= 2) {
1128 if (!m_multiViewDepthStencilBuffer) {
1129 const auto format = rhi->isTextureFormatSupported(QRhiTexture::D24S8) ? QRhiTexture::D24S8 : QRhiTexture::D32FS8;
1130 m_multiViewDepthStencilBuffer = rhi->newTextureArray(format, m_layer->viewCount, renderSize,
1131 m_samples, QRhiTexture::RenderTarget);
1132 m_multiViewDepthStencilBuffer->create();
1135 if (!m_depthStencilBuffer) {
1136 m_depthStencilBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, renderSize, m_samples);
1137 m_depthStencilBuffer->create();
1141 if (!m_textureRenderTarget) {
1142 QRhiTextureRenderTargetDescription rtDesc;
1143 QRhiColorAttachment att;
1144 if (m_samples > 1) {
1145 if (m_layer->viewCount >= 2) {
1146 m_msaaMultiViewRenderBuffer = rhi->newTextureArray(textureFormat, m_layer->viewCount, renderSize, m_samples, QRhiTexture::RenderTarget);
1147 m_msaaMultiViewRenderBuffer->create();
1148 att.setTexture(m_msaaMultiViewRenderBuffer);
1150 if (!rhi->isFeatureSupported(QRhi::MultisampleTexture)) {
1152 m_msaaRenderBufferLegacy = rhi->newRenderBuffer(QRhiRenderBuffer::Color, renderSize, m_samples, {}, m_texture->format());
1153 m_msaaRenderBufferLegacy->create();
1154 att.setRenderBuffer(m_msaaRenderBufferLegacy);
1161 m_msaaRenderTexture = rhi->newTexture(textureFormat, renderSize, m_samples, QRhiTexture::RenderTarget);
1162 m_msaaRenderTexture->create();
1163 att.setTexture(m_msaaRenderTexture);
1166 att.setResolveTexture(m_texture);
1168 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA)
1169 att.setTexture(m_ssaaTexture);
1171 att.setTexture(m_texture);
1173 att.setMultiViewCount(m_layer->viewCount);
1174 rtDesc.setColorAttachments({ att });
1175 if (m_depthStencilBuffer)
1176 rtDesc.setDepthStencilBuffer(m_depthStencilBuffer);
1177 if (m_multiViewDepthStencilBuffer)
1178 rtDesc.setDepthTexture(m_multiViewDepthStencilBuffer);
1180 m_textureRenderTarget = rhi->newTextureRenderTarget(rtDesc);
1181 m_textureRenderTarget->setName(QByteArrayLiteral(
"View3D"));
1182 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
1183 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
1184 m_textureRenderTarget->create();
1187 if (!m_ssaaTextureToTextureRenderTarget && m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
1188 QRhiColorAttachment att(m_texture);
1189 att.setMultiViewCount(m_layer->viewCount);
1190 m_ssaaTextureToTextureRenderTarget = rhi->newTextureRenderTarget(QRhiTextureRenderTargetDescription({ att }));
1191 m_ssaaTextureToTextureRenderTarget->setName(QByteArrayLiteral(
"SSAA texture"));
1192 m_ssaaTextureToTextureRenderPassDescriptor = m_ssaaTextureToTextureRenderTarget->newCompatibleRenderPassDescriptor();
1193 m_ssaaTextureToTextureRenderTarget->setRenderPassDescriptor(m_ssaaTextureToTextureRenderPassDescriptor);
1194 m_ssaaTextureToTextureRenderTarget->create();
1197 if (m_layer->firstEffect) {
1198 if (!m_effectSystem)
1199 m_effectSystem =
new QSSGRhiEffectSystem(m_sgContext);
1200 m_effectSystem->setup(renderSize);
1201 }
else if (m_effectSystem) {
1202 delete m_effectSystem;
1203 m_effectSystem =
nullptr;
1206 if (m_timeBasedAA && !m_temporalAARenderTarget) {
1207 m_temporalAARenderTarget = rhi->newTextureRenderTarget({ m_temporalAATexture });
1208 m_temporalAARenderTarget->setName(QByteArrayLiteral(
"Temporal AA texture"));
1209 m_temporalAARenderPassDescriptor = m_temporalAARenderTarget->newCompatibleRenderPassDescriptor();
1210 m_temporalAARenderTarget->setRenderPassDescriptor(m_temporalAARenderPassDescriptor);
1211 m_temporalAARenderTarget->create();
1214 m_textureNeedsFlip = rhi->isYUpInFramebuffer();
1215 m_aaIsDirty =
false;
1219 m_renderStats->endSync(dumpRenderTimes());
1221 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DSynchronizeFrame, quint64(m_surfaceSize.width()) | quint64(m_surfaceSize.height()) << 32, profilingId);
1227 fboNode->invalidatePending =
true;
1232 if (m_layer && m_layer->renderData) {
1233 if (
const auto &mgr = m_layer->renderData->getShadowMapManager())
1234 mgr->releaseCachedResources();
1235 if (
const auto &mgr = m_layer->renderData->getReflectionMapManager())
1236 mgr->releaseCachedResources();
1242 if (!m_layer || !m_layer->renderData)
1243 return std::nullopt;
1245 QMutexLocker locker(&m_layer->renderedCamerasMutex);
1247 if (m_layer->renderedCameras.isEmpty())
1248 return std::nullopt;
1250 QMatrix4x4 globalTransform = m_layer->renderData->getGlobalTransform(*m_layer->renderedCameras[0]);
1252 const QVector2D viewportSize(m_surfaceSize.width(), m_surfaceSize.height());
1253 const QVector2D position(
float(pos.x()),
float(pos.y()));
1254 const QRectF viewportRect(QPointF{}, QSizeF(m_surfaceSize));
1258 QVector2D correctCoords(position.x(), viewportSize.y() - position.y());
1259 QVector2D theLocalMouse = QSSGUtils::rect::toRectRelative(viewportRect, correctCoords);
1260 if ((theLocalMouse.x() < 0.0f || theLocalMouse.x() >= viewportSize.x() || theLocalMouse.y() < 0.0f
1261 || theLocalMouse.y() >= viewportSize.y()))
1262 return std::nullopt;
1264 return m_layer->renderedCameras[0]->unproject(globalTransform, theLocalMouse, viewportRect);
1267std::optional<QSSGRenderPickResult>
QQuick3DSceneRenderer::syncPickClosestPoint(
const QVector3D ¢er,
float radiusSquared, QSSGRenderNode *node)
1270 return std::nullopt;
1272 return QSSGRendererPrivate::syncPickClosestPoint(*m_sgContext,
1274 center, radiusSquared,
1281 return QQuick3DSceneRenderer::PickResultList();
1283 return QSSGRendererPrivate::syncPick(*m_sgContext,
1291 return QQuick3DSceneRenderer::PickResultList();
1293 return QSSGRendererPrivate::syncPick(*m_sgContext,
1300 QVarLengthArray<QSSGRenderNode *> subset)
1303 return QQuick3DSceneRenderer::PickResultList();
1305 return QSSGRendererPrivate::syncPickSubset(*m_layer,
1306 *m_sgContext->bufferManager(),
1314 return QQuick3DSceneRenderer::PickResultList();
1316 return QSSGRendererPrivate::syncPickAll(*m_sgContext,
1326 return QSSGRendererPrivate::syncPickInFrustum(*m_sgContext, *m_layer, frustum);
1331 QSSGRendererPrivate::setGlobalPickingEnabled(*m_sgContext->renderer(), isEnabled);
1336 return m_renderStats;
1339void QQuick3DRenderLayerHelpers::updateLayerNodeHelper(
const QQuick3DViewport &view3D,
1340 const std::shared_ptr<QSSGRenderContextInterface>& rci,
1341 QSSGRenderLayer &layerNode,
1343 bool &temporalIsDirty)
1345 QList<QSSGRenderGraphObject *> resourceLoaders;
1347 QQuick3DSceneRenderer dummyRenderer(rci);
1350 dummyRenderer.updateLayerNode(layerNode, view3D, resourceLoaders);
1352 aaIsDirty = dummyRenderer.m_aaIsDirty;
1353 temporalIsDirty = dummyRenderer.m_temporalIsDirty;
1357 const QQuick3DViewport &view3D,
1358 const QList<QSSGRenderGraphObject *> &resourceLoaders)
1360 QQuick3DSceneEnvironment *environment = view3D.environment();
1361 const auto &effects = environment->effectList();
1363 QSSGRenderLayer::AAMode aaMode = QSSGRenderLayer::AAMode(environment->antialiasingMode());
1364 if (aaMode != layerNode.antialiasingMode) {
1365 layerNode.antialiasingMode = aaMode;
1366 layerNode.progAAPassIndex = 0;
1369 QSSGRenderLayer::AAQuality aaQuality = QSSGRenderLayer::AAQuality(environment->antialiasingQuality());
1370 if (aaQuality != layerNode.antialiasingQuality) {
1371 layerNode.antialiasingQuality = aaQuality;
1372 layerNode.ssaaMultiplier = QSSGRenderLayer::ssaaMultiplierForQuality(aaQuality);
1377 const bool temporalAARequested = environment->temporalAAEnabled();
1378 const bool wasTaaEnabled = layerNode.isTemporalAAEnabled();
1379 layerNode.temporalAAMode = temporalAARequested ? QSSGRenderLayer::TAAMode(environment->m_temporalAAMode + 1)
1380 : QSSGRenderLayer::TAAMode::Off;
1383 if (wasTaaEnabled != layerNode.isTemporalAAEnabled()) {
1384 layerNode.tempAAPassIndex = 0;
1386 m_temporalIsDirty =
true;
1389 layerNode.temporalAAStrength = environment->temporalAAStrength();
1391 layerNode.specularAAEnabled = environment->specularAAEnabled();
1393 layerNode.background = QSSGRenderLayer::Background(environment->backgroundMode());
1394 layerNode.clearColor = QVector3D(
float(environment->clearColor().redF()),
1395 float(environment->clearColor().greenF()),
1396 float(environment->clearColor().blueF()));
1398 layerNode.gridEnabled = environment->gridEnabled();
1399 layerNode.gridScale = environment->gridScale();
1400 layerNode.gridFlags = environment->gridFlags();
1402 layerNode.aoStrength = environment->aoStrength();
1403 layerNode.aoDistance = environment->aoDistance();
1404 layerNode.aoSoftness = environment->aoSoftness();
1405 layerNode.aoEnabled = environment->aoEnabled();
1406 layerNode.aoBias = environment->aoBias();
1407 layerNode.aoSamplerate = environment->aoSampleRate();
1408 layerNode.aoDither = environment->aoDither();
1411 if (environment->lightProbe())
1412 layerNode.lightProbe = environment->lightProbe()->getRenderImage();
1414 layerNode.lightProbe =
nullptr;
1415 if (view3D.environment()->skyBoxCubeMap())
1416 layerNode.skyBoxCubeMap = view3D.environment()->skyBoxCubeMap()->getRenderImage();
1418 layerNode.skyBoxCubeMap =
nullptr;
1420 layerNode.lightProbeSettings.probeExposure = environment->probeExposure();
1422 layerNode.lightProbeSettings.probeHorizon = qMin(environment->probeHorizon() - 1.0f, -0.001f);
1423 layerNode.setProbeOrientation(environment->probeOrientation());
1425 QQuick3DViewport::updateCameraForLayer(view3D, layerNode);
1427 layerNode.layerFlags.setFlag(QSSGRenderLayer::LayerFlag::EnableDepthTest, environment->depthTestEnabled());
1428 layerNode.layerFlags.setFlag(QSSGRenderLayer::LayerFlag::EnableDepthPrePass, environment->depthPrePassEnabled());
1430 layerNode.tonemapMode = QQuick3DSceneRenderer::getTonemapMode(*environment);
1431 layerNode.skyboxBlurAmount = environment->skyboxBlurAmount();
1432 if (
auto debugSettings = view3D.environment()->debugSettings()) {
1433 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode(debugSettings->materialOverride());
1434 layerNode.wireframeMode = debugSettings->wireframeEnabled();
1435 layerNode.drawDirectionalLightShadowBoxes = debugSettings->drawDirectionalLightShadowBoxes();
1436 layerNode.drawPointLightShadowBoxes = debugSettings->drawPointLightShadowBoxes();
1437 layerNode.drawShadowCastingBounds = debugSettings->drawShadowCastingBounds();
1438 layerNode.drawShadowReceivingBounds = debugSettings->drawShadowReceivingBounds();
1439 layerNode.drawCascades = debugSettings->drawCascades();
1440 layerNode.drawSceneCascadeIntersection = debugSettings->drawSceneCascadeIntersection();
1441 layerNode.disableShadowCameraUpdate = debugSettings->disableShadowCameraUpdate();
1442 layerNode.drawCulledObjects = debugSettings->drawCulledObjects();
1444 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode::None;
1445 layerNode.wireframeMode =
false;
1448 if (environment->fog() && environment->fog()->isEnabled()) {
1449 layerNode.fog.enabled =
true;
1450 const QQuick3DFog *fog = environment->fog();
1451 layerNode.fog.color = QSSGUtils::color::sRGBToLinear(fog->color()).toVector3D();
1452 layerNode.fog.density = fog->density();
1453 layerNode.fog.depthEnabled = fog->isDepthEnabled();
1454 layerNode.fog.depthBegin = fog->depthNear();
1455 layerNode.fog.depthEnd = fog->depthFar();
1456 layerNode.fog.depthCurve = fog->depthCurve();
1457 layerNode.fog.heightEnabled = fog->isHeightEnabled();
1458 layerNode.fog.heightMin = fog->leastIntenseY();
1459 layerNode.fog.heightMax = fog->mostIntenseY();
1460 layerNode.fog.heightCurve = fog->heightCurve();
1461 layerNode.fog.transmitEnabled = fog->isTransmitEnabled();
1462 layerNode.fog.transmitCurve = fog->transmitCurve();
1464 layerNode.fog.enabled =
false;
1466 const auto method =
static_cast<QSSGRenderLayer::OITMethod>(environment->oitMethod());
1467 layerNode.oitMethodDirty = method != layerNode.oitMethod;
1468 layerNode.oitMethod = method;
1473 layerNode.firstEffect =
nullptr;
1474 auto rit = effects.crbegin();
1475 const auto rend = effects.crend();
1476 for (; rit != rend; ++rit) {
1477 QQuick3DObjectPrivate *p = QQuick3DObjectPrivate::get(*rit);
1478 QSSGRenderEffect *effectNode =
static_cast<QSSGRenderEffect *>(p->spatialNode);
1480 if (layerNode.hasEffect(effectNode)) {
1481 qWarning() <<
"Duplicate effect found, skipping!";
1483 effectNode->className = (*rit)->metaObject()->className();
1484 layerNode.addEffect(*effectNode);
1489 const bool hasEffects = (layerNode.firstEffect !=
nullptr);
1491 const auto renderMode = view3D.renderMode();
1493 const bool progressiveAA = layerNode.isProgressiveAAEnabled();
1494 const bool temporalAA = layerNode.isTemporalAAEnabled();
1495 const bool superSamplingAA = layerNode.isSsaaEnabled();
1496 m_timeBasedAA = progressiveAA || temporalAA;
1497 m_postProcessingStack = hasEffects || m_timeBasedAA || superSamplingAA;
1498 m_useFBO = renderMode == QQuick3DViewport::RenderMode::Offscreen ||
1499 ((renderMode == QQuick3DViewport::RenderMode::Underlay || renderMode == QQuick3DViewport::RenderMode::Overlay)
1500 && m_postProcessingStack);
1509 if (m_useFBO && (layerNode.viewCount > 1) && !view3D.isXrViewInstance())
1510 layerNode.viewCount = 1;
1513 layerNode.resourceLoaders.clear();
1514 layerNode.resourceLoaders = resourceLoaders;
1516 layerNode.renderOverrides = QSSGRenderLayer::RenderOverridesT(view3D.renderOverrides().toInt());
1524 m_layer->removeChild(*node);
1529 if (m_layer->renderData && m_layer->renderData->lightmapBaker)
1534 bool bakeRequested =
false;
1535 bool denoiseRequested =
false;
1536 bool fromCmd =
false;
1537 QQuick3DLightmapBaker *lightmapBaker = view3D->maybeLightmapBaker();
1538 if (lightmapBaker && (lightmapBaker->m_bakingRequested || lightmapBaker->m_denoisingRequested)) {
1539 bakeRequested = std::exchange(lightmapBaker->m_bakingRequested,
false);
1540 denoiseRequested = std::exchange(lightmapBaker->m_denoisingRequested,
false);
1542 bakeRequested = m_lightmapBakingFromCmdRequested;
1543 denoiseRequested = m_lightmapDenoisingFromCmdRequested;
1544 fromCmd = bakeRequested;
1548 if (bakeRequested || denoiseRequested) {
1549 QSSGLightmapBaker::Context ctx;
1550 ctx.settings.bakeRequested = bakeRequested;
1551 ctx.settings.denoiseRequested = denoiseRequested;
1552 ctx.settings.quitWhenFinished = fromCmd;
1555 if (lightmapBaker) {
1556 QQuick3DLightmapBaker::Callback qq3dCallback = lightmapBaker->m_callback;
1557 QQuick3DLightmapBaker::BakingControl *qq3dBakingControl = lightmapBaker->m_bakingControl;
1558 QSSGLightmapper::Callback callback =
1560 qq3dBakingControl](
const QVariantMap &payload,
1561 QSSGLightmapper::BakingControl *qssgBakingControl) {
1562 qq3dCallback(payload, qq3dBakingControl);
1564 if (qq3dBakingControl->isCancelled() && !qssgBakingControl->cancelled)
1565 qssgBakingControl->cancelled =
true;
1567 ctx.callbacks.lightmapBakingOutput = callback;
1571 ctx.callbacks.triggerNewFrame = [view3D](
bool releaseResources) {
1572 if (releaseResources) {
1573 QMetaObject::invokeMethod(view3D->window(),
1574 &QQuickWindow::releaseResources,
1575 Qt::QueuedConnection);
1577 QMetaObject::invokeMethod(view3D, &QQuick3DViewport::update, Qt::QueuedConnection);
1579 ctx.callbacks.setCurrentlyBaking = [
this](
bool value) {
1580 m_sgContext->bufferManager()->setCurrentlyLightmapBaking(value);
1583 ctx.env.rhiCtx = m_sgContext->rhiContext().get();
1584 ctx.env.renderer = m_sgContext->renderer().get();
1585 ctx.env.lmOptions = lmOptions;
1586 m_layer->renderData->initializeLightmapBaking(ctx);
1590 static bool flagsChecked =
false;
1593 flagsChecked =
true;
1595 auto isLightmapFlagSet = [](
const QString &flag,
const char *envVar) {
1596 return QCoreApplication::arguments().contains(flag)
1597 || qEnvironmentVariableIntValue(envVar);
1600 m_lightmapBakingFromCmdRequested = isLightmapFlagSet(QStringLiteral(
"--bake-lightmaps"),
"QT_QUICK3D_BAKE_LIGHTMAPS");
1601 m_lightmapDenoisingFromCmdRequested = isLightmapFlagSet(QStringLiteral(
"--denoise-lightmaps"),
"QT_QUICK3D_DENOISE_LIGHTMAPS");
1603 if (m_lightmapBakingFromCmdRequested || m_lightmapDenoisingFromCmdRequested) {
1605 QMetaObject::invokeMethod(view3D, &QQuick3DViewport::update, Qt::QueuedConnection);
1615 m_layer->addChild(*node);
1620 return BlendState | StencilState | DepthState | ScissorState | ColorState | CullState | ViewportState | RenderTargetState;
1624inline QRect convertQtRectToGLViewport(
const QRectF &rect,
const QSize surfaceSize)
1626 const int x =
int(rect.x());
1627 const int y = surfaceSize.height() - (
int(rect.y()) +
int(rect.height()));
1628 const int width =
int(rect.width());
1629 const int height =
int(rect.height());
1630 return QRect(x, y, width, height);
1633inline void queryMainRenderPassDescriptorAndCommandBuffer(QQuickWindow *window, QSSGRhiContext *rhiCtx)
1635 if (rhiCtx->isValid()) {
1636 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
1641 int sampleCount = 1;
1643 QRhiSwapChain *swapchain = window->swapChain();
1645 rhiCtxD->setMainRenderPassDescriptor(swapchain->renderPassDescriptor());
1646 rhiCtxD->setCommandBuffer(swapchain->currentFrameCommandBuffer());
1647 rhiCtxD->setRenderTarget(swapchain->currentFrameRenderTarget());
1648 sampleCount = swapchain->sampleCount();
1650 QSGRendererInterface *rif = window->rendererInterface();
1652 QRhiCommandBuffer *cb =
static_cast<QRhiCommandBuffer *>(
1653 rif->getResource(window, QSGRendererInterface::RhiRedirectCommandBuffer));
1654 QRhiTextureRenderTarget *rt =
static_cast<QRhiTextureRenderTarget *>(
1655 rif->getResource(window, QSGRendererInterface::RhiRedirectRenderTarget));
1657 rhiCtxD->setMainRenderPassDescriptor(rt->renderPassDescriptor());
1658 rhiCtxD->setCommandBuffer(cb);
1659 rhiCtxD->setRenderTarget(rt);
1660 const auto descr = rt->description();
1661 const QRhiColorAttachment *color0 = descr.cbeginColorAttachments();
1662 if (color0 && color0->texture()) {
1663 sampleCount = color0->texture()->sampleCount();
1664 if (rt->resourceType() == QRhiResource::TextureRenderTarget) {
1665 const QRhiTextureRenderTargetDescription desc =
static_cast<QRhiTextureRenderTarget *>(rt)->description();
1666 for (
auto it = desc.cbeginColorAttachments(), end = desc.cendColorAttachments(); it != end; ++it) {
1667 if (it->multiViewCount() >= 2) {
1668 viewCount = it->multiViewCount();
1675 qWarning(
"Neither swapchain nor redirected command buffer and render target are available.");
1684 rhiCtxD->setMainPassSampleCount(sampleCount);
1692 rhiCtxD->setMainPassViewCount(viewCount);
1698inline void queryInlineRenderPassDescriptorAndCommandBuffer(QSGRenderNode *node, QSSGRhiContext *rhiCtx)
1700 QSGRenderNodePrivate *d = QSGRenderNodePrivate::get(node);
1701 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
1702 rhiCtxD->setMainRenderPassDescriptor(d->m_rt.rpDesc);
1703 rhiCtxD->setCommandBuffer(d->m_rt.cb);
1704 rhiCtxD->setRenderTarget(d->m_rt.rt);
1705 rhiCtxD->setMainPassSampleCount(d->m_rt.rt->sampleCount());
1706 rhiCtxD->setMainPassViewCount(1);
1720 if (!
renderer->m_sgContext->rhiContext()->isValid())
1722 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1724 renderer->renderStats()->startRenderPrepare();
1726 queryInlineRenderPassDescriptorAndCommandBuffer(
this,
renderer->m_sgContext->rhiContext().get());
1728 qreal dpr = window->effectiveDevicePixelRatio();
1729 const QSizeF itemSize =
renderer->surfaceSize() / dpr;
1730 QRectF viewport = matrix()->mapRect(QRectF(QPoint(0, 0), itemSize));
1731 viewport = QRectF(viewport.topLeft() * dpr, viewport.size() * dpr);
1732 const QRect vp = convertQtRectToGLViewport(viewport, window->size() * dpr);
1734 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1738 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32,
renderer->profilingId);
1740 renderer->renderStats()->endRenderPrepare();
1743void QQuick3DSGRenderNode::
render(
const QSGRenderNode::RenderState *state)
1747 const auto &rhiContext =
renderer->m_sgContext->rhiContext();
1749 if (rhiContext->isValid()) {
1751 renderer->renderStats()->startRender();
1752 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1753 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1755 queryInlineRenderPassDescriptorAndCommandBuffer(
this,
renderer->m_sgContext->rhiContext().get());
1758 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1759 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiContext)),
renderer->profilingId);
1773 return NoExternalRendering;
1777 : m_renderer(renderer)
1780 if (QSGRendererInterface::isApiRhiBased(window->rendererInterface()->graphicsApi())) {
1781 connect(window, &QQuickWindow::beforeRendering,
this, &QQuick3DSGDirectRenderer::prepare, Qt::DirectConnection);
1782 if (mode == Underlay)
1783 connect(window, &QQuickWindow::beforeRenderPassRecording,
this, &
QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1785 connect(window, &QQuickWindow::afterRenderPassRecording,
this, &
QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1796 m_viewport = viewport;
1801 if (m_isVisible == visible)
1803 m_isVisible = visible;
1809 renderPending =
true;
1810 requestFullUpdate(m_window);
1820 if (m_renderer->m_sgContext->rhiContext()->isValid())
1821 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1826 if (!m_isVisible || !m_renderer)
1829 if (m_renderer->m_sgContext->rhiContext()->isValid()) {
1831 if (m_renderer->m_postProcessingStack) {
1832 if (renderPending) {
1833 renderPending =
false;
1834 m_rhiTexture = m_renderer->renderToRhiTexture(m_window);
1837 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1838 const auto &quadRenderer = m_renderer->m_sgContext->renderer()->rhiQuadRenderer();
1839 quadRenderer->prepareQuad(m_renderer->m_sgContext->rhiContext().get(),
nullptr);
1840 if (m_renderer->m_requestedFramesCount > 0) {
1842 m_renderer->m_requestedFramesCount--;
1848 QQuick3DRenderStats *renderStats = m_renderer->renderStats();
1850 renderStats->startRenderPrepare();
1852 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1853 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1854 const QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->effectiveDevicePixelRatio());
1856 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1858 m_renderer->rhiPrepare(vp, m_window->effectiveDevicePixelRatio());
1859 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32, m_renderer->profilingId);
1862 renderStats->endRenderPrepare();
1869 if (!m_isVisible || !m_renderer)
1872 const auto &rhiContext = m_renderer->m_sgContext->rhiContext();
1874 if (rhiContext->isValid()) {
1885 if (m_renderer->m_postProcessingStack) {
1887 queryMainRenderPassDescriptorAndCommandBuffer(m_window, rhiContext.get());
1888 auto rhiCtx = m_renderer->m_sgContext->rhiContext().get();
1889 const auto &renderer = m_renderer->m_sgContext->renderer();
1890 QRhiCommandBuffer *cb = rhiContext->commandBuffer();
1891 cb->debugMarkBegin(QByteArrayLiteral(
"Post-processing result to main rt"));
1898 QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->effectiveDevicePixelRatio());
1900 const auto &shaderCache = m_renderer->m_sgContext->shaderCache();
1901 const auto &shaderPipeline = shaderCache->getBuiltInRhiShaders().getRhiSimpleQuadShader(m_renderer->m_layer->viewCount);
1903 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
1904 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge });
1905 QSSGRhiShaderResourceBindingList bindings;
1906 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, m_rhiTexture, sampler);
1907 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiContext.get());
1908 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
1910 QSSGRhiGraphicsPipelineState ps;
1911 ps.viewport = QRhiViewport(
float(vp.x()),
float(vp.y()),
float(vp.width()),
float(vp.height()));
1912 ps.samples = rhiCtx->mainPassSampleCount();
1913 ps.viewCount = m_renderer->m_layer->viewCount;
1914 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
1915 renderer->rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, rhiCtx->mainRenderPassDescriptor(), QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::PremulBlend);
1921 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1922 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1923 if (m_renderer->renderStats())
1924 m_renderer->renderStats()->startRender();
1926 queryMainRenderPassDescriptorAndCommandBuffer(m_window, rhiContext.get());
1930 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1931 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiContext)),
1932 m_renderer->profilingId);
1935 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)