310 QRhiTexture *currentTexture = m_texture;
314 m_renderStats->startRenderPrepare();
316 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
318 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
319 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
321 rhiCtxD->setMainRenderPassDescriptor(m_textureRenderPassDescriptor);
322 rhiCtxD->setRenderTarget(m_textureRenderTarget);
324 QRhiCommandBuffer *cb =
nullptr;
325 QRhiSwapChain *swapchain = qw->swapChain();
327 cb = swapchain->currentFrameCommandBuffer();
328 rhiCtxD->setCommandBuffer(cb);
330 QSGRendererInterface *rif = qw->rendererInterface();
331 cb =
static_cast<QRhiCommandBuffer *>(
332 rif->getResource(qw, QSGRendererInterface::RhiRedirectCommandBuffer));
334 rhiCtxD->setCommandBuffer(cb);
336 qWarning(
"Neither swapchain nor redirected command buffer are available.");
337 return currentTexture;
343 rhiCtxD->setMainPassSampleCount(m_msaaRenderBufferLegacy ? m_msaaRenderBufferLegacy->sampleCount() :
344 (m_msaaRenderTexture ? m_msaaRenderTexture->sampleCount() :
345 (m_msaaMultiViewRenderBuffer ? m_msaaMultiViewRenderBuffer->sampleCount() : 1)));
349 int ssaaAdjustedWidth = m_surfaceSize.width();
350 int ssaaAdjustedHeight = m_surfaceSize.height();
351 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
352 ssaaAdjustedWidth *= m_layer->ssaaMultiplier;
353 ssaaAdjustedHeight *= m_layer->ssaaMultiplier;
356 Q_TRACE(QSSG_prepareFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
358 float dpr = m_sgContext->renderer()->dpr();
359 const QRect vp = QRect(0, 0, ssaaAdjustedWidth, ssaaAdjustedHeight);
364 m_renderStats->endRenderPrepare();
366 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, profilingId);
368 Q_TRACE(QSSG_prepareFrame_exit);
370 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
371 Q_TRACE(QSSG_renderFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
373 m_renderStats->startRender();
375 QColor clearColor = Qt::transparent;
376 if (m_backgroundMode == QSSGRenderLayer::Background::Color
377 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBoxCubeMap && !m_layer->skyBoxCubeMap)
378 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBox && !m_layer->lightProbe)
379 || (m_backgroundMode == QSSGRenderLayer::Background::SkyMaterial && !m_layer->skyMaterial)) {
382 clearColor = m_layer->firstEffect ? m_linearBackgroundColor : m_tonemappedBackgroundColor;
387 cb->beginPass(m_textureRenderTarget, clearColor, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
388 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
389 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(m_textureRenderTarget));
392 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
393 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, QByteArrayLiteral(
"main"));
395 const bool temporalAA = m_layer->temporalAAIsActive;
396 const bool progressiveAA = m_layer->progressiveAAIsActive;
397 const bool superSamplingAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA;
398 QRhi *rhi = rhiCtx->rhi();
400 currentTexture = superSamplingAA ? m_ssaaTexture : m_texture;
403 if (m_effectSystem && m_layer->firstEffect && !m_layer->renderedCameras.isEmpty()) {
404 const auto &renderer = m_sgContext->renderer();
406 Q_ASSERT(theRenderData);
407 QRhiTexture *theDepthTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::DepthTexture)->texture;
408 QRhiTexture *theNormalTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::NormalTexture)->texture;
409 QRhiTexture *theMotionVectorTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::MotionVectorTexture)->texture;
411 currentTexture = m_effectSystem->process(*m_layer,
415 theMotionVectorTexture);
418 if ((progressiveAA || temporalAA) && m_prevTempAATexture) {
419 cb->debugMarkBegin(QByteArrayLiteral(
"Temporal AA"));
420 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
421 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"Temporal AA"));
422 QRhiTexture *blendResult;
423 uint *aaIndex = progressiveAA ? &m_layer->progAAPassIndex : &m_layer->tempAAPassIndex;
426 if ((temporalAA && m_layer->temporalAAMode != QSSGRenderLayer::TAAMode::MotionVector) ||
428 (temporalAA && m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector ?
429 quint32(QSSGLayerRenderData::MAX_AA_LEVELS) :
430 quint32(m_layer->antialiasingQuality))) {
431 const auto &renderer = m_sgContext->renderer();
433 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
434 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ m_layer,
nullptr,
nullptr,
nullptr, 0 }));
435 QRhiBuffer *&ubuf = dcd.ubuf;
436 const int ubufSize = 4 *
sizeof(
float);
438 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
441 int idx = *aaIndex - 1;
443 const QSize textureSize = m_prevTempAATexture->pixelSize();
444 QVector4D bufferData;
446 bufferData = QVector4D(s_ProgressiveAABlendFactors[idx]);
447 else if (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::Default)
448 bufferData = QVector4D(s_TemporalAABlendFactors);
450 bufferData = QVector4D(1.0f / qMax(textureSize.width(), 1), 1.0f / qMax(textureSize.height(), 1),
451 0.9f + (qMin(qMax(m_layer->temporalAAStrength, 0.3f), 1.0f) - 0.3f) / 0.7f * 0.09f, 0.0f);
453 rub->updateDynamicBuffer(ubuf, 0, 4 *
sizeof(
float), &bufferData);
454 QSSGRhiGraphicsPipelineState ps;
455 ps.viewport = QRhiViewport(0, 0,
float(textureSize.width()),
float(textureSize.height()));
457 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
458 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
459 QSSGRhiShaderResourceBindingList bindings;
460 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
461 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
462 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, m_prevTempAATexture, sampler);
463 if (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector) {
465 Q_ASSERT(theRenderData);
466 QRhiTexture *theDepthTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::DepthTexture)->texture;
467 QRhiTexture *theMotionVectorTexture = theRenderData->getRenderResult(QSSGRenderResult::Key::MotionVectorTexture)->texture;
468 bindings.addTexture(3, QRhiShaderResourceBinding::FragmentStage, theDepthTexture, sampler);
469 bindings.addTexture(4, QRhiShaderResourceBinding::FragmentStage, theMotionVectorTexture, sampler);
470 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiTemporalAAShader().get());
475 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiProgressiveAAShader().get());
478 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
479 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx, rub);
480 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_temporalAARenderTarget, QSSGRhiQuadRenderer::UvCoords);
481 blendResult = m_temporalAATexture;
483 blendResult = m_prevTempAATexture;
487 blendResult = currentTexture;
490 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
492 const bool isMotionVector = m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector;
493 const quint32 aaLimit = (temporalAA && isMotionVector) ? quint32(QSSGLayerRenderData::MAX_AA_LEVELS) : quint32(m_layer->antialiasingQuality);
495 const bool aaActive = (temporalAA && !isMotionVector) || (*aaIndex < aaLimit);
496 const bool usePrevTexture = m_prevTempAATexture !=
nullptr;
498 if (aaActive && usePrevTexture) {
499 QRhiTexture *copySource = (blendResult && (progressiveAA || isMotionVector)) ? blendResult : currentTexture;
502 auto *rub = rhi->nextResourceUpdateBatch();
503 rub->copyTexture(m_prevTempAATexture, copySource);
504 cb->resourceUpdate(rub);
510 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"temporal_aa"));
512 currentTexture = blendResult;
515 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
525 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
526 const auto &renderer = m_sgContext->renderer();
528 cb->debugMarkBegin(QByteArrayLiteral(
"SSAA downsample"));
529 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
531 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"SSAA downsample"));
533 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx,
nullptr);
540 const auto &shaderPipeline = m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiSupersampleResolveShader(m_layer->viewCount);
542 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
543 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::Repeat });
544 QSSGRhiShaderResourceBindingList bindings;
545 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
546 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
548 QSSGRhiGraphicsPipelineState ps;
549 ps.viewport = QRhiViewport(0, 0,
float(m_surfaceSize.width()),
float(m_surfaceSize.height()));
550 ps.viewCount = m_layer->viewCount;
551 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
553 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_ssaaTextureToTextureRenderTarget, QSSGRhiQuadRenderer::UvCoords);
555 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"ssaa_downsample"));
557 currentTexture = m_texture;
560 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
561 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiCtx)),
565 m_renderStats->endRender(dumpRenderTimes());
566 Q_TRACE(QSSG_renderFrame_exit);
569 if (m_layer && m_layer->skyMaterial && m_layer->skyMaterial->wantsMoreFrames)
570 ++m_requestedFramesCount;
572 return currentTexture;
654 Q_TRACE_SCOPE(QSSG_synchronize, view3D, size, dpr);
656 Q_ASSERT(view3D !=
nullptr);
657 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
658 Q_ASSERT(rhiCtx !=
nullptr);
662 m_layer =
new QSSGRenderLayer();
664 bool newRenderStats =
false;
665 if (!m_renderStats) {
666 m_renderStats = view3D->renderStats();
667 newRenderStats =
true;
671 m_renderStats->startSync();
673 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DSynchronizeFrame);
675 m_sgContext->renderer()->setDpr(dpr);
676 bool layerSizeIsDirty = m_surfaceSize != size;
677 m_surfaceSize = size;
679 QQuick3DSceneEnvironment *environment = view3D->environment();
680 if (environment->lightmapper()) {
681 QQuick3DLightmapper *lightmapper = environment->lightmapper();
682 lmOptions.opacityThreshold = lightmapper->opacityThreshold();
683 lmOptions.bias = lightmapper->bias();
684 lmOptions.useAdaptiveBias = lightmapper->isAdaptiveBiasEnabled();
685 lmOptions.indirectLightEnabled = lightmapper->isIndirectLightEnabled();
686 lmOptions.indirectLightSamples = lightmapper->samples();
687 lmOptions.indirectLightWorkgroupSize = lightmapper->indirectLightWorkgroupSize();
688 lmOptions.indirectLightBounces = lightmapper->bounces();
689 lmOptions.indirectLightFactor = lightmapper->indirectLightFactor();
690 lmOptions.sigma = lightmapper->denoiseSigma();
691 lmOptions.texelsPerUnit = lightmapper->texelsPerUnit();
697 if (environment->m_dirtyFlags & QQuick3DSceneEnvironment::InternalDirtyFlag::LightmapperDirty) {
698 environment->m_dirtyFlags &= ~QQuick3DSceneEnvironment::InternalDirtyFlag::LightmapperDirty;
700 const QQmlContext *context = qmlContext(view3D);
701 const QUrl originalSource = environment->lightmapper() ? environment->lightmapper()->source()
702 : QUrl::fromLocalFile(QStringLiteral(
"lightmaps.bin"));
703 const auto resolvedUrl = context ? context->resolvedUrl(originalSource) : originalSource;
704 const auto qmlSource = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
705 const QString lightmapSource = qmlSource.isEmpty() ? originalSource.path() : qmlSource;
706 lmOptions.source = lightmapSource;
707 m_layer->lightmapSource = lightmapSource;
710 m_sgContext->bufferManager()->setLightmapSource(m_layer->lightmapSource);
711 if (QQuick3DSceneManager *sceneManager = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager)
712 sceneManager->lightmapSourceTracker = { m_layer->lightmapSource,
true };
716 QSet<QSSGRenderGraphObject *> resourceLoaders;
717 QQuick3DWindowAttachment::SyncResult requestSharedUpdate = QQuick3DWindowAttachment::SyncResultFlag::None;
718 if (
auto window = view3D->window()) {
719 if (!winAttacment || winAttacment->window() != window)
720 winAttacment = QQuick3DSceneManager::getOrSetWindowAttachment(*window);
722 if (winAttacment && winAttacment->rci() != m_sgContext)
723 winAttacment->setRci(m_sgContext);
725 QSSGRenderRoot *rootNode = winAttacment->rootNode();
726 if (m_layer->rootNode != rootNode) {
727 Q_ASSERT(m_layer->rootNode ==
nullptr);
728 rootNode->addChild(*m_layer);
729 rootNode->setStartVersion(m_layer->h.version());
730 m_layer->ref(rootNode);
734 requestSharedUpdate |= winAttacment->synchronize(resourceLoaders);
738 QQuick3DNode *importScene = view3D->importScene();
740 QQuick3DSceneManager *importSceneManager = QQuick3DObjectPrivate::get(importScene)->sceneManager;
743 if (
auto window = importSceneManager->window(); window && window != view3D->window()) {
744 if (
auto winAttacment = importSceneManager->wattached) {
746 auto rci = winAttacment->rci();
747 const bool inlineSync = (rci && rci->rhi() && (rci->rhi()->thread() == m_sgContext->rhi()->thread()));
751 winAttacment->synchronize(resourceLoaders);
752 }
else if (rci && !window->isExposed()) {
754 winAttacment->synchronize(resourceLoaders);
755 }
else if (!rci || (requestSharedUpdate & QQuick3DWindowAttachment::SyncResultFlag::SharedResourcesDirty)) {
760 winAttacment->requestUpdate();
773 m_layer->viewCount = rhiCtx->mainPassViewCount();
774 updateLayerNode(*m_layer, *view3D, resourceLoaders.values());
780 if (view3D->m_visibilityChanged) {
781 view3D->m_visibilityChanged =
false;
782 m_layer->markDirty(QSSGRenderLayer::DirtyFlag::VisibilityDirty);
787 m_requestedFramesCount = 0;
788 if (m_layer->isProgressiveAAEnabled() || m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector) {
795 m_requestedFramesCount = (m_layer->temporalAAMode == QSSGRenderLayer::TAAMode::MotionVector ? 45 :
796 int(m_layer->antialiasingQuality) + 1);
797 }
else if (m_layer->isTemporalAAEnabled()) {
802 m_requestedFramesCount = (m_aaIsDirty || m_temporalIsDirty) ? QSSGLayerRenderData::MAX_TEMPORAL_AA_LEVELS : 1;
807 for (QSSGRenderEffect *effectNode = m_layer->firstEffect; effectNode; effectNode = effectNode->m_nextEffect)
808 effectNode->finalizeShaders(*m_layer, m_sgContext.get());
826 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
830 if (sm->userRenderPassesDirty) {
834 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses)) {
835 if (userPass->role != QSSGRenderUserPass::Role::SubPass)
837 for (
const QSSGCommand *cmd : std::as_const(userPass->commands)) {
838 if (cmd->m_type == CommandType::ColorAttachment
839 || cmd->m_type == CommandType::DepthStencilAttachment
840 || cmd->m_type == CommandType::DepthTextureAttachment) {
841 qWarning() <<
"RenderPass" << sm->lookUpNode(userPass)
842 <<
"is used as a sub-pass; its" << cmd->typeAsString()
843 <<
"command is ignored because a sub-pass renders into its parent's render target.";
854 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses)) {
855 userPass->m_nestingDepth = 0;
856 if (userPass->role != QSSGRenderUserPass::Role::TopLevel)
858 const QQuick3DObject *fo = sm->lookUpNode(userPass);
862 for (QQuick3DObject *p = fo->parentItem(); p; p = p->parentItem()) {
863 if (QSSGRenderGraphObjectUtils::isUserRenderPass(QQuick3DObjectPrivate::get(p)->type))
866 userPass->m_nestingDepth = depth;
868 quint32 declarationOrder = 0;
869 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses)) {
870 if (userPass->role == QSSGRenderUserPass::Role::TopLevel)
871 userPass->m_declarationOrder = declarationOrder++;
873 sm->userRenderPassesDirty =
false;
876 QSSGUserRenderPassManager::UserPassSet topLevelPasses;
877 topLevelPasses.reserve(sm->userRenderPasses.size());
878 for (QSSGRenderUserPass *userPass : std::as_const(sm->userRenderPasses)) {
879 userPass->finalizeShaders(*m_sgContext);
880 if (userPass->role == QSSGRenderUserPass::Role::TopLevel)
881 topLevelPasses.push_back(userPass);
888 QSSGLayerRenderData *renderData = m_sgContext->renderer()->getOrCreateLayerRenderData(*m_layer);
889 if (
const QSSGUserRenderPassManagerPtr &upm = renderData->requestUserRenderPassManager())
890 upm->setScheduledPasses(topLevelPasses);
894 m_renderStats->setRhiContext(rhiCtx, m_layer);
896 static const auto getStageIndex = [](
const QSSGRenderExtension &ext) -> size_t {
897 const QSSGRenderExtension::RenderMode mode = ext.mode();
898 const QSSGRenderExtension::RenderStage stage = ext.stage();
901 if (mode == QSSGRenderExtension::RenderMode::Standalone)
902 return size_t(QSSGRenderLayer::RenderExtensionStage::TextureProviders);
905 case QSSGRenderExtension::RenderStage::PreColor:
906 return size_t(QSSGRenderLayer::RenderExtensionStage::Underlay);
907 case QSSGRenderExtension::RenderStage::PostColor:
908 return size_t(QSSGRenderLayer::RenderExtensionStage::Overlay);
911 Q_UNREACHABLE_RETURN(size_t(QSSGRenderLayer::RenderExtensionStage::Underlay));
917 if (QQuick3DSceneManager *sm = QQuick3DObjectPrivate::get(view3D->scene())->sceneManager; sm) {
918 const bool rebuildExtensionLists = (requestSharedUpdate & QQuick3DWindowAttachment::SyncResultFlag::ExtensionsDiry)
919 || view3D->extensionListDirty()
920 || sm->autoRegisteredExtensionsDirty;
925 if (rebuildExtensionLists) {
927 for (size_t i = 0; i != size_t(QSSGRenderLayer::RenderExtensionStage::Count); ++i)
928 m_layer->renderExtensions[i].clear();
931 const auto &extensions = view3D->extensionList();
932 for (
const auto &ext : extensions) {
933 const auto type = QQuick3DObjectPrivate::get(ext)->type;
934 if (QSSGRenderGraphObject::isExtension(type)) {
935 if (type == QSSGRenderGraphObject::Type::RenderExtension) {
936 if (
auto *renderExt = qobject_cast<QQuick3DRenderExtension *>(ext)) {
937 if (QSSGRenderExtension *ssgExt =
static_cast<QSSGRenderExtension *>(QQuick3DObjectPrivate::get(renderExt)->spatialNode)) {
938 const auto stage = getStageIndex(*ssgExt);
939 auto &list = m_layer->renderExtensions[size_t(stage)];
940 bfs(qobject_cast<QQuick3DRenderExtension *>(ext), list);
947 view3D->clearExtensionListDirty();
951 if (sm->autoRegisteredExtensionsDirty) {
952 for (QSSGRenderExtension *ae : std::as_const(sm->autoRegisteredExtensions))
953 m_layer->renderExtensions[getStageIndex(*ae)].push_back(ae);
954 sm->autoRegisteredExtensionsDirty =
false;
958 bool postProcessingNeeded = m_layer->firstEffect;
959 bool postProcessingWasActive = m_effectSystem;
960 QSSGRenderTextureFormat::Format effectOutputFormatOverride = QSSGRenderTextureFormat::Unknown;
961 if (postProcessingNeeded) {
962 QSSGRenderEffect *lastEffect = m_layer->firstEffect;
963 while (lastEffect->m_nextEffect)
964 lastEffect = lastEffect->m_nextEffect;
965 effectOutputFormatOverride = QSSGRhiEffectSystem::overriddenOutputFormat(lastEffect);
967 const auto layerTextureFormat = [effectOutputFormatOverride, view3D](QRhi *rhi,
bool postProc) {
968 if (effectOutputFormatOverride != QSSGRenderTextureFormat::Unknown)
969 return QSSGBufferManager::toRhiFormat(effectOutputFormatOverride);
984 const QRhiTexture::Format preferredPostProcFormat = QRhiTexture::RGBA16F;
985 if (postProc && rhi->isTextureFormatSupported(preferredPostProcFormat))
986 return preferredPostProcFormat;
988#if QT_CONFIG(quick_shadereffect)
989 const QRhiTexture::Format preferredView3DFormat = toRhiTextureFormat(view3D->renderFormat());
990 if (rhi->isTextureFormatSupported(preferredView3DFormat))
991 return preferredView3DFormat;
994 return QRhiTexture::RGBA8;
996 bool postProcessingStateDirty = postProcessingNeeded != postProcessingWasActive;
999 m_backgroundMode = QSSGRenderLayer::Background(view3D->environment()->backgroundMode());
1003 QColor currentUserBackgroundColor = view3D->environment()->clearColor();
1004 if (m_userBackgroundColor != currentUserBackgroundColor) {
1005 m_userBackgroundColor = currentUserBackgroundColor;
1006 m_linearBackgroundColor = QSSGUtils::color::sRGBToLinearColor(m_userBackgroundColor);
1007 const QVector3D tc = tonemapRgb(QVector3D(m_linearBackgroundColor.redF(),
1008 m_linearBackgroundColor.greenF(),
1009 m_linearBackgroundColor.blueF()),
1010 view3D->environment()->tonemapMode());
1011 m_tonemappedBackgroundColor = QColor::fromRgbF(tc.x(), tc.y(), tc.z(), m_linearBackgroundColor.alphaF());
1013 m_layer->scissorRect = QRect(view3D->environment()->scissorRect().topLeft() * dpr,
1014 view3D->environment()->scissorRect().size() * dpr);
1020 auto sceneRootNode =
static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(view3D->scene())->spatialNode);
1021 if (sceneRootNode != m_sceneRootNode) {
1022 if (m_sceneRootNode)
1023 removeNodeFromLayer(m_sceneRootNode);
1026 addNodeToLayer(sceneRootNode);
1028 m_sceneRootNode = sceneRootNode;
1032 QSSGRenderNode *importSceneRootNode =
nullptr;
1034 importSceneRootNode =
static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(importScene)->spatialNode);
1036 if (importSceneRootNode != m_importSceneRootNode) {
1037 if (m_importSceneRootNode)
1038 m_layer->removeImportScene(*m_importSceneRootNode);
1040 if (importSceneRootNode) {
1044 QObject *sceneParent = importScene->parent();
1045 bool isEmbedded =
false;
1046 while (sceneParent) {
1047 if (sceneParent == view3D) {
1051 sceneParent = sceneParent->parent();
1054 m_layer->setImportScene(*importSceneRootNode);
1057 m_importSceneRootNode = importSceneRootNode;
1065 QSSGRenderRoot *rootNode = winAttacment->rootNode();
1066 if (rootNode->isDirty(QSSGRenderRoot::DirtyFlag::TreeDirty)) {
1067 rootNode->reindex();
1071 maybeSetupLightmapBaking(view3D);
1073 if (m_useFBO && rhiCtx->isValid()) {
1074 QRhi *rhi = rhiCtx->rhi();
1075 const QSize renderSize = m_layer->isSsaaEnabled() ? m_surfaceSize * m_layer->ssaaMultiplier : m_surfaceSize;
1079 if (layerSizeIsDirty || postProcessingStateDirty) {
1080 m_texture->setPixelSize(m_surfaceSize);
1081 m_texture->setFormat(layerTextureFormat(rhi, postProcessingNeeded));
1082 m_texture->create();
1093 if (postProcessingStateDirty && (m_layer->antialiasingMode != QSSGRenderLayer::AAMode::NoAA || m_layer->isTemporalAAEnabled())) {
1094 releaseAaDependentRhiResources();
1096 if (m_ssaaTexture) {
1097 m_ssaaTexture->setPixelSize(renderSize);
1098 m_ssaaTexture->create();
1100 if (m_depthStencilBuffer) {
1101 m_depthStencilBuffer->setPixelSize(renderSize);
1102 m_depthStencilBuffer->create();
1104 if (m_multiViewDepthStencilBuffer) {
1105 m_multiViewDepthStencilBuffer->setPixelSize(renderSize);
1106 m_multiViewDepthStencilBuffer->create();
1108 if (m_msaaRenderBufferLegacy) {
1109 m_msaaRenderBufferLegacy->setPixelSize(renderSize);
1110 m_msaaRenderBufferLegacy->create();
1112 if (m_msaaRenderTexture) {
1113 m_msaaRenderTexture->setPixelSize(renderSize);
1114 m_msaaRenderTexture->create();
1116 if (m_msaaMultiViewRenderBuffer) {
1117 m_msaaMultiViewRenderBuffer->setPixelSize(renderSize);
1118 m_msaaMultiViewRenderBuffer->create();
1124 if (postProcessingStateDirty) {
1125 delete m_textureRenderPassDescriptor;
1126 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
1127 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
1129 m_textureRenderTarget->create();
1130 if (m_ssaaTextureToTextureRenderTarget)
1131 m_ssaaTextureToTextureRenderTarget->create();
1133 if (m_temporalAATexture) {
1134 m_temporalAATexture->setPixelSize(renderSize);
1135 m_temporalAATexture->create();
1137 if (m_prevTempAATexture) {
1138 m_prevTempAATexture->setPixelSize(renderSize);
1139 m_prevTempAATexture->create();
1141 if (m_temporalAARenderTarget)
1142 m_temporalAARenderTarget->create();
1145 }
else if (m_aaIsDirty && rhi->backend() == QRhi::Metal) {
1146 m_texture->create();
1150 releaseAaDependentRhiResources();
1153 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget
1154 | QRhiTexture::UsedAsTransferSource;
1155 const QRhiTexture::Format textureFormat = layerTextureFormat(rhi, postProcessingNeeded);
1158 if (m_layer->viewCount >= 2)
1159 m_texture = rhi->newTextureArray(textureFormat, m_layer->viewCount, m_surfaceSize, 1, textureFlags);
1161 m_texture = rhi->newTexture(textureFormat, m_surfaceSize, 1, textureFlags);
1162 m_texture->create();
1165 if (!m_ssaaTexture && m_layer->isSsaaEnabled()) {
1166 if (m_layer->viewCount >= 2)
1167 m_ssaaTexture = rhi->newTextureArray(textureFormat, m_layer->viewCount, renderSize, 1, textureFlags);
1169 m_ssaaTexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1170 m_ssaaTexture->create();
1173 if (m_timeBasedAA && !m_temporalAATexture) {
1174 m_temporalAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1175 m_temporalAATexture->create();
1176 m_prevTempAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
1177 m_prevTempAATexture->create();
1181 if (m_aaIsDirty || layerSizeIsDirty)
1182 m_layer->tempAAPassIndex = m_layer->progAAPassIndex = 0;
1186 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::MSAA) {
1187 if (rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer)) {
1188 m_samples = qMax(1,
int(m_layer->antialiasingQuality));
1194 const QVector<
int> supported = rhi->supportedSampleCounts();
1195 if (!supported.contains(m_samples)) {
1196 if (!supported.isEmpty()) {
1197 auto it = std::lower_bound(supported.cbegin(), supported.cend(), m_samples);
1198 m_samples = it == supported.cend() ? supported.last() : *it;
1204 static bool warned =
false;
1207 qWarning(
"Multisample renderbuffers are not supported, disabling MSAA for Offscreen View3D");
1213 if (m_layer->viewCount >= 2) {
1214 if (!m_multiViewDepthStencilBuffer) {
1215 const auto format = rhi->isTextureFormatSupported(QRhiTexture::D24S8) ? QRhiTexture::D24S8 : QRhiTexture::D32FS8;
1216 m_multiViewDepthStencilBuffer = rhi->newTextureArray(format, m_layer->viewCount, renderSize,
1217 m_samples, QRhiTexture::RenderTarget);
1218 m_multiViewDepthStencilBuffer->create();
1221 if (!m_depthStencilBuffer) {
1222 m_depthStencilBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, renderSize, m_samples);
1223 m_depthStencilBuffer->create();
1227 if (!m_textureRenderTarget) {
1228 QRhiTextureRenderTargetDescription rtDesc;
1229 QRhiColorAttachment att;
1230 if (m_samples > 1) {
1231 if (m_layer->viewCount >= 2) {
1232 m_msaaMultiViewRenderBuffer = rhi->newTextureArray(textureFormat, m_layer->viewCount, renderSize, m_samples, QRhiTexture::RenderTarget);
1233 m_msaaMultiViewRenderBuffer->create();
1234 att.setTexture(m_msaaMultiViewRenderBuffer);
1236 if (!rhi->isFeatureSupported(QRhi::MultisampleTexture)) {
1238 m_msaaRenderBufferLegacy = rhi->newRenderBuffer(QRhiRenderBuffer::Color, renderSize, m_samples, {}, m_texture->format());
1239 m_msaaRenderBufferLegacy->create();
1240 att.setRenderBuffer(m_msaaRenderBufferLegacy);
1247 m_msaaRenderTexture = rhi->newTexture(textureFormat, renderSize, m_samples, QRhiTexture::RenderTarget);
1248 m_msaaRenderTexture->create();
1249 att.setTexture(m_msaaRenderTexture);
1252 att.setResolveTexture(m_texture);
1254 if (m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA)
1255 att.setTexture(m_ssaaTexture);
1257 att.setTexture(m_texture);
1259 att.setMultiViewCount(m_layer->viewCount);
1260 rtDesc.setColorAttachments({ att });
1261 if (m_depthStencilBuffer)
1262 rtDesc.setDepthStencilBuffer(m_depthStencilBuffer);
1263 if (m_multiViewDepthStencilBuffer)
1264 rtDesc.setDepthTexture(m_multiViewDepthStencilBuffer);
1266 m_textureRenderTarget = rhi->newTextureRenderTarget(rtDesc);
1267 m_textureRenderTarget->setName(QByteArrayLiteral(
"View3D"));
1268 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
1269 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
1270 m_textureRenderTarget->create();
1273 if (!m_ssaaTextureToTextureRenderTarget && m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
1274 QRhiColorAttachment att(m_texture);
1275 att.setMultiViewCount(m_layer->viewCount);
1276 m_ssaaTextureToTextureRenderTarget = rhi->newTextureRenderTarget(QRhiTextureRenderTargetDescription({ att }));
1277 m_ssaaTextureToTextureRenderTarget->setName(QByteArrayLiteral(
"SSAA texture"));
1278 m_ssaaTextureToTextureRenderPassDescriptor = m_ssaaTextureToTextureRenderTarget->newCompatibleRenderPassDescriptor();
1279 m_ssaaTextureToTextureRenderTarget->setRenderPassDescriptor(m_ssaaTextureToTextureRenderPassDescriptor);
1280 m_ssaaTextureToTextureRenderTarget->create();
1283 if (m_layer->firstEffect) {
1284 if (!m_effectSystem)
1285 m_effectSystem =
new QSSGRhiEffectSystem(m_sgContext);
1286 m_effectSystem->setup(renderSize);
1287 }
else if (m_effectSystem) {
1288 delete m_effectSystem;
1289 m_effectSystem =
nullptr;
1292 if (m_timeBasedAA && !m_temporalAARenderTarget) {
1293 m_temporalAARenderTarget = rhi->newTextureRenderTarget({ m_temporalAATexture });
1294 m_temporalAARenderTarget->setName(QByteArrayLiteral(
"Temporal AA texture"));
1295 m_temporalAARenderPassDescriptor = m_temporalAARenderTarget->newCompatibleRenderPassDescriptor();
1296 m_temporalAARenderTarget->setRenderPassDescriptor(m_temporalAARenderPassDescriptor);
1297 m_temporalAARenderTarget->create();
1300 m_textureNeedsFlip = rhi->isYUpInFramebuffer();
1301 m_aaIsDirty =
false;
1305 m_renderStats->endSync(dumpRenderTimes());
1307 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DSynchronizeFrame, quint64(m_surfaceSize.width()) | quint64(m_surfaceSize.height()) << 32, profilingId);