306 QRhiTexture *currentTexture = m_texture;
310 m_renderStats->startRenderPrepare();
312 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
314 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
315 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
317 rhiCtxD->setMainRenderPassDescriptor(m_textureRenderPassDescriptor);
318 rhiCtxD->setRenderTarget(m_textureRenderTarget);
320 QRhiCommandBuffer *cb =
nullptr;
321 QRhiSwapChain *swapchain = qw->swapChain();
323 cb = swapchain->currentFrameCommandBuffer();
324 rhiCtxD->setCommandBuffer(cb);
326 QSGRendererInterface *rif = qw->rendererInterface();
327 cb =
static_cast<QRhiCommandBuffer *>(
328 rif->getResource(qw, QSGRendererInterface::RhiRedirectCommandBuffer));
330 rhiCtxD->setCommandBuffer(cb);
332 qWarning(
"Neither swapchain nor redirected command buffer are available.");
333 return currentTexture;
339 rhiCtxD->setMainPassSampleCount(m_msaaRenderBufferLegacy ? m_msaaRenderBufferLegacy->sampleCount() :
340 (m_msaaRenderTexture ? m_msaaRenderTexture->sampleCount() :
341 (m_msaaMultiViewRenderBuffer ? m_msaaMultiViewRenderBuffer->sampleCount() : 1)));
345 int ssaaAdjustedWidth = m_surfaceSize.width();
346 int ssaaAdjustedHeight = m_surfaceSize.height();
347 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
348 ssaaAdjustedWidth *= m_layer->ssaaMultiplier;
349 ssaaAdjustedHeight *= m_layer->ssaaMultiplier;
352 Q_TRACE(QSSG_prepareFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
354 float dpr = m_sgContext->renderer()->dpr();
355 const QRect vp = QRect(0, 0, ssaaAdjustedWidth, ssaaAdjustedHeight);
360 m_renderStats->endRenderPrepare();
362 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, profilingId);
364 Q_TRACE(QSSG_prepareFrame_exit);
366 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
367 Q_TRACE(QSSG_renderFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
369 m_renderStats->startRender();
371 QColor clearColor = Qt::transparent;
372 if (m_backgroundMode == QSSGRenderLayer::Background::Color
373 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBoxCubeMap && !m_layer->skyBoxCubeMap)
374 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBox && !m_layer->lightProbe)
375 || (m_backgroundMode == QSSGRenderLayer::Background::SkyMaterial && !m_layer->skyMaterial)) {
378 clearColor = m_layer->firstEffect ? m_linearBackgroundColor : m_tonemappedBackgroundColor;
383 cb->beginPass(m_textureRenderTarget, clearColor, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
384 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
385 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(m_textureRenderTarget));
388 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
389 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, QByteArrayLiteral(
"main"));
391 const bool temporalAA = m_layer->temporalAAIsActive;
392 const bool progressiveAA = m_layer->progressiveAAIsActive;
393 const bool superSamplingAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA;
394 QRhi *rhi = rhiCtx->rhi();
396 currentTexture = superSamplingAA ? m_ssaaTexture : m_texture;
399 if (m_effectSystem && m_layer->firstEffect && !m_layer->renderedCameras.isEmpty()) {
400 const auto &renderer = m_sgContext->renderer();
402 Q_ASSERT(theRenderData);
403 QRhiTexture *theDepthTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::DepthTexture)->texture;
404 QRhiTexture *theNormalTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::NormalTexture)->texture;
405 QRhiTexture *theMotionVectorTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::MotionVectorTexture)->texture;
407 currentTexture = m_effectSystem->process(*m_layer,
411 theMotionVectorTexture);
414 if ((progressiveAA || temporalAA) && m_prevTempAATexture) {
415 cb->debugMarkBegin(QByteArrayLiteral(
"Temporal AA"));
416 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
417 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"Temporal AA"));
418 QRhiTexture *blendResult;
419 uint *aaIndex = progressiveAA ? &m_layer->progAAPassIndex : &m_layer->tempAAPassIndex;
422 if ((temporalAA && m_layer->temporalAAMode != QSSGRenderLayer::TAAMode::MotionVector) ||
424 (temporalAA && m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector ?
425 quint32(QSSGLayerRenderData::MAX_AA_LEVELS) :
426 quint32(m_layer->antialiasingQuality))) {
427 const auto &renderer = m_sgContext->renderer();
429 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
430 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ m_layer,
nullptr,
nullptr, 0 }));
431 QRhiBuffer *&ubuf = dcd.ubuf;
432 const int ubufSize = 4 *
sizeof(
float);
434 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
437 int idx = *aaIndex - 1;
439 const QSize textureSize = m_prevTempAATexture->pixelSize();
440 QVector4D bufferData;
442 bufferData = QVector4D(s_ProgressiveAABlendFactors[idx]);
443 else if (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::Default)
444 bufferData = QVector4D(s_TemporalAABlendFactors);
446 bufferData = QVector4D(1.0f / qMax(textureSize.width(), 1), 1.0f / qMax(textureSize.height(), 1),
447 0.9f + (qMin(qMax(m_layer->temporalAAStrength, 0.3f), 1.0f) - 0.3f) / 0.7f * 0.09f, 0.0f);
449 rub->updateDynamicBuffer(ubuf, 0, 4 *
sizeof(
float), &bufferData);
450 QSSGRhiGraphicsPipelineState ps;
451 ps.viewport = QRhiViewport(0, 0,
float(textureSize.width()),
float(textureSize.height()));
453 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
454 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
455 QSSGRhiShaderResourceBindingList bindings;
456 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
457 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
458 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, m_prevTempAATexture, sampler);
459 if (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector) {
461 Q_ASSERT(theRenderData);
462 QRhiTexture *theDepthTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::DepthTexture)->texture;
463 QRhiTexture *theMotionVectorTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::MotionVectorTexture)->texture;
464 bindings.addTexture(3, QRhiShaderResourceBinding::FragmentStage, theDepthTexture, sampler);
465 bindings.addTexture(4, QRhiShaderResourceBinding::FragmentStage, theMotionVectorTexture, sampler);
466 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiTemporalAAShader().get());
471 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiProgressiveAAShader().get());
474 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
475 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx, rub);
476 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_temporalAARenderTarget, QSSGRhiQuadRenderer::UvCoords);
477 blendResult = m_temporalAATexture;
479 blendResult = m_prevTempAATexture;
483 blendResult = currentTexture;
486 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
488 const bool isMotionVector = m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector;
489 const quint32 aaLimit = (temporalAA && isMotionVector) ? quint32(QSSGLayerRenderData::MAX_AA_LEVELS) : quint32(m_layer->antialiasingQuality);
491 const bool aaActive = (temporalAA && !isMotionVector) || (*aaIndex < aaLimit);
492 const bool usePrevTexture = m_prevTempAATexture !=
nullptr;
494 if (aaActive && usePrevTexture) {
495 QRhiTexture *copySource = (blendResult && (progressiveAA || isMotionVector)) ? blendResult : currentTexture;
498 auto *rub = rhi->nextResourceUpdateBatch();
499 rub->copyTexture(m_prevTempAATexture, copySource);
500 cb->resourceUpdate(rub);
506 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"temporal_aa"));
508 currentTexture = blendResult;
511 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
521 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
522 const auto &renderer = m_sgContext->renderer();
524 cb->debugMarkBegin(QByteArrayLiteral(
"SSAA downsample"));
525 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
527 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"SSAA downsample"));
529 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
536 const auto &shaderPipeline = m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiSupersampleResolveShader(m_layer->viewCount);
538 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
539 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
540 QSSGRhiShaderResourceBindingList bindings;
541 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
542 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
544 QSSGRhiGraphicsPipelineState ps;
545 ps.viewport = QRhiViewport(0, 0,
float(m_surfaceSize.width()),
float(m_surfaceSize.height()));
546 ps.viewCount = m_layer->viewCount;
547 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
549 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_ssaaTextureToTextureRenderTarget, QSSGRhiQuadRenderer::UvCoords);
551 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"ssaa_downsample"));
553 currentTexture = m_texture;
556 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
557 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiCtx)),
561 m_renderStats->endRender(dumpRenderTimes());
562 Q_TRACE(QSSG_renderFrame_exit);
565 if (m_layer && m_layer->skyMaterial && m_layer->skyMaterial->wantsMoreFrames)
566 ++m_requestedFramesCount;
568 return currentTexture;
650 Q_TRACE_SCOPE(QSSG_synchronize, view3D, size, dpr);
652 Q_ASSERT(view3D !=
nullptr);
653 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
654 Q_ASSERT(rhiCtx !=
nullptr);
658 m_layer =
new QSSGRenderLayer();
660 bool newRenderStats =
false;
661 if (!m_renderStats) {
662 m_renderStats = view3D->renderStats();
663 newRenderStats =
true;
667 m_renderStats->startSync();
669 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DSynchronizeFrame);
671 m_sgContext->renderer()->setDpr(dpr);
672 bool layerSizeIsDirty = m_surfaceSize != size;
673 m_surfaceSize = size;
675 QQuick3DSceneEnvironment *environment = view3D->environment();
676 if (environment->lightmapper()) {
677 QQuick3DLightmapper *lightmapper = environment->lightmapper();
678 lmOptions.opacityThreshold = lightmapper->opacityThreshold();
679 lmOptions.bias = lightmapper->bias();
680 lmOptions.useAdaptiveBias = lightmapper->isAdaptiveBiasEnabled();
681 lmOptions.indirectLightEnabled = lightmapper->isIndirectLightEnabled();
682 lmOptions.indirectLightSamples = lightmapper->samples();
683 lmOptions.indirectLightWorkgroupSize = lightmapper->indirectLightWorkgroupSize();
684 lmOptions.indirectLightBounces = lightmapper->bounces();
685 lmOptions.indirectLightFactor = lightmapper->indirectLightFactor();
686 lmOptions.sigma = lightmapper->denoiseSigma();
687 lmOptions.texelsPerUnit = lightmapper->texelsPerUnit();
693 if (environment->m_dirtyFlags & QQuick3DSceneEnvironment::InternalDirtyFlag::LightmapperDirty) {
694 environment->m_dirtyFlags &= ~QQuick3DSceneEnvironment::InternalDirtyFlag::LightmapperDirty;
696 const QQmlContext *context = qmlContext(view3D);
697 const QUrl originalSource = environment->lightmapper() ? environment->lightmapper()->source()
698 : QUrl::fromLocalFile(QStringLiteral(
"lightmaps.bin"));
699 const auto resolvedUrl = context ? context->resolvedUrl(originalSource) : originalSource;
700 const auto qmlSource = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
701 const QString lightmapSource = qmlSource.isEmpty() ? originalSource.path() : qmlSource;
702 lmOptions.source = lightmapSource;
703 m_layer->lightmapSource = lightmapSource;
706 m_sgContext->bufferManager()->setLightmapSource(m_layer->lightmapSource);
707 if (QQuick3DSceneManager *sceneManager = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager)
708 sceneManager->lightmapSourceTracker = { m_layer->lightmapSource,
true };
712 QSet<QSSGRenderGraphObject *> resourceLoaders;
713 QQuick3DWindowAttachment::SyncResult requestSharedUpdate = QQuick3DWindowAttachment::SyncResultFlag::None;
714 if (
auto window = view3D->window()) {
715 if (!winAttacment || winAttacment->window() != window)
716 winAttacment = QQuick3DSceneManager::getOrSetWindowAttachment(*window);
718 if (winAttacment && winAttacment->rci() != m_sgContext)
719 winAttacment->setRci(m_sgContext);
721 QSSGRenderRoot *rootNode = winAttacment->rootNode();
722 if (m_layer->rootNode != rootNode) {
723 Q_ASSERT(m_layer->rootNode ==
nullptr);
724 rootNode->addChild(*m_layer);
725 rootNode->setStartVersion(m_layer->h.version());
726 m_layer->ref(rootNode);
730 requestSharedUpdate |= winAttacment->synchronize(resourceLoaders);
734 QQuick3DNode *importScene = view3D->importScene();
736 QQuick3DSceneManager *importSceneManager = QQuick3DObjectPrivate::get(importScene)->sceneManager;
739 if (
auto window = importSceneManager->window(); window && window != view3D->window()) {
740 if (
auto winAttacment = importSceneManager->wattached) {
742 auto rci = winAttacment->rci();
743 const bool inlineSync = (rci && rci->rhi() && (rci->rhi()->thread() == m_sgContext->rhi()->thread()));
747 winAttacment->synchronize(resourceLoaders);
748 }
else if (rci && !window->isExposed()) {
750 winAttacment->synchronize(resourceLoaders);
751 }
else if (!rci || (requestSharedUpdate & QQuick3DWindowAttachment::SyncResultFlag::SharedResourcesDirty)) {
756 winAttacment->requestUpdate();
769 m_layer->viewCount = rhiCtx->mainPassViewCount();
770 updateLayerNode(*m_layer, *view3D, resourceLoaders.values());
776 if (view3D->m_visibilityChanged) {
777 view3D->m_visibilityChanged =
false;
778 m_layer->markDirty(QSSGRenderLayer::DirtyFlag::VisibilityDirty);
783 m_requestedFramesCount = 0;
784 if (m_layer->isProgressiveAAEnabled() || m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector) {
791 m_requestedFramesCount = (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector ? 45 :
792 int(m_layer->antialiasingQuality) + 1);
793 }
else if (m_layer->isTemporalAAEnabled()) {
798 m_requestedFramesCount = (m_aaIsDirty || m_temporalIsDirty) ? QSSGLayerRenderData::MAX_TEMPORAL_AA_LEVELS : 1;
803 for (QSSGRenderEffect *effectNode = m_layer->firstEffect; effectNode; effectNode = effectNode->m_nextEffect)
804 effectNode->finalizeShaders(*m_layer, m_sgContext.get());
811 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
812 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses))
813 userPass->role = QSSGRenderUserPass::Role::TopLevel;
814 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses)) {
815 for (
const QSSGCommand *cmd : std::as_const(userPass->commands)) {
816 if (cmd->m_type != CommandType::SubRenderPass)
818 const auto *subCmd =
static_cast<
const QSSGSubRenderPass *>(cmd);
819 if (subCmd->m_userPassId == QSSGResourceId::Invalid)
821 if (
auto *subPass = QSSGRenderGraphObjectUtils::getResource<QSSGRenderUserPass>(subCmd->m_userPassId))
822 subPass->role = QSSGRenderUserPass::Role::SubPass;
826 QSSGUserRenderPassManagerPtr upm;
827 if (m_layer->renderData)
828 upm = m_layer->renderData->requestUserRenderPassManager();
830 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses)) {
831 if (userPass->role == QSSGRenderUserPass::Role::TopLevel)
832 upm->unscheduleUserPass(userPass);
835 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses)) {
836 userPass->finalizeShaders(*m_sgContext);
837 if (upm && userPass->role == QSSGRenderUserPass::Role::TopLevel)
838 upm->scheduleUserPass(userPass);
843 m_renderStats->setRhiContext(rhiCtx, m_layer);
845 static const auto getStageIndex = [](
const QSSGRenderExtension &ext) -> size_t {
846 const QSSGRenderExtension::RenderMode mode = ext.mode();
847 const QSSGRenderExtension::RenderStage stage = ext.stage();
850 if (mode == QSSGRenderExtension::RenderMode::Standalone)
851 return size_t(QSSGRenderLayer::RenderExtensionStage::TextureProviders);
854 case QSSGRenderExtension::RenderStage::PreColor:
855 return size_t(QSSGRenderLayer::RenderExtensionStage::Underlay);
856 case QSSGRenderExtension::RenderStage::PostColor:
857 return size_t(QSSGRenderLayer::RenderExtensionStage::Overlay);
860 Q_UNREACHABLE_RETURN(size_t(QSSGRenderLayer::RenderExtensionStage::Underlay));
866 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
867 const bool rebuildExtensionLists = (requestSharedUpdate & QQuick3DWindowAttachment::SyncResultFlag::ExtensionsDiry)
868 || view3D->extensionListDirty()
869 || sm->autoRegisteredExtensionsDirty;
874 if (rebuildExtensionLists) {
876 for (size_t i = 0; i != size_t(QSSGRenderLayer::RenderExtensionStage::Count); ++i)
877 m_layer->renderExtensions[i].clear();
880 const auto &extensions = view3D->extensionList();
881 for (
const auto &ext : extensions) {
882 const auto type = QQuick3DObjectPrivate::get(ext)->type;
883 if (QSSGRenderGraphObject::isExtension(type)) {
884 if (type == QSSGRenderGraphObject::Type::RenderExtension) {
885 if (
auto *renderExt = qobject_cast<QQuick3DRenderExtension *>(ext)) {
886 if (QSSGRenderExtension *ssgExt =
static_cast<QSSGRenderExtension *>(QQuick3DObjectPrivate::get(renderExt)->spatialNode)) {
887 const auto stage = getStageIndex(*ssgExt);
888 auto &list = m_layer->renderExtensions[size_t(stage)];
889 bfs(qobject_cast<QQuick3DRenderExtension *>(ext), list);
896 view3D->clearExtensionListDirty();
900 if (sm->autoRegisteredExtensionsDirty) {
901 for (QSSGRenderExtension *ae : std::as_const(sm->autoRegisteredExtensions))
902 m_layer->renderExtensions[getStageIndex(*ae)].push_back(ae);
903 sm->autoRegisteredExtensionsDirty =
false;
907 bool postProcessingNeeded = m_layer->firstEffect;
908 bool postProcessingWasActive = m_effectSystem;
909 QSSGRenderTextureFormat::Format effectOutputFormatOverride = QSSGRenderTextureFormat::Unknown;
910 if (postProcessingNeeded) {
911 QSSGRenderEffect *lastEffect = m_layer->firstEffect;
912 while (lastEffect->m_nextEffect)
913 lastEffect = lastEffect->m_nextEffect;
914 effectOutputFormatOverride = QSSGRhiEffectSystem::overriddenOutputFormat(lastEffect);
916 const auto layerTextureFormat = [effectOutputFormatOverride, view3D](QRhi *rhi,
bool postProc) {
917 if (effectOutputFormatOverride != QSSGRenderTextureFormat::Unknown)
918 return QSSGBufferManager::toRhiFormat(effectOutputFormatOverride);
933 const QRhiTexture::Format preferredPostProcFormat = QRhiTexture::RGBA16F;
934 if (postProc && rhi->isTextureFormatSupported(preferredPostProcFormat))
935 return preferredPostProcFormat;
937#if QT_CONFIG(quick_shadereffect)
938 const QRhiTexture::Format preferredView3DFormat = toRhiTextureFormat(view3D->renderFormat());
939 if (rhi->isTextureFormatSupported(preferredView3DFormat))
940 return preferredView3DFormat;
943 return QRhiTexture::RGBA8;
945 bool postProcessingStateDirty = postProcessingNeeded != postProcessingWasActive;
948 m_backgroundMode = QSSGRenderLayer::Background(view3D->environment()->backgroundMode());
952 QColor currentUserBackgroundColor = view3D->environment()->clearColor();
953 if (m_userBackgroundColor != currentUserBackgroundColor) {
954 m_userBackgroundColor = currentUserBackgroundColor;
955 m_linearBackgroundColor = QSSGUtils::color::sRGBToLinearColor(m_userBackgroundColor);
956 const QVector3D tc = tonemapRgb(QVector3D(m_linearBackgroundColor.redF(),
957 m_linearBackgroundColor.greenF(),
958 m_linearBackgroundColor.blueF()),
959 view3D->environment()->tonemapMode());
960 m_tonemappedBackgroundColor = QColor::fromRgbF(tc.x(), tc.y(), tc.z(), m_linearBackgroundColor.alphaF());
962 m_layer->scissorRect = QRect(view3D->environment()->scissorRect().topLeft() * dpr,
963 view3D->environment()->scissorRect().size() * dpr);
969 auto sceneRootNode =
static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(view3D->scene())->spatialNode);
970 if (sceneRootNode != m_sceneRootNode) {
972 removeNodeFromLayer(m_sceneRootNode);
975 addNodeToLayer(sceneRootNode);
977 m_sceneRootNode = sceneRootNode;
981 QSSGRenderNode *importSceneRootNode =
nullptr;
983 importSceneRootNode =
static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(importScene)->spatialNode);
985 if (importSceneRootNode != m_importSceneRootNode) {
986 if (m_importSceneRootNode)
987 m_layer->removeImportScene(*m_importSceneRootNode);
989 if (importSceneRootNode) {
993 QObject *sceneParent = importScene->parent();
994 bool isEmbedded =
false;
995 while (sceneParent) {
996 if (sceneParent == view3D) {
1000 sceneParent = sceneParent->parent();
1003 m_layer->setImportScene(*importSceneRootNode);
1006 m_importSceneRootNode = importSceneRootNode;
1014 QSSGRenderRoot *rootNode = winAttacment->rootNode();
1015 if (rootNode->isDirty(QSSGRenderRoot::DirtyFlag::TreeDirty)) {
1016 rootNode->reindex();
1020 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
1021 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses)) {
1022 if (
const auto *fo = sm->lookUpNode(userPass); fo && fo->parentItem()) {
1023 const auto *pi = fo->parentItem();
1024 if (
const QSSGRenderGraphObject *parentNode = QQuick3DObjectPrivate::get(pi)->spatialNode; parentNode && QSSGRenderGraphObject::isNodeType(parentNode->type))
1025 userPass->setDependencyIndex(
static_cast<
const QSSGRenderNode *>(parentNode)->h.index());
1027 userPass->setDependencyIndex(0);
1034 maybeSetupLightmapBaking(view3D);
1036 if (m_useFBO && rhiCtx->isValid()) {
1037 QRhi *rhi = rhiCtx->rhi();
1038 const QSize renderSize = m_layer->isSsaaEnabled() ? m_surfaceSize * m_layer->ssaaMultiplier : m_surfaceSize;
1042 if (layerSizeIsDirty || postProcessingStateDirty) {
1043 m_texture->setPixelSize(m_surfaceSize);
1044 m_texture->setFormat(layerTextureFormat(rhi, postProcessingNeeded));
1045 m_texture->create();
1056 if (postProcessingStateDirty && (m_layer->antialiasingMode != QSSGRenderLayer::AAMode::NoAA || m_layer->isTemporalAAEnabled())) {
1057 releaseAaDependentRhiResources();
1059 if (m_ssaaTexture) {
1060 m_ssaaTexture->setPixelSize(renderSize);
1061 m_ssaaTexture->create();
1063 if (m_depthStencilBuffer) {
1064 m_depthStencilBuffer->setPixelSize(renderSize);
1065 m_depthStencilBuffer->create();
1067 if (m_multiViewDepthStencilBuffer) {
1068 m_multiViewDepthStencilBuffer->setPixelSize(renderSize);
1069 m_multiViewDepthStencilBuffer->create();
1071 if (m_msaaRenderBufferLegacy) {
1072 m_msaaRenderBufferLegacy->setPixelSize(renderSize);
1073 m_msaaRenderBufferLegacy->create();
1075 if (m_msaaRenderTexture) {
1076 m_msaaRenderTexture->setPixelSize(renderSize);
1077 m_msaaRenderTexture->create();
1079 if (m_msaaMultiViewRenderBuffer) {
1080 m_msaaMultiViewRenderBuffer->setPixelSize(renderSize);
1081 m_msaaMultiViewRenderBuffer->create();
1087 if (postProcessingStateDirty) {
1088 delete m_textureRenderPassDescriptor;
1089 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
1090 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
1092 m_textureRenderTarget->create();
1093 if (m_ssaaTextureToTextureRenderTarget)
1094 m_ssaaTextureToTextureRenderTarget->create();
1096 if (m_temporalAATexture) {
1097 m_temporalAATexture->setPixelSize(renderSize);
1098 m_temporalAATexture->create();
1100 if (m_prevTempAATexture) {
1101 m_prevTempAATexture->setPixelSize(renderSize);
1102 m_prevTempAATexture->create();
1104 if (m_temporalAARenderTarget)
1105 m_temporalAARenderTarget->create();
1108 }
else if (m_aaIsDirty && rhi->backend() == QRhi::Metal) {
1109 m_texture->create();
1113 releaseAaDependentRhiResources();
1116 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget
1117 | QRhiTexture::UsedAsTransferSource;
1118 const QRhiTexture::Format textureFormat = layerTextureFormat(rhi, postProcessingNeeded);
1121 if (m_layer->viewCount >= 2)
1122 m_texture = rhi->newTextureArray(textureFormat, m_layer->viewCount, m_surfaceSize, 1, textureFlags);
1124 m_texture = rhi->newTexture(textureFormat, m_surfaceSize, 1, textureFlags);
1125 m_texture->create();
1128 if (!m_ssaaTexture && m_layer->isSsaaEnabled()) {
1129 if (m_layer->viewCount >= 2)
1130 m_ssaaTexture = rhi->newTextureArray(textureFormat, m_layer->viewCount, renderSize, 1, textureFlags);
1132 m_ssaaTexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1133 m_ssaaTexture->create();
1136 if (m_timeBasedAA && !m_temporalAATexture) {
1137 m_temporalAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1138 m_temporalAATexture->create();
1139 m_prevTempAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1140 m_prevTempAATexture->create();
1144 if (m_aaIsDirty || layerSizeIsDirty)
1145 m_layer->tempAAPassIndex = m_layer->progAAPassIndex = 0;
1149 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::MSAA) {
1150 if (rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer)) {
1151 m_samples = qMax(1,
int(m_layer->antialiasingQuality));
1157 const QVector<
int> supported = rhi->supportedSampleCounts();
1158 if (!supported.contains(m_samples)) {
1159 if (!supported.isEmpty()) {
1160 auto it = std::lower_bound(supported.cbegin(), supported.cend(), m_samples);
1161 m_samples = it == supported.cend() ? supported.last() : *it;
1167 static bool warned =
false;
1170 qWarning(
"Multisample renderbuffers are not supported, disabling MSAA for Offscreen View3D");
1176 if (m_layer->viewCount >= 2) {
1177 if (!m_multiViewDepthStencilBuffer) {
1178 const auto format = rhi->isTextureFormatSupported(QRhiTexture::D24S8) ? QRhiTexture::D24S8 : QRhiTexture::D32FS8;
1179 m_multiViewDepthStencilBuffer = rhi->newTextureArray(format, m_layer->viewCount, renderSize,
1180 m_samples, QRhiTexture::RenderTarget);
1181 m_multiViewDepthStencilBuffer->create();
1184 if (!m_depthStencilBuffer) {
1185 m_depthStencilBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, renderSize, m_samples);
1186 m_depthStencilBuffer->create();
1190 if (!m_textureRenderTarget) {
1191 QRhiTextureRenderTargetDescription rtDesc;
1192 QRhiColorAttachment att;
1193 if (m_samples > 1) {
1194 if (m_layer->viewCount >= 2) {
1195 m_msaaMultiViewRenderBuffer = rhi->newTextureArray(textureFormat, m_layer->viewCount, renderSize, m_samples, QRhiTexture::RenderTarget);
1196 m_msaaMultiViewRenderBuffer->create();
1197 att.setTexture(m_msaaMultiViewRenderBuffer);
1199 if (!rhi->isFeatureSupported(QRhi::MultisampleTexture)) {
1201 m_msaaRenderBufferLegacy = rhi->newRenderBuffer(QRhiRenderBuffer::Color, renderSize, m_samples, {}, m_texture->format());
1202 m_msaaRenderBufferLegacy->create();
1203 att.setRenderBuffer(m_msaaRenderBufferLegacy);
1210 m_msaaRenderTexture = rhi->newTexture(textureFormat, renderSize, m_samples, QRhiTexture::RenderTarget);
1211 m_msaaRenderTexture->create();
1212 att.setTexture(m_msaaRenderTexture);
1215 att.setResolveTexture(m_texture);
1217 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA)
1218 att.setTexture(m_ssaaTexture);
1220 att.setTexture(m_texture);
1222 att.setMultiViewCount(m_layer->viewCount);
1223 rtDesc.setColorAttachments({ att });
1224 if (m_depthStencilBuffer)
1225 rtDesc.setDepthStencilBuffer(m_depthStencilBuffer);
1226 if (m_multiViewDepthStencilBuffer)
1227 rtDesc.setDepthTexture(m_multiViewDepthStencilBuffer);
1229 m_textureRenderTarget = rhi->newTextureRenderTarget(rtDesc);
1230 m_textureRenderTarget->setName(QByteArrayLiteral(
"View3D"));
1231 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
1232 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
1233 m_textureRenderTarget->create();
1236 if (!m_ssaaTextureToTextureRenderTarget && m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
1237 QRhiColorAttachment att(m_texture);
1238 att.setMultiViewCount(m_layer->viewCount);
1239 m_ssaaTextureToTextureRenderTarget = rhi->newTextureRenderTarget(QRhiTextureRenderTargetDescription({ att }));
1240 m_ssaaTextureToTextureRenderTarget->setName(QByteArrayLiteral(
"SSAA texture"));
1241 m_ssaaTextureToTextureRenderPassDescriptor = m_ssaaTextureToTextureRenderTarget->newCompatibleRenderPassDescriptor();
1242 m_ssaaTextureToTextureRenderTarget->setRenderPassDescriptor(m_ssaaTextureToTextureRenderPassDescriptor);
1243 m_ssaaTextureToTextureRenderTarget->create();
1246 if (m_layer->firstEffect) {
1247 if (!m_effectSystem)
1248 m_effectSystem =
new QSSGRhiEffectSystem(m_sgContext);
1249 m_effectSystem->setup(renderSize);
1250 }
else if (m_effectSystem) {
1251 delete m_effectSystem;
1252 m_effectSystem =
nullptr;
1255 if (m_timeBasedAA && !m_temporalAARenderTarget) {
1256 m_temporalAARenderTarget = rhi->newTextureRenderTarget({ m_temporalAATexture });
1257 m_temporalAARenderTarget->setName(QByteArrayLiteral(
"Temporal AA texture"));
1258 m_temporalAARenderPassDescriptor = m_temporalAARenderTarget->newCompatibleRenderPassDescriptor();
1259 m_temporalAARenderTarget->setRenderPassDescriptor(m_temporalAARenderPassDescriptor);
1260 m_temporalAARenderTarget->create();
1263 m_textureNeedsFlip = rhi->isYUpInFramebuffer();
1264 m_aaIsDirty =
false;
1268 m_renderStats->endSync(dumpRenderTimes());
1270 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DSynchronizeFrame, quint64(m_surfaceSize.width()) | quint64(m_surfaceSize.height()) << 32, profilingId);