18#include "extensions/qquick3drenderextensions.h"
19#include <QtQuick3DUtils/private/qquick3dprofiler_p.h>
21#include <QtQuick3DRuntimeRender/private/qssgrendererutil_p.h>
22#include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
24#include <QtQuick/private/qquickwindow_p.h>
25#include <QtQuick/private/qsgdefaultrendercontext_p.h>
26#include <QtQuick/private/qsgtexture_p.h>
27#include <QtQuick/private/qsgplaintexture_p.h>
28#include <QtQuick/private/qsgrendernode_p.h>
30#include <QtQuick3DRuntimeRender/private/qssgrendereffect_p.h>
31#include <QtQuick3DRuntimeRender/private/qssgrhieffectsystem_p.h>
32#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
33#include <QtQuick3DRuntimeRender/private/qssgrhiquadrenderer_p.h>
34#include <QtQuick3DRuntimeRender/private/qssgrhicontext_p.h>
35#include <QtQuick3DRuntimeRender/private/qssgcputonemapper_p.h>
36#include <QtQuick3DRuntimeRender/private/qssgrenderroot_p.h>
37#include <QtQuick3DRuntimeRender/private/qssgrenderuserpass_p.h>
39#include <QtQuick3DUtils/private/qssgutils_p.h>
40#include <QtQuick3DUtils/private/qssgassert_p.h>
43#include <qtquick3d_tracepoints_p.h>
45#include <QtCore/QObject>
46#include <QtCore/qqueue.h>
50Q_TRACE_PREFIX(qtquick3d,
52 "class QQuick3DViewport;"
56Q_TRACE_POINT(qtquick3d, QSSG_prepareFrame_entry,
int width,
int height);
67 static bool val = (qEnvironmentVariableIntValue(
"QT_QUICK3D_DUMP_RENDERTIMES") > 0);
71#if QT_CONFIG(qml_debug)
73static inline quint64 statDrawCallCount(
const QSSGRhiContextStats &stats)
76 const QSSGRhiContextStats::PerLayerInfo &info(stats.perLayerInfo[stats.layerKey]);
77 for (
const auto &pass : info.renderPasses)
78 count += QSSGRhiContextStats::totalDrawCallCountForPass(pass);
79 count += QSSGRhiContextStats::totalDrawCallCountForPass(info.externalRenderPass);
83#define STAT_PAYLOAD(stats)
84 (statDrawCallCount(stats) | (quint64(stats.perLayerInfo[stats.layerKey].renderPasses.size()) << 32
))
88template <
typename In,
typename Out>
89static void bfs(In *inExtension, QList<Out *> &outList)
91 QSSG_ASSERT(inExtension,
return);
93 QQueue<In *> queue { { inExtension } };
94 while (queue.size() > 0) {
95 if (
auto cur = queue.dequeue()) {
96 if (
auto *ext =
static_cast<Out *>(QQuick3DObjectPrivate::get(cur)->spatialNode))
97 outList.push_back(ext);
98 for (
auto &chld : cur->childItems())
99 queue.enqueue(qobject_cast<In *>(chld));
109 , devicePixelRatio(1)
111 qsgnode_set_description(
this, QStringLiteral(
"fbonode"));
112 setFlag(QSGNode::UsePreprocess,
true);
124 markDirty(DirtyMaterial);
129 return QSGSimpleTextureNode::texture();
142 if (QThread::currentThread() == QCoreApplication::instance()->thread())
145 QCoreApplication::postEvent(window,
new QEvent(QEvent::Type(QQuickWindowPrivate::FullUpdateRequest)));
152 renderer->renderStats()->startRender();
156 if (
renderer->m_sgContext->rhiContext()->isValid()) {
157 QRhiTexture *rhiTexture =
renderer->renderToRhiTexture(window);
158 bool needsNewWrapper =
false;
159 if (!texture() || (texture()->textureSize() != renderer->surfaceSize()
160 || texture()->rhiTexture() != rhiTexture))
162 needsNewWrapper =
true;
164 if (needsNewWrapper) {
166 QSGPlainTexture *t =
new QSGPlainTexture;
167 t->setOwnsTexture(
false);
168 t->setHasAlphaChannel(
true);
169 t->setTexture(rhiTexture);
170 t->setTextureSize(
renderer->surfaceSize());
175 markDirty(QSGNode::DirtyMaterial);
176 emit textureChanged();
181 if (
renderer->m_requestedFramesCount > 0) {
183 requestFullUpdate(window);
191 if (!qFuzzyCompare(window->effectiveDevicePixelRatio(), devicePixelRatio)) {
205 const auto &rhiCtx = m_sgContext->rhiContext();
206 auto *rhi = rhiCtx->rhi();
208 QSSGRhiContextStats::get(*rhiCtx).cleanupLayerInfo(m_layer);
209 m_sgContext->bufferManager()->releaseResourcesForLayer(m_layer);
219 if (m_sceneRootNode && winAttacment)
220 removeNodeFromLayer(m_sceneRootNode);
226 winAttacment->queueForCleanup(m_layer);
234 releaseAaDependentRhiResources();
235 delete m_effectSystem;
240 const auto &rhiCtx = m_sgContext->rhiContext();
241 if (!rhiCtx->isValid())
244 delete m_textureRenderTarget;
245 m_textureRenderTarget =
nullptr;
247 delete m_textureRenderPassDescriptor;
248 m_textureRenderPassDescriptor =
nullptr;
250 delete m_depthStencilBuffer;
251 m_depthStencilBuffer =
nullptr;
253 delete m_multiViewDepthStencilBuffer;
254 m_multiViewDepthStencilBuffer =
nullptr;
256 delete m_msaaRenderBufferLegacy;
257 m_msaaRenderBufferLegacy =
nullptr;
259 delete m_msaaRenderTexture;
260 m_msaaRenderTexture =
nullptr;
262 delete m_msaaMultiViewRenderBuffer;
263 m_msaaMultiViewRenderBuffer =
nullptr;
265 delete m_ssaaTexture;
266 m_ssaaTexture =
nullptr;
268 delete m_ssaaTextureToTextureRenderTarget;
269 m_ssaaTextureToTextureRenderTarget =
nullptr;
271 delete m_ssaaTextureToTextureRenderPassDescriptor;
272 m_ssaaTextureToTextureRenderPassDescriptor =
nullptr;
274 delete m_temporalAATexture;
275 m_temporalAATexture =
nullptr;
276 delete m_temporalAARenderTarget;
277 m_temporalAARenderTarget =
nullptr;
278 delete m_temporalAARenderPassDescriptor;
279 m_temporalAARenderPassDescriptor =
nullptr;
281 delete m_prevTempAATexture;
282 m_prevTempAATexture =
nullptr;
287 QVector2D(0.500000f, 0.500000f),
288 QVector2D(0.333333f, 0.666667f),
289 QVector2D(0.250000f, 0.750000f),
290 QVector2D(0.200000f, 0.800000f),
291 QVector2D(0.166667f, 0.833333f),
292 QVector2D(0.142857f, 0.857143f),
293 QVector2D(0.125000f, 0.875000f),
294 QVector2D(0.111111f, 0.888889f),
304 QRhiTexture *currentTexture = m_texture;
308 m_renderStats->startRenderPrepare();
310 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
312 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
313 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
315 rhiCtxD->setMainRenderPassDescriptor(m_textureRenderPassDescriptor);
316 rhiCtxD->setRenderTarget(m_textureRenderTarget);
318 QRhiCommandBuffer *cb =
nullptr;
319 QRhiSwapChain *swapchain = qw->swapChain();
321 cb = swapchain->currentFrameCommandBuffer();
322 rhiCtxD->setCommandBuffer(cb);
324 QSGRendererInterface *rif = qw->rendererInterface();
325 cb =
static_cast<QRhiCommandBuffer *>(
326 rif->getResource(qw, QSGRendererInterface::RhiRedirectCommandBuffer));
328 rhiCtxD->setCommandBuffer(cb);
330 qWarning(
"Neither swapchain nor redirected command buffer are available.");
331 return currentTexture;
337 rhiCtxD->setMainPassSampleCount(m_msaaRenderBufferLegacy ? m_msaaRenderBufferLegacy->sampleCount() :
338 (m_msaaRenderTexture ? m_msaaRenderTexture->sampleCount() :
339 (m_msaaMultiViewRenderBuffer ? m_msaaMultiViewRenderBuffer->sampleCount() : 1)));
343 int ssaaAdjustedWidth = m_surfaceSize.width();
344 int ssaaAdjustedHeight = m_surfaceSize.height();
345 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
346 ssaaAdjustedWidth *= m_layer->ssaaMultiplier;
347 ssaaAdjustedHeight *= m_layer->ssaaMultiplier;
350 Q_TRACE(QSSG_prepareFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
352 float dpr = m_sgContext->renderer()->dpr();
353 const QRect vp = QRect(0, 0, ssaaAdjustedWidth, ssaaAdjustedHeight);
358 m_renderStats->endRenderPrepare();
360 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, profilingId);
362 Q_TRACE(QSSG_prepareFrame_exit);
364 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
365 Q_TRACE(QSSG_renderFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
367 m_renderStats->startRender();
369 QColor clearColor = Qt::transparent;
370 if (m_backgroundMode == QSSGRenderLayer::Background::Color
371 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBoxCubeMap && !m_layer->skyBoxCubeMap)
372 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBox && !m_layer->lightProbe))
376 clearColor = m_layer->firstEffect ? m_linearBackgroundColor : m_tonemappedBackgroundColor;
381 cb->beginPass(m_textureRenderTarget, clearColor, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
382 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
383 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(m_textureRenderTarget));
386 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
387 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, QByteArrayLiteral(
"main"));
389 const bool temporalAA = m_layer->temporalAAIsActive;
390 const bool progressiveAA = m_layer->progressiveAAIsActive;
391 const bool superSamplingAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA;
392 QRhi *rhi = rhiCtx->rhi();
394 currentTexture = superSamplingAA ? m_ssaaTexture : m_texture;
397 if (m_effectSystem && m_layer->firstEffect && !m_layer->renderedCameras.isEmpty()) {
398 const auto &renderer = m_sgContext->renderer();
400 Q_ASSERT(theRenderData);
401 QRhiTexture *theDepthTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::DepthTexture)->texture;
402 QRhiTexture *theNormalTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::NormalTexture)->texture;
403 QRhiTexture *theMotionVectorTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::MotionVectorTexture)->texture;
405 currentTexture = m_effectSystem->process(*m_layer,
409 theMotionVectorTexture);
412 if ((progressiveAA || temporalAA) && m_prevTempAATexture) {
413 cb->debugMarkBegin(QByteArrayLiteral(
"Temporal AA"));
414 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
415 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"Temporal AA"));
416 QRhiTexture *blendResult;
417 uint *aaIndex = progressiveAA ? &m_layer->progAAPassIndex : &m_layer->tempAAPassIndex;
420 if ((temporalAA && m_layer->temporalAAMode != QSSGRenderLayer::TAAMode::MotionVector) ||
422 (temporalAA && m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector ?
423 quint32(QSSGLayerRenderData::MAX_AA_LEVELS) :
424 quint32(m_layer->antialiasingQuality))) {
425 const auto &renderer = m_sgContext->renderer();
427 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
428 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ m_layer,
nullptr,
nullptr, 0 }));
429 QRhiBuffer *&ubuf = dcd.ubuf;
430 const int ubufSize = 4 *
sizeof(
float);
432 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
435 int idx = *aaIndex - 1;
437 const QSize textureSize = m_prevTempAATexture->pixelSize();
438 QVector4D bufferData;
440 bufferData = QVector4D(s_ProgressiveAABlendFactors[idx]);
441 else if (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::Default)
442 bufferData = QVector4D(s_TemporalAABlendFactors);
444 bufferData = QVector4D(1.0f / qMax(textureSize.width(), 1), 1.0f / qMax(textureSize.height(), 1),
445 0.9f + (qMin(qMax(m_layer->temporalAAStrength, 0.3f), 1.0f) - 0.3f) / 0.7f * 0.09f, 0.0f);
447 rub->updateDynamicBuffer(ubuf, 0, 4 *
sizeof(
float), &bufferData);
448 QSSGRhiGraphicsPipelineState ps;
449 ps.viewport = QRhiViewport(0, 0,
float(textureSize.width()),
float(textureSize.height()));
451 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
452 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
453 QSSGRhiShaderResourceBindingList bindings;
454 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
455 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
456 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, m_prevTempAATexture, sampler);
457 if (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector) {
459 Q_ASSERT(theRenderData);
460 QRhiTexture *theDepthTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::DepthTexture)->texture;
461 QRhiTexture *theMotionVectorTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::MotionVectorTexture)->texture;
462 bindings.addTexture(3, QRhiShaderResourceBinding::FragmentStage, theDepthTexture, sampler);
463 bindings.addTexture(4, QRhiShaderResourceBinding::FragmentStage, theMotionVectorTexture, sampler);
464 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiTemporalAAShader().get());
469 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiProgressiveAAShader().get());
472 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
473 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx, rub);
474 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_temporalAARenderTarget, QSSGRhiQuadRenderer::UvCoords);
475 blendResult = m_temporalAATexture;
477 blendResult = m_prevTempAATexture;
481 blendResult = currentTexture;
484 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
486 const bool isMotionVector = m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector;
487 const quint32 aaLimit = (temporalAA && isMotionVector) ? quint32(QSSGLayerRenderData::MAX_AA_LEVELS) : quint32(m_layer->antialiasingQuality);
489 const bool aaActive = (temporalAA && !isMotionVector) || (*aaIndex < aaLimit);
490 const bool usePrevTexture = m_prevTempAATexture !=
nullptr;
492 if (aaActive && usePrevTexture) {
493 QRhiTexture *copySource = (blendResult && (progressiveAA || isMotionVector)) ? blendResult : currentTexture;
496 auto *rub = rhi->nextResourceUpdateBatch();
497 rub->copyTexture(m_prevTempAATexture, copySource);
498 cb->resourceUpdate(rub);
504 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"temporal_aa"));
506 currentTexture = blendResult;
509 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
519 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
520 const auto &renderer = m_sgContext->renderer();
522 cb->debugMarkBegin(QByteArrayLiteral(
"SSAA downsample"));
523 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
525 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"SSAA downsample"));
527 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
534 const auto &shaderPipeline = m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiSupersampleResolveShader(m_layer->viewCount);
536 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
537 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
538 QSSGRhiShaderResourceBindingList bindings;
539 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
540 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
542 QSSGRhiGraphicsPipelineState ps;
543 ps.viewport = QRhiViewport(0, 0,
float(m_surfaceSize.width()),
float(m_surfaceSize.height()));
544 ps.viewCount = m_layer->viewCount;
545 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
547 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_ssaaTextureToTextureRenderTarget, QSSGRhiQuadRenderer::UvCoords);
549 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"ssaa_downsample"));
551 currentTexture = m_texture;
554 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
555 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiCtx)),
559 m_renderStats->endRender(dumpRenderTimes());
560 Q_TRACE(QSSG_renderFrame_exit);
563 return currentTexture;
568 m_sgContext->renderer()->beginFrame(*m_layer);
573 m_sgContext->renderer()->endFrame(*m_layer);
581 const auto &renderer = m_sgContext->renderer();
583 renderer->setDpr(displayPixelRatio);
585 renderer->setViewport(viewport);
587 renderer->prepareLayerForRender(*m_layer);
591 const bool renderReady = !m_layer->renderData->renderedCameras.isEmpty();
593 renderer->rhiPrepare(*m_layer);
604 m_sgContext->renderer()->rhiRender(*m_layer);
610#if QT_CONFIG(quick_shadereffect)
611static QRhiTexture::Format toRhiTextureFormat(QQuickShaderEffectSource::Format format)
614 case QQuickShaderEffectSource::RGBA8:
615 return QRhiTexture::RGBA8;
616 case QQuickShaderEffectSource::RGBA16F:
617 return QRhiTexture::RGBA16F;
618 case QQuickShaderEffectSource::RGBA32F:
619 return QRhiTexture::RGBA32F;
621 return QRhiTexture::RGBA8;
626static QVector3D tonemapRgb(
const QVector3D &c, QQuick3DSceneEnvironment::QQuick3DEnvironmentTonemapModes tonemapMode)
628 switch (tonemapMode) {
629 case QQuick3DSceneEnvironment::TonemapModeLinear:
630 return QSSGTonemapper::tonemapLinearToSrgb(c);
631 case QQuick3DSceneEnvironment::TonemapModeHejlDawson:
632 return QSSGTonemapper::tonemapHejlDawson(c);
633 case QQuick3DSceneEnvironment::TonemapModeAces:
634 return QSSGTonemapper::tonemapAces(c);
635 case QQuick3DSceneEnvironment::TonemapModeFilmic:
636 return QSSGTonemapper::tonemapFilmic(c);
645 Q_TRACE_SCOPE(QSSG_synchronize, view3D, size, dpr);
647 Q_ASSERT(view3D !=
nullptr);
648 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
649 Q_ASSERT(rhiCtx !=
nullptr);
653 m_layer =
new QSSGRenderLayer();
655 bool newRenderStats =
false;
656 if (!m_renderStats) {
657 m_renderStats = view3D->renderStats();
658 newRenderStats =
true;
662 m_renderStats->startSync();
664 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DSynchronizeFrame);
666 m_sgContext->renderer()->setDpr(dpr);
667 bool layerSizeIsDirty = m_surfaceSize != size;
668 m_surfaceSize = size;
670 QQuick3DSceneEnvironment *environment = view3D->environment();
671 if (environment->lightmapper()) {
672 QQuick3DLightmapper *lightmapper = environment->lightmapper();
673 lmOptions.opacityThreshold = lightmapper->opacityThreshold();
674 lmOptions.bias = lightmapper->bias();
675 lmOptions.useAdaptiveBias = lightmapper->isAdaptiveBiasEnabled();
676 lmOptions.indirectLightEnabled = lightmapper->isIndirectLightEnabled();
677 lmOptions.indirectLightSamples = lightmapper->samples();
678 lmOptions.indirectLightWorkgroupSize = lightmapper->indirectLightWorkgroupSize();
679 lmOptions.indirectLightBounces = lightmapper->bounces();
680 lmOptions.indirectLightFactor = lightmapper->indirectLightFactor();
681 lmOptions.sigma = lightmapper->denoiseSigma();
682 lmOptions.texelsPerUnit = lightmapper->texelsPerUnit();
688 const QQmlContext *context = qmlContext(view3D);
689 const QUrl originalSource = environment->lightmapper() ? environment->lightmapper()->source()
690 : QUrl::fromLocalFile(QStringLiteral(
"lightmaps.bin"));
691 const auto resolvedUrl = context ? context->resolvedUrl(originalSource) : originalSource;
692 const auto qmlSource = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
693 const QString lightmapSource = qmlSource.isEmpty() ? originalSource.path() : qmlSource;
694 lmOptions.source = lightmapSource;
695 m_layer->lightmapSource = lightmapSource;
698 m_sgContext->bufferManager()->setLightmapSource(lightmapSource);
699 if (QQuick3DSceneManager *sceneManager = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager)
700 sceneManager->lightmapSource = lightmapSource;
704 QSet<QSSGRenderGraphObject *> resourceLoaders;
705 QQuick3DWindowAttachment::SyncResult requestSharedUpdate = QQuick3DWindowAttachment::SyncResultFlag::None;
706 if (
auto window = view3D->window()) {
707 if (!winAttacment || winAttacment->window() != window)
708 winAttacment = QQuick3DSceneManager::getOrSetWindowAttachment(*window);
710 if (winAttacment && winAttacment->rci() != m_sgContext)
711 winAttacment->setRci(m_sgContext);
713 QSSGRenderRoot *rootNode = winAttacment->rootNode();
714 if (m_layer->rootNode != rootNode) {
715 Q_ASSERT(m_layer->rootNode ==
nullptr);
716 rootNode->addChild(*m_layer);
717 rootNode->setStartVersion(m_layer->h.version());
718 m_layer->ref(rootNode);
722 requestSharedUpdate |= winAttacment->synchronize(resourceLoaders);
726 QQuick3DNode *importScene = view3D->importScene();
728 QQuick3DSceneManager *importSceneManager = QQuick3DObjectPrivate::get(importScene)->sceneManager;
731 if (
auto window = importSceneManager->window(); window && window != view3D->window()) {
732 if (
auto winAttacment = importSceneManager->wattached) {
734 auto rci = winAttacment->rci();
735 const bool inlineSync = (rci && rci->rhi() && (rci->rhi()->thread() == m_sgContext->rhi()->thread()));
739 winAttacment->synchronize(resourceLoaders);
740 }
else if (rci && !window->isExposed()) {
742 winAttacment->synchronize(resourceLoaders);
743 }
else if (!rci || (requestSharedUpdate & QQuick3DWindowAttachment::SyncResultFlag::SharedResourcesDirty)) {
748 winAttacment->requestUpdate();
761 m_layer->viewCount = rhiCtx->mainPassViewCount();
762 updateLayerNode(*m_layer, *view3D, resourceLoaders.values());
766 m_requestedFramesCount = 0;
767 if (m_layer->isProgressiveAAEnabled() || m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector) {
774 m_requestedFramesCount = (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector ? 45 :
775 int(m_layer->antialiasingQuality) + 1);
776 }
else if (m_layer->isTemporalAAEnabled()) {
781 m_requestedFramesCount = (m_aaIsDirty || m_temporalIsDirty) ? QSSGLayerRenderData::MAX_TEMPORAL_AA_LEVELS : 1;
786 for (QSSGRenderEffect *effectNode = m_layer->firstEffect; effectNode; effectNode = effectNode->m_nextEffect)
787 effectNode->finalizeShaders(*m_layer, m_sgContext.get());
790 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
791 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses))
792 userPass->finalizeShaders(*m_sgContext);
796 m_renderStats->setRhiContext(rhiCtx, m_layer);
798 static const auto getStageIndex = [](
const QSSGRenderExtension &ext) -> size_t {
799 const QSSGRenderExtension::RenderMode mode = ext.mode();
800 const QSSGRenderExtension::RenderStage stage = ext.stage();
803 if (mode == QSSGRenderExtension::RenderMode::Standalone)
804 return size_t(QSSGRenderLayer::RenderExtensionStage::TextureProviders);
807 case QSSGRenderExtension::RenderStage::PreColor:
808 return size_t(QSSGRenderLayer::RenderExtensionStage::Overlay);
809 case QSSGRenderExtension::RenderStage::PostColor:
810 return size_t(QSSGRenderLayer::RenderExtensionStage::Underlay);
813 Q_UNREACHABLE_RETURN(size_t(QSSGRenderLayer::RenderExtensionStage::Underlay));
819 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
820 const bool rebuildExtensionLists = (requestSharedUpdate & QQuick3DWindowAttachment::SyncResultFlag::ExtensionsDiry)
821 || view3D->extensionListDirty()
822 || sm->autoRegisteredExtensionsDirty;
827 if (rebuildExtensionLists) {
829 for (size_t i = 0; i != size_t(QSSGRenderLayer::RenderExtensionStage::Count); ++i)
830 m_layer->renderExtensions[i].clear();
833 const auto &extensions = view3D->extensionList();
834 for (
const auto &ext : extensions) {
835 const auto type = QQuick3DObjectPrivate::get(ext)->type;
836 if (QSSGRenderGraphObject::isExtension(type)) {
837 if (type == QSSGRenderGraphObject::Type::RenderExtension) {
838 if (
auto *renderExt = qobject_cast<QQuick3DRenderExtension *>(ext)) {
839 if (QSSGRenderExtension *ssgExt =
static_cast<QSSGRenderExtension *>(QQuick3DObjectPrivate::get(renderExt)->spatialNode)) {
840 const auto stage = getStageIndex(*ssgExt);
841 auto &list = m_layer->renderExtensions[size_t(stage)];
842 bfs(qobject_cast<QQuick3DRenderExtension *>(ext), list);
849 view3D->clearExtensionListDirty();
853 if (sm->autoRegisteredExtensionsDirty) {
854 for (QSSGRenderExtension *ae : std::as_const(sm->autoRegisteredExtensions))
855 m_layer->renderExtensions[getStageIndex(*ae)].push_back(ae);
856 sm->autoRegisteredExtensionsDirty =
false;
860 bool postProcessingNeeded = m_layer->firstEffect;
861 bool postProcessingWasActive = m_effectSystem;
862 QSSGRenderTextureFormat::Format effectOutputFormatOverride = QSSGRenderTextureFormat::Unknown;
863 if (postProcessingNeeded) {
864 QSSGRenderEffect *lastEffect = m_layer->firstEffect;
865 while (lastEffect->m_nextEffect)
866 lastEffect = lastEffect->m_nextEffect;
867 effectOutputFormatOverride = QSSGRhiEffectSystem::overriddenOutputFormat(lastEffect);
869 const auto layerTextureFormat = [effectOutputFormatOverride, view3D](QRhi *rhi,
bool postProc) {
870 if (effectOutputFormatOverride != QSSGRenderTextureFormat::Unknown)
871 return QSSGBufferManager::toRhiFormat(effectOutputFormatOverride);
886 const QRhiTexture::Format preferredPostProcFormat = QRhiTexture::RGBA16F;
887 if (postProc && rhi->isTextureFormatSupported(preferredPostProcFormat))
888 return preferredPostProcFormat;
890#if QT_CONFIG(quick_shadereffect)
891 const QRhiTexture::Format preferredView3DFormat = toRhiTextureFormat(view3D->renderFormat());
892 if (rhi->isTextureFormatSupported(preferredView3DFormat))
893 return preferredView3DFormat;
896 return QRhiTexture::RGBA8;
898 bool postProcessingStateDirty = postProcessingNeeded != postProcessingWasActive;
901 m_backgroundMode = QSSGRenderLayer::Background(view3D->environment()->backgroundMode());
905 QColor currentUserBackgroundColor = view3D->environment()->clearColor();
906 if (m_userBackgroundColor != currentUserBackgroundColor) {
907 m_userBackgroundColor = currentUserBackgroundColor;
908 m_linearBackgroundColor = QSSGUtils::color::sRGBToLinearColor(m_userBackgroundColor);
909 const QVector3D tc = tonemapRgb(QVector3D(m_linearBackgroundColor.redF(),
910 m_linearBackgroundColor.greenF(),
911 m_linearBackgroundColor.blueF()),
912 view3D->environment()->tonemapMode());
913 m_tonemappedBackgroundColor = QColor::fromRgbF(tc.x(), tc.y(), tc.z(), m_linearBackgroundColor.alphaF());
915 m_layer->scissorRect = QRect(view3D->environment()->scissorRect().topLeft() * dpr,
916 view3D->environment()->scissorRect().size() * dpr);
922 auto sceneRootNode =
static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(view3D->scene())->spatialNode);
923 if (sceneRootNode != m_sceneRootNode) {
925 removeNodeFromLayer(m_sceneRootNode);
928 addNodeToLayer(sceneRootNode);
930 m_sceneRootNode = sceneRootNode;
934 QSSGRenderNode *importSceneRootNode =
nullptr;
936 importSceneRootNode =
static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(importScene)->spatialNode);
938 if (importSceneRootNode != m_importSceneRootNode) {
939 if (m_importSceneRootNode)
940 m_layer->removeImportScene(*m_importSceneRootNode);
942 if (importSceneRootNode) {
946 QObject *sceneParent = importScene->parent();
947 bool isEmbedded =
false;
948 while (sceneParent) {
949 if (sceneParent == view3D) {
953 sceneParent = sceneParent->parent();
956 m_layer->setImportScene(*importSceneRootNode);
959 m_importSceneRootNode = importSceneRootNode;
967 QSSGRenderRoot *rootNode = winAttacment->rootNode();
968 if (rootNode->isDirty(QSSGRenderRoot::DirtyFlag::TreeDirty)) {
970 for (QSSGRenderNode &layer : rootNode->children) {
971 if (QSSG_GUARD_X(layer.type == QSSGRenderGraphObject::Type::Layer,
"Layer type mismatch"))
972 static_cast<QSSGRenderLayer &>(layer).markDirty(QSSGRenderLayer::DirtyFlag::TreeDirty);
977 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
978 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses)) {
979 if (
const auto *fo = sm->lookUpNode(userPass); fo && fo->parentItem()) {
980 const auto *pi = fo->parentItem();
981 if (
const QSSGRenderGraphObject *parentNode = QQuick3DObjectPrivate::get(pi)->spatialNode; parentNode && QSSGRenderGraphObject::isNodeType(parentNode->type))
982 userPass->setDependencyIndex(
static_cast<
const QSSGRenderNode *>(parentNode)->h.index());
984 userPass->setDependencyIndex(0);
991 maybeSetupLightmapBaking(view3D);
993 if (m_useFBO && rhiCtx->isValid()) {
994 QRhi *rhi = rhiCtx->rhi();
995 const QSize renderSize = m_layer->isSsaaEnabled() ? m_surfaceSize * m_layer->ssaaMultiplier : m_surfaceSize;
999 if (layerSizeIsDirty || postProcessingStateDirty) {
1000 m_texture->setPixelSize(m_surfaceSize);
1001 m_texture->setFormat(layerTextureFormat(rhi, postProcessingNeeded));
1002 m_texture->create();
1013 if (postProcessingStateDirty && (m_layer->antialiasingMode != QSSGRenderLayer::AAMode::NoAA || m_layer->isTemporalAAEnabled())) {
1014 releaseAaDependentRhiResources();
1016 if (m_ssaaTexture) {
1017 m_ssaaTexture->setPixelSize(renderSize);
1018 m_ssaaTexture->create();
1020 if (m_depthStencilBuffer) {
1021 m_depthStencilBuffer->setPixelSize(renderSize);
1022 m_depthStencilBuffer->create();
1024 if (m_multiViewDepthStencilBuffer) {
1025 m_multiViewDepthStencilBuffer->setPixelSize(renderSize);
1026 m_multiViewDepthStencilBuffer->create();
1028 if (m_msaaRenderBufferLegacy) {
1029 m_msaaRenderBufferLegacy->setPixelSize(renderSize);
1030 m_msaaRenderBufferLegacy->create();
1032 if (m_msaaRenderTexture) {
1033 m_msaaRenderTexture->setPixelSize(renderSize);
1034 m_msaaRenderTexture->create();
1036 if (m_msaaMultiViewRenderBuffer) {
1037 m_msaaMultiViewRenderBuffer->setPixelSize(renderSize);
1038 m_msaaMultiViewRenderBuffer->create();
1044 if (postProcessingStateDirty) {
1045 delete m_textureRenderPassDescriptor;
1046 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
1047 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
1049 m_textureRenderTarget->create();
1050 if (m_ssaaTextureToTextureRenderTarget)
1051 m_ssaaTextureToTextureRenderTarget->create();
1053 if (m_temporalAATexture) {
1054 m_temporalAATexture->setPixelSize(renderSize);
1055 m_temporalAATexture->create();
1057 if (m_prevTempAATexture) {
1058 m_prevTempAATexture->setPixelSize(renderSize);
1059 m_prevTempAATexture->create();
1061 if (m_temporalAARenderTarget)
1062 m_temporalAARenderTarget->create();
1065 }
else if (m_aaIsDirty && rhi->backend() == QRhi::Metal) {
1066 m_texture->create();
1070 releaseAaDependentRhiResources();
1073 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget
1074 | QRhiTexture::UsedAsTransferSource;
1075 const QRhiTexture::Format textureFormat = layerTextureFormat(rhi, postProcessingNeeded);
1078 if (m_layer->viewCount >= 2)
1079 m_texture = rhi->newTextureArray(textureFormat, m_layer->viewCount, m_surfaceSize, 1, textureFlags);
1081 m_texture = rhi->newTexture(textureFormat, m_surfaceSize, 1, textureFlags);
1082 m_texture->create();
1085 if (!m_ssaaTexture && m_layer->isSsaaEnabled()) {
1086 if (m_layer->viewCount >= 2)
1087 m_ssaaTexture = rhi->newTextureArray(textureFormat, m_layer->viewCount, renderSize, 1, textureFlags);
1089 m_ssaaTexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1090 m_ssaaTexture->create();
1093 if (m_timeBasedAA && !m_temporalAATexture) {
1094 m_temporalAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1095 m_temporalAATexture->create();
1096 m_prevTempAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1097 m_prevTempAATexture->create();
1101 if (m_aaIsDirty || layerSizeIsDirty)
1102 m_layer->tempAAPassIndex = m_layer->progAAPassIndex = 0;
1106 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::MSAA) {
1107 if (rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer)) {
1108 m_samples = qMax(1,
int(m_layer->antialiasingQuality));
1114 const QVector<
int> supported = rhi->supportedSampleCounts();
1115 if (!supported.contains(m_samples)) {
1116 if (!supported.isEmpty()) {
1117 auto it = std::lower_bound(supported.cbegin(), supported.cend(), m_samples);
1118 m_samples = it == supported.cend() ? supported.last() : *it;
1124 static bool warned =
false;
1127 qWarning(
"Multisample renderbuffers are not supported, disabling MSAA for Offscreen View3D");
1133 if (m_layer->viewCount >= 2) {
1134 if (!m_multiViewDepthStencilBuffer) {
1135 const auto format = rhi->isTextureFormatSupported(QRhiTexture::D24S8) ? QRhiTexture::D24S8 : QRhiTexture::D32FS8;
1136 m_multiViewDepthStencilBuffer = rhi->newTextureArray(format, m_layer->viewCount, renderSize,
1137 m_samples, QRhiTexture::RenderTarget);
1138 m_multiViewDepthStencilBuffer->create();
1141 if (!m_depthStencilBuffer) {
1142 m_depthStencilBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, renderSize, m_samples);
1143 m_depthStencilBuffer->create();
1147 if (!m_textureRenderTarget) {
1148 QRhiTextureRenderTargetDescription rtDesc;
1149 QRhiColorAttachment att;
1150 if (m_samples > 1) {
1151 if (m_layer->viewCount >= 2) {
1152 m_msaaMultiViewRenderBuffer = rhi->newTextureArray(textureFormat, m_layer->viewCount, renderSize, m_samples, QRhiTexture::RenderTarget);
1153 m_msaaMultiViewRenderBuffer->create();
1154 att.setTexture(m_msaaMultiViewRenderBuffer);
1156 if (!rhi->isFeatureSupported(QRhi::MultisampleTexture)) {
1158 m_msaaRenderBufferLegacy = rhi->newRenderBuffer(QRhiRenderBuffer::Color, renderSize, m_samples, {}, m_texture->format());
1159 m_msaaRenderBufferLegacy->create();
1160 att.setRenderBuffer(m_msaaRenderBufferLegacy);
1167 m_msaaRenderTexture = rhi->newTexture(textureFormat, renderSize, m_samples, QRhiTexture::RenderTarget);
1168 m_msaaRenderTexture->create();
1169 att.setTexture(m_msaaRenderTexture);
1172 att.setResolveTexture(m_texture);
1174 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA)
1175 att.setTexture(m_ssaaTexture);
1177 att.setTexture(m_texture);
1179 att.setMultiViewCount(m_layer->viewCount);
1180 rtDesc.setColorAttachments({ att });
1181 if (m_depthStencilBuffer)
1182 rtDesc.setDepthStencilBuffer(m_depthStencilBuffer);
1183 if (m_multiViewDepthStencilBuffer)
1184 rtDesc.setDepthTexture(m_multiViewDepthStencilBuffer);
1186 m_textureRenderTarget = rhi->newTextureRenderTarget(rtDesc);
1187 m_textureRenderTarget->setName(QByteArrayLiteral(
"View3D"));
1188 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
1189 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
1190 m_textureRenderTarget->create();
1193 if (!m_ssaaTextureToTextureRenderTarget && m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
1194 QRhiColorAttachment att(m_texture);
1195 att.setMultiViewCount(m_layer->viewCount);
1196 m_ssaaTextureToTextureRenderTarget = rhi->newTextureRenderTarget(QRhiTextureRenderTargetDescription({ att }));
1197 m_ssaaTextureToTextureRenderTarget->setName(QByteArrayLiteral(
"SSAA texture"));
1198 m_ssaaTextureToTextureRenderPassDescriptor = m_ssaaTextureToTextureRenderTarget->newCompatibleRenderPassDescriptor();
1199 m_ssaaTextureToTextureRenderTarget->setRenderPassDescriptor(m_ssaaTextureToTextureRenderPassDescriptor);
1200 m_ssaaTextureToTextureRenderTarget->create();
1203 if (m_layer->firstEffect) {
1204 if (!m_effectSystem)
1205 m_effectSystem =
new QSSGRhiEffectSystem(m_sgContext);
1206 m_effectSystem->setup(renderSize);
1207 }
else if (m_effectSystem) {
1208 delete m_effectSystem;
1209 m_effectSystem =
nullptr;
1212 if (m_timeBasedAA && !m_temporalAARenderTarget) {
1213 m_temporalAARenderTarget = rhi->newTextureRenderTarget({ m_temporalAATexture });
1214 m_temporalAARenderTarget->setName(QByteArrayLiteral(
"Temporal AA texture"));
1215 m_temporalAARenderPassDescriptor = m_temporalAARenderTarget->newCompatibleRenderPassDescriptor();
1216 m_temporalAARenderTarget->setRenderPassDescriptor(m_temporalAARenderPassDescriptor);
1217 m_temporalAARenderTarget->create();
1220 m_textureNeedsFlip = rhi->isYUpInFramebuffer();
1221 m_aaIsDirty =
false;
1225 m_renderStats->endSync(dumpRenderTimes());
1227 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DSynchronizeFrame, quint64(m_surfaceSize.width()) | quint64(m_surfaceSize.height()) << 32, profilingId);
1233 fboNode->invalidatePending =
true;
1238 if (m_layer && m_layer->renderData) {
1239 if (
const auto &mgr = m_layer->renderData->getShadowMapManager())
1240 mgr->releaseCachedResources();
1241 if (
const auto &mgr = m_layer->renderData->getReflectionMapManager())
1242 mgr->releaseCachedResources();
1248 if (!m_layer || !m_layer->renderData)
1249 return std::nullopt;
1251 QMutexLocker locker(&m_layer->renderedCamerasMutex);
1253 if (m_layer->renderedCameras.isEmpty())
1254 return std::nullopt;
1256 QMatrix4x4 globalTransform = m_layer->renderData->getGlobalTransform(*m_layer->renderedCameras[0]);
1258 const QVector2D viewportSize(m_surfaceSize.width(), m_surfaceSize.height());
1259 const QVector2D position(
float(pos.x()),
float(pos.y()));
1260 const QRectF viewportRect(QPointF{}, QSizeF(m_surfaceSize));
1264 QVector2D correctCoords(position.x(), viewportSize.y() - position.y());
1265 QVector2D theLocalMouse = QSSGUtils::rect::toRectRelative(viewportRect, correctCoords);
1266 if ((theLocalMouse.x() < 0.0f || theLocalMouse.x() >= viewportSize.x() || theLocalMouse.y() < 0.0f
1267 || theLocalMouse.y() >= viewportSize.y()))
1268 return std::nullopt;
1270 return m_layer->renderedCameras[0]->unproject(globalTransform, theLocalMouse, viewportRect);
1273std::optional<QSSGRenderPickResult>
QQuick3DSceneRenderer::syncPickClosestPoint(
const QVector3D ¢er,
float radiusSquared, QSSGRenderNode *node)
1276 return std::nullopt;
1278 return QSSGRendererPrivate::syncPickClosestPoint(*m_sgContext,
1280 center, radiusSquared,
1287 return QQuick3DSceneRenderer::PickResultList();
1289 return QSSGRendererPrivate::syncPick(*m_sgContext,
1297 return QQuick3DSceneRenderer::PickResultList();
1299 return QSSGRendererPrivate::syncPick(*m_sgContext,
1306 QVarLengthArray<QSSGRenderNode *> subset)
1309 return QQuick3DSceneRenderer::PickResultList();
1311 return QSSGRendererPrivate::syncPickSubset(*m_layer,
1312 *m_sgContext->bufferManager(),
1320 return QQuick3DSceneRenderer::PickResultList();
1322 return QSSGRendererPrivate::syncPickAll(*m_sgContext,
1332 return QSSGRendererPrivate::syncPickInFrustum(*m_sgContext, *m_layer, frustum);
1337 QSSGRendererPrivate::setGlobalPickingEnabled(*m_sgContext->renderer(), isEnabled);
1342 return m_renderStats;
1345void QQuick3DRenderLayerHelpers::updateLayerNodeHelper(
const QQuick3DViewport &view3D,
1346 const std::shared_ptr<QSSGRenderContextInterface>& rci,
1347 QSSGRenderLayer &layerNode,
1349 bool &temporalIsDirty)
1351 QList<QSSGRenderGraphObject *> resourceLoaders;
1353 QQuick3DSceneRenderer dummyRenderer(rci);
1356 dummyRenderer.updateLayerNode(layerNode, view3D, resourceLoaders);
1358 aaIsDirty = dummyRenderer.m_aaIsDirty;
1359 temporalIsDirty = dummyRenderer.m_temporalIsDirty;
1363 const QQuick3DViewport &view3D,
1364 const QList<QSSGRenderGraphObject *> &resourceLoaders)
1366 QQuick3DSceneEnvironment *environment = view3D.environment();
1367 const auto &effects = environment->effectList();
1369 QSSGRenderLayer::AAMode aaMode = QSSGRenderLayer::AAMode(environment->antialiasingMode());
1370 if (aaMode != layerNode.antialiasingMode) {
1371 layerNode.antialiasingMode = aaMode;
1372 layerNode.progAAPassIndex = 0;
1375 QSSGRenderLayer::AAQuality aaQuality = QSSGRenderLayer::AAQuality(environment->antialiasingQuality());
1376 if (aaQuality != layerNode.antialiasingQuality) {
1377 layerNode.antialiasingQuality = aaQuality;
1378 layerNode.ssaaMultiplier = QSSGRenderLayer::ssaaMultiplierForQuality(aaQuality);
1383 const bool temporalAARequested = environment->temporalAAEnabled();
1384 const bool wasTaaEnabled = layerNode.isTemporalAAEnabled();
1385 layerNode.temporalAAMode = temporalAARequested ? QSSGRenderLayer::TAAMode(environment->m_temporalAAMode + 1)
1386 : QSSGRenderLayer::TAAMode::Off;
1389 if (wasTaaEnabled != layerNode.isTemporalAAEnabled()) {
1390 layerNode.tempAAPassIndex = 0;
1392 m_temporalIsDirty =
true;
1395 layerNode.temporalAAStrength = environment->temporalAAStrength();
1397 layerNode.specularAAEnabled = environment->specularAAEnabled();
1399 layerNode.background = QSSGRenderLayer::Background(environment->backgroundMode());
1400 layerNode.clearColor = QVector3D(
float(environment->clearColor().redF()),
1401 float(environment->clearColor().greenF()),
1402 float(environment->clearColor().blueF()));
1404 layerNode.gridEnabled = environment->gridEnabled();
1405 layerNode.gridScale = environment->gridScale();
1406 layerNode.gridFlags = environment->gridFlags();
1408 layerNode.aoStrength = environment->aoStrength();
1409 layerNode.aoDistance = environment->aoDistance();
1410 layerNode.aoSoftness = environment->aoSoftness();
1411 layerNode.aoEnabled = environment->aoEnabled();
1412 layerNode.aoBias = environment->aoBias();
1413 layerNode.aoSamplerate = environment->aoSampleRate();
1414 layerNode.aoDither = environment->aoDither();
1417 if (environment->lightProbe())
1418 layerNode.lightProbe = environment->lightProbe()->getRenderImage();
1420 layerNode.lightProbe =
nullptr;
1421 if (view3D.environment()->skyBoxCubeMap())
1422 layerNode.skyBoxCubeMap = view3D.environment()->skyBoxCubeMap()->getRenderImage();
1424 layerNode.skyBoxCubeMap =
nullptr;
1426 layerNode.lightProbeSettings.probeExposure = environment->probeExposure();
1428 layerNode.lightProbeSettings.probeHorizon = qMin(environment->probeHorizon() - 1.0f, -0.001f);
1429 layerNode.setProbeOrientation(environment->probeOrientation());
1431 QQuick3DViewport::updateCameraForLayer(view3D, layerNode);
1433 layerNode.layerFlags.setFlag(QSSGRenderLayer::LayerFlag::EnableDepthTest, environment->depthTestEnabled());
1434 layerNode.layerFlags.setFlag(QSSGRenderLayer::LayerFlag::EnableDepthPrePass, environment->depthPrePassEnabled());
1436 layerNode.tonemapMode = QQuick3DSceneRenderer::getTonemapMode(*environment);
1437 layerNode.skyboxBlurAmount = environment->skyboxBlurAmount();
1438 if (
auto debugSettings = view3D.environment()->debugSettings()) {
1439 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode(debugSettings->materialOverride());
1440 layerNode.wireframeMode = debugSettings->wireframeEnabled();
1441 layerNode.drawDirectionalLightShadowBoxes = debugSettings->drawDirectionalLightShadowBoxes();
1442 layerNode.drawPointLightShadowBoxes = debugSettings->drawPointLightShadowBoxes();
1443 layerNode.drawShadowCastingBounds = debugSettings->drawShadowCastingBounds();
1444 layerNode.drawShadowReceivingBounds = debugSettings->drawShadowReceivingBounds();
1445 layerNode.drawCascades = debugSettings->drawCascades();
1446 layerNode.drawSceneCascadeIntersection = debugSettings->drawSceneCascadeIntersection();
1447 layerNode.disableShadowCameraUpdate = debugSettings->disableShadowCameraUpdate();
1448 layerNode.drawCulledObjects = debugSettings->drawCulledObjects();
1450 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode::None;
1451 layerNode.wireframeMode =
false;
1454 if (environment->fog() && environment->fog()->isEnabled()) {
1455 layerNode.fog.enabled =
true;
1456 const QQuick3DFog *fog = environment->fog();
1457 layerNode.fog.color = QSSGUtils::color::sRGBToLinear(fog->color()).toVector3D();
1458 layerNode.fog.density = fog->density();
1459 layerNode.fog.depthEnabled = fog->isDepthEnabled();
1460 layerNode.fog.depthBegin = fog->depthNear();
1461 layerNode.fog.depthEnd = fog->depthFar();
1462 layerNode.fog.depthCurve = fog->depthCurve();
1463 layerNode.fog.heightEnabled = fog->isHeightEnabled();
1464 layerNode.fog.heightMin = fog->leastIntenseY();
1465 layerNode.fog.heightMax = fog->mostIntenseY();
1466 layerNode.fog.heightCurve = fog->heightCurve();
1467 layerNode.fog.transmitEnabled = fog->isTransmitEnabled();
1468 layerNode.fog.transmitCurve = fog->transmitCurve();
1470 layerNode.fog.enabled =
false;
1472 const auto method =
static_cast<QSSGRenderLayer::OITMethod>(environment->oitMethod());
1473 layerNode.oitMethodDirty = method != layerNode.oitMethod;
1474 layerNode.oitMethod = method;
1479 layerNode.firstEffect =
nullptr;
1480 auto rit = effects.crbegin();
1481 const auto rend = effects.crend();
1482 for (; rit != rend; ++rit) {
1483 QQuick3DObjectPrivate *p = QQuick3DObjectPrivate::get(*rit);
1484 QSSGRenderEffect *effectNode =
static_cast<QSSGRenderEffect *>(p->spatialNode);
1486 if (layerNode.hasEffect(effectNode)) {
1487 qWarning() <<
"Duplicate effect found, skipping!";
1489 effectNode->className = (*rit)->metaObject()->className();
1490 layerNode.addEffect(*effectNode);
1495 const bool hasEffects = (layerNode.firstEffect !=
nullptr);
1497 const auto renderMode = view3D.renderMode();
1499 const bool progressiveAA = layerNode.isProgressiveAAEnabled();
1500 const bool temporalAA = layerNode.isTemporalAAEnabled();
1501 const bool superSamplingAA = layerNode.isSsaaEnabled();
1502 m_timeBasedAA = progressiveAA || temporalAA;
1503 m_postProcessingStack = hasEffects || m_timeBasedAA || superSamplingAA;
1504 m_useFBO = renderMode == QQuick3DViewport::RenderMode::Offscreen ||
1505 ((renderMode == QQuick3DViewport::RenderMode::Underlay || renderMode == QQuick3DViewport::RenderMode::Overlay)
1506 && m_postProcessingStack);
1515 if (m_useFBO && (layerNode.viewCount > 1) && !view3D.isXrViewInstance())
1516 layerNode.viewCount = 1;
1519 layerNode.resourceLoaders.clear();
1520 layerNode.resourceLoaders = resourceLoaders;
1522 layerNode.renderOverrides = QSSGRenderLayer::RenderOverridesT(view3D.renderOverrides().toInt());
1530 m_layer->removeChild(*node);
1535 if (m_layer->renderData && m_layer->renderData->lightmapBaker)
1540 bool bakeRequested =
false;
1541 bool denoiseRequested =
false;
1542 bool fromCmd =
false;
1543 QQuick3DLightmapBaker *lightmapBaker = view3D->maybeLightmapBaker();
1544 if (lightmapBaker && (lightmapBaker->m_bakingRequested || lightmapBaker->m_denoisingRequested)) {
1545 bakeRequested = std::exchange(lightmapBaker->m_bakingRequested,
false);
1546 denoiseRequested = std::exchange(lightmapBaker->m_denoisingRequested,
false);
1548 bakeRequested = m_lightmapBakingFromCmdRequested;
1549 denoiseRequested = m_lightmapDenoisingFromCmdRequested;
1550 fromCmd = bakeRequested;
1554 if (bakeRequested || denoiseRequested) {
1555 QSSGLightmapBaker::Context ctx;
1556 ctx.settings.bakeRequested = bakeRequested;
1557 ctx.settings.denoiseRequested = denoiseRequested;
1558 ctx.settings.quitWhenFinished = fromCmd;
1561 if (lightmapBaker) {
1562 QQuick3DLightmapBaker::Callback qq3dCallback = lightmapBaker->m_callback;
1563 QQuick3DLightmapBaker::BakingControl *qq3dBakingControl = lightmapBaker->m_bakingControl;
1564 QSSGLightmapper::Callback callback =
1566 qq3dBakingControl](
const QVariantMap &payload,
1567 QSSGLightmapper::BakingControl *qssgBakingControl) {
1568 qq3dCallback(payload, qq3dBakingControl);
1570 if (qq3dBakingControl->isCancelled() && !qssgBakingControl->cancelled)
1571 qssgBakingControl->cancelled =
true;
1573 ctx.callbacks.lightmapBakingOutput = callback;
1577 ctx.callbacks.triggerNewFrame = [view3D](
bool releaseResources) {
1578 if (releaseResources) {
1579 QMetaObject::invokeMethod(view3D->window(),
1580 &QQuickWindow::releaseResources,
1581 Qt::QueuedConnection);
1583 QMetaObject::invokeMethod(view3D, &QQuick3DViewport::update, Qt::QueuedConnection);
1585 ctx.callbacks.setCurrentlyBaking = [
this](
bool value) {
1586 m_sgContext->bufferManager()->setCurrentlyLightmapBaking(value);
1589 ctx.env.rhiCtx = m_sgContext->rhiContext().get();
1590 ctx.env.renderer = m_sgContext->renderer().get();
1591 ctx.env.lmOptions = lmOptions;
1592 m_layer->renderData->initializeLightmapBaking(ctx);
1596 static bool flagsChecked =
false;
1599 flagsChecked =
true;
1601 auto isLightmapFlagSet = [](
const QString &flag,
const char *envVar) {
1602 return QCoreApplication::arguments().contains(flag)
1603 || qEnvironmentVariableIntValue(envVar);
1606 m_lightmapBakingFromCmdRequested = isLightmapFlagSet(QStringLiteral(
"--bake-lightmaps"),
"QT_QUICK3D_BAKE_LIGHTMAPS");
1607 m_lightmapDenoisingFromCmdRequested = isLightmapFlagSet(QStringLiteral(
"--denoise-lightmaps"),
"QT_QUICK3D_DENOISE_LIGHTMAPS");
1609 if (m_lightmapBakingFromCmdRequested || m_lightmapDenoisingFromCmdRequested) {
1611 QMetaObject::invokeMethod(view3D, &QQuick3DViewport::update, Qt::QueuedConnection);
1621 m_layer->addChild(*node);
1626 return BlendState | StencilState | DepthState | ScissorState | ColorState | CullState | ViewportState | RenderTargetState;
1630inline QRect convertQtRectToGLViewport(
const QRectF &rect,
const QSize surfaceSize)
1632 const int x =
int(rect.x());
1633 const int y = surfaceSize.height() - (
int(rect.y()) +
int(rect.height()));
1634 const int width =
int(rect.width());
1635 const int height =
int(rect.height());
1636 return QRect(x, y, width, height);
1639inline void queryMainRenderPassDescriptorAndCommandBuffer(QQuickWindow *window, QSSGRhiContext *rhiCtx)
1641 if (rhiCtx->isValid()) {
1642 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
1647 int sampleCount = 1;
1649 QRhiSwapChain *swapchain = window->swapChain();
1651 rhiCtxD->setMainRenderPassDescriptor(swapchain->renderPassDescriptor());
1652 rhiCtxD->setCommandBuffer(swapchain->currentFrameCommandBuffer());
1653 rhiCtxD->setRenderTarget(swapchain->currentFrameRenderTarget());
1654 sampleCount = swapchain->sampleCount();
1656 QSGRendererInterface *rif = window->rendererInterface();
1658 QRhiCommandBuffer *cb =
static_cast<QRhiCommandBuffer *>(
1659 rif->getResource(window, QSGRendererInterface::RhiRedirectCommandBuffer));
1660 QRhiTextureRenderTarget *rt =
static_cast<QRhiTextureRenderTarget *>(
1661 rif->getResource(window, QSGRendererInterface::RhiRedirectRenderTarget));
1663 rhiCtxD->setMainRenderPassDescriptor(rt->renderPassDescriptor());
1664 rhiCtxD->setCommandBuffer(cb);
1665 rhiCtxD->setRenderTarget(rt);
1666 const auto descr = rt->description();
1667 const QRhiColorAttachment *color0 = descr.cbeginColorAttachments();
1668 if (color0 && color0->texture()) {
1669 sampleCount = color0->texture()->sampleCount();
1670 if (rt->resourceType() == QRhiResource::TextureRenderTarget) {
1671 const QRhiTextureRenderTargetDescription desc =
static_cast<QRhiTextureRenderTarget *>(rt)->description();
1672 for (
auto it = desc.cbeginColorAttachments(), end = desc.cendColorAttachments(); it != end; ++it) {
1673 if (it->multiViewCount() >= 2) {
1674 viewCount = it->multiViewCount();
1681 qWarning(
"Neither swapchain nor redirected command buffer and render target are available.");
1690 rhiCtxD->setMainPassSampleCount(sampleCount);
1698 rhiCtxD->setMainPassViewCount(viewCount);
1704inline void queryInlineRenderPassDescriptorAndCommandBuffer(QSGRenderNode *node, QSSGRhiContext *rhiCtx)
1706 QSGRenderNodePrivate *d = QSGRenderNodePrivate::get(node);
1707 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
1708 rhiCtxD->setMainRenderPassDescriptor(d->m_rt.rpDesc);
1709 rhiCtxD->setCommandBuffer(d->m_rt.cb);
1710 rhiCtxD->setRenderTarget(d->m_rt.rt);
1711 rhiCtxD->setMainPassSampleCount(d->m_rt.rt->sampleCount());
1712 rhiCtxD->setMainPassViewCount(1);
1726 if (!
renderer->m_sgContext->rhiContext()->isValid())
1728 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1730 renderer->renderStats()->startRenderPrepare();
1732 queryInlineRenderPassDescriptorAndCommandBuffer(
this,
renderer->m_sgContext->rhiContext().get());
1734 qreal dpr = window->effectiveDevicePixelRatio();
1735 const QSizeF itemSize =
renderer->surfaceSize() / dpr;
1736 QRectF viewport = matrix()->mapRect(QRectF(QPoint(0, 0), itemSize));
1737 viewport = QRectF(viewport.topLeft() * dpr, viewport.size() * dpr);
1738 const QRect vp = convertQtRectToGLViewport(viewport, window->size() * dpr);
1740 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1744 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32,
renderer->profilingId);
1746 renderer->renderStats()->endRenderPrepare();
1749void QQuick3DSGRenderNode::
render(
const QSGRenderNode::RenderState *state)
1753 const auto &rhiContext =
renderer->m_sgContext->rhiContext();
1755 if (rhiContext->isValid()) {
1757 renderer->renderStats()->startRender();
1758 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1759 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1761 queryInlineRenderPassDescriptorAndCommandBuffer(
this,
renderer->m_sgContext->rhiContext().get());
1764 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1765 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiContext)),
renderer->profilingId);
1779 return NoExternalRendering;
1783 : m_renderer(renderer)
1786 if (QSGRendererInterface::isApiRhiBased(window->rendererInterface()->graphicsApi())) {
1787 connect(window, &QQuickWindow::beforeRendering,
this, &QQuick3DSGDirectRenderer::prepare, Qt::DirectConnection);
1788 if (mode == Underlay)
1789 connect(window, &QQuickWindow::beforeRenderPassRecording,
this, &
QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1791 connect(window, &QQuickWindow::afterRenderPassRecording,
this, &
QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1802 m_viewport = viewport;
1807 if (m_isVisible == visible)
1809 m_isVisible = visible;
1815 renderPending =
true;
1816 requestFullUpdate(m_window);
1826 if (m_renderer->m_sgContext->rhiContext()->isValid())
1827 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1832 if (!m_isVisible || !m_renderer)
1835 if (m_renderer->m_sgContext->rhiContext()->isValid()) {
1837 if (m_renderer->m_postProcessingStack) {
1838 if (renderPending) {
1839 renderPending =
false;
1840 m_rhiTexture = m_renderer->renderToRhiTexture(m_window);
1843 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1844 const auto &quadRenderer = m_renderer->m_sgContext->renderer()->rhiQuadRenderer();
1845 quadRenderer->prepareQuad(m_renderer->m_sgContext->rhiContext().get(),
nullptr);
1846 if (m_renderer->m_requestedFramesCount > 0) {
1848 m_renderer->m_requestedFramesCount--;
1854 QQuick3DRenderStats *renderStats = m_renderer->renderStats();
1856 renderStats->startRenderPrepare();
1858 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1859 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1860 const QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->effectiveDevicePixelRatio());
1862 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1864 m_renderer->rhiPrepare(vp, m_window->effectiveDevicePixelRatio());
1865 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32, m_renderer->profilingId);
1868 renderStats->endRenderPrepare();
1875 if (!m_isVisible || !m_renderer)
1878 const auto &rhiContext = m_renderer->m_sgContext->rhiContext();
1880 if (rhiContext->isValid()) {
1891 if (m_renderer->m_postProcessingStack) {
1893 queryMainRenderPassDescriptorAndCommandBuffer(m_window, rhiContext.get());
1894 auto rhiCtx = m_renderer->m_sgContext->rhiContext().get();
1895 const auto &renderer = m_renderer->m_sgContext->renderer();
1896 QRhiCommandBuffer *cb = rhiContext->commandBuffer();
1897 cb->debugMarkBegin(QByteArrayLiteral(
"Post-processing result to main rt"));
1904 QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->effectiveDevicePixelRatio());
1906 const auto &shaderCache = m_renderer->m_sgContext->shaderCache();
1907 const auto &shaderPipeline = shaderCache->getBuiltInRhiShaders().getRhiSimpleQuadShader(m_renderer->m_layer->viewCount);
1909 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
1910 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge });
1911 QSSGRhiShaderResourceBindingList bindings;
1912 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, m_rhiTexture, sampler);
1913 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiContext.get());
1914 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
1916 QSSGRhiGraphicsPipelineState ps;
1917 ps.viewport = QRhiViewport(
float(vp.x()),
float(vp.y()),
float(vp.width()),
float(vp.height()));
1918 ps.samples = rhiCtx->mainPassSampleCount();
1919 ps.viewCount = m_renderer->m_layer->viewCount;
1920 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
1921 renderer->rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, rhiCtx->mainRenderPassDescriptor(), QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::PremulBlend);
1927 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1928 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1929 if (m_renderer->renderStats())
1930 m_renderer->renderStats()->startRender();
1932 queryMainRenderPassDescriptorAndCommandBuffer(m_window, rhiContext.get());
1936 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1937 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiContext)),
1938 m_renderer->profilingId);
1941 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)