47 QSSG_ASSERT(!data.renderedCameras.isEmpty(),
return);
48 camera = data.renderedCameras[0];
50 const auto &renderedDepthWriteObjects = data.getSortedRenderedDepthWriteObjects(*
camera);
51 const auto &renderedOpaqueDepthPrepassObjects = data.getSortedrenderedOpaqueDepthPrepassObjects(*
camera);
53 QSSG_ASSERT(shadowPassObjects.isEmpty(), shadowPassObjects.clear());
55 for (
const auto &handles : { &renderedDepthWriteObjects, &renderedOpaqueDepthPrepassObjects }) {
56 for (
const auto &handle : *handles) {
57 if (handle.obj->renderableFlags.castsShadows())
58 shadowPassObjects.push_back(handle);
62 globalLights = data.globalLights;
64 enabled = !shadowPassObjects.isEmpty() || !globalLights.isEmpty();
67 shadowMapManager = data.requestShadowMapManager();
69 ps = data.getPipelineState();
70 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
73 ps.slopeScaledDepthBias = 1.5f;
75 const auto &sortedOpaqueObjects = data.getSortedOpaqueRenderableObjects(*
camera);
76 const auto &sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*
camera);
77 const auto [casting, receiving] = calculateSortedObjectBounds(sortedOpaqueObjects,
78 sortedTransparentObjects);
79 castingObjectsBox = casting;
80 receivingObjectsBox = receiving;
83 debugCamera = std::make_unique<QSSGRenderCamera>(QSSGRenderGraphObject::Type::OrthographicCamera);
144 QSSG_ASSERT(!data.renderedCameras.isEmpty(),
return);
145 QSSGRenderCamera *camera = data.renderedCameras[0];
147 ps = data.getPipelineState();
148 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled,
149 QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
150 QSSGRhiGraphicsPipelineState::Flag::BlendEnabled };
152 reflectionProbes = { data.reflectionProbesView.begin(), data.reflectionProbesView.end() };
153 reflectionMapManager = data.requestReflectionMapManager();
155 const auto &sortedOpaqueObjects = data.getSortedOpaqueRenderableObjects(*camera);
156 const auto &sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
157 const auto &sortedScreenTextureObjects = data.getSortedScreenTextureRenderableObjects(*camera);
159 QSSG_ASSERT(reflectionPassObjects.isEmpty(), reflectionPassObjects.clear());
163 for (
const auto &handles : { &sortedOpaqueObjects, &sortedTransparentObjects, &sortedScreenTextureObjects }) {
164 for (
const auto &handle : *handles) {
165 if (handle.obj->renderableFlags.testFlag(QSSGRenderableObjectFlag::CastsReflections))
166 reflectionPassObjects.push_back(handle);
236 QSSG_ASSERT(!data.renderedCameras.isEmpty(),
return);
237 QSSGRenderCamera *camera = data.renderedCameras[0];
239 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
240 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
241 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
242 ps = data.getPipelineState();
244 renderedDepthWriteObjects = data.getSortedRenderedDepthWriteObjects(*camera);
245 renderedOpaqueDepthPrepassObjects = data.getSortedrenderedOpaqueDepthPrepassObjects(*camera);
247 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D prepare Z prepass"));
248 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"Quick3D prepare Z prepass"));
249 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
250 active = rhiPrepareDepthPass(rhiCtx.get(),
this, ps, rhiCtx->mainRenderPassDescriptor(), data,
251 renderedDepthWriteObjects, renderedOpaqueDepthPrepassObjects,
252 rhiCtx->mainPassSampleCount(), data.layer.viewCount);
253 data.setZPrePassPrepResult(
active);
255 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"prepare_z_prepass"));
295 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
296 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
298 rhiAoTexture = data.getRenderResult(QSSGFrameData::RenderResult::AoTexture);
299 rhiDepthTexture = data.getRenderResult(QSSGFrameData::RenderResult::DepthTexture);
300 QSSG_ASSERT_X(!data.renderedCameras.isEmpty(),
"Preparing AO pass failed, missing camera",
return);
301 camera = data.renderedCameras[0];
302 QSSG_ASSERT_X((rhiDepthTexture && rhiDepthTexture->isValid()),
"Preparing AO pass failed, missing equired texture(s)",
return);
304 const auto &shaderCache = renderer.contextInterface()->shaderCache();
305 ssaoShaderPipeline = shaderCache->getBuiltInRhiShaders().getRhiSsaoShader(data.layer.viewCount);
306 aoSettings = { data.layer.aoStrength, data.layer.aoDistance, data.layer.aoSoftness, data.layer.aoBias, data.layer.aoSamplerate, data.layer.aoDither };
308 ps = data.getPipelineState();
309 const auto &layerPrepResult = data.layerPrepResult;
310 const bool ready = rhiAoTexture && rhiPrepareAoTexture(rhiCtx.get(), layerPrepResult.textureDimensions(), rhiAoTexture, data.layer.viewCount);
312 if (Q_UNLIKELY(!ready))
313 rhiAoTexture =
nullptr;
365void DepthMapPass::renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data)
367 using namespace RenderHelpers;
369 QSSG_ASSERT(!data.renderedCameras.isEmpty(),
return);
370 QSSGRenderCamera *camera = data.renderedCameras[0];
372 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
373 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
374 const auto &layerPrepResult = data.layerPrepResult;
376 ps = data.getPipelineState();
378 if (m_multisampling) {
379 ps.samples = rhiCtx->mainPassSampleCount();
380 rhiDepthTexture = data.getRenderResult(QSSGFrameData::RenderResult::DepthTextureMS);
383 rhiDepthTexture = data.getRenderResult(QSSGFrameData::RenderResult::DepthTexture);
386 if (Q_LIKELY(rhiDepthTexture && rhiPrepareDepthTexture(rhiCtx.get(), layerPrepResult.textureDimensions(), rhiDepthTexture, data.layer.viewCount, ps.samples))) {
387 sortedOpaqueObjects = data.getSortedOpaqueRenderableObjects(*camera);
388 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
390 ready = rhiPrepareDepthPass(rhiCtx.get(),
this, ps, rhiDepthTexture->rpDesc, data,
391 sortedOpaqueObjects, sortedTransparentObjects,
392 ps.samples, data.layer.viewCount);
395 if (Q_UNLIKELY(!ready))
396 rhiDepthTexture =
nullptr;
399void DepthMapPass::renderPass(QSSGRenderer &renderer)
401 using namespace RenderHelpers;
419 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
420 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
421 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
422 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D depth texture"));
424 if (Q_LIKELY(rhiDepthTexture && rhiDepthTexture->isValid())) {
425 bool needsSetViewport =
true;
426 cb->beginPass(rhiDepthTexture->rt, Qt::transparent, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
427 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rhiDepthTexture->rt));
428 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
436 rhiRenderDepthPass(rhiCtx.get(), ps, sortedOpaqueObjects, {}, &needsSetViewport);
438 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
439 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"depth_texture"));
455void NormalPass::renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data)
457 using namespace RenderHelpers;
459 QSSG_ASSERT(!data.renderedCameras.isEmpty(),
return);
460 QSSGRenderCamera *camera = data.renderedCameras[0];
462 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
463 QRhi *rhi = rhiCtx->rhi();
465 const auto &layerPrepResult = data.layerPrepResult;
472 ps = data.getPipelineState();
476 sortedOpaqueObjects = data.getSortedOpaqueRenderableObjects(*camera);
480 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
481 shaderFeatures.set(QSSGShaderFeatures::Feature::NormalPass,
true);
483 normalTexture = data.getRenderResult(QSSGFrameData::RenderResult::NormalTexture);
485 const QSize size = layerPrepResult.textureDimensions();
486 bool needsBuild =
false;
488 if (!normalTexture->texture) {
489 QRhiTexture::Format format = QRhiTexture::RGBA16F;
490 if (!rhi->isTextureFormatSupported(format)) {
491 qWarning(
"No float formats, not great");
492 format = QRhiTexture::RGBA8;
494 normalTexture->texture = rhiCtx->rhi()->newTexture(format, size, 1, QRhiTexture::RenderTarget);
496 normalTexture->texture->setName(QByteArrayLiteral(
"Normal texture"));
497 }
else if (normalTexture->texture->pixelSize() != size) {
498 normalTexture->texture->setPixelSize(size);
502 if (!normalTexture->depthStencil) {
503 normalTexture->depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size);
505 }
else if (normalTexture->depthStencil->pixelSize() != size) {
506 normalTexture->depthStencil->setPixelSize(size);
511 if (!normalTexture->texture->create()) {
512 qWarning(
"Failed to build normal texture (size %dx%d, format %d)",
513 size.width(), size.height(),
int(normalTexture->texture->format()));
514 normalTexture->reset();
518 if (!normalTexture->depthStencil->create()) {
519 qWarning(
"Failed to build depth-stencil buffer for normal texture (size %dx%d)",
520 size.width(), size.height());
521 normalTexture->reset();
525 normalTexture->resetRenderTarget();
527 QRhiTextureRenderTargetDescription rtDesc;
528 QRhiColorAttachment colorAttachment(normalTexture->texture);
529 rtDesc.setColorAttachments({ colorAttachment });
530 rtDesc.setDepthStencilBuffer(normalTexture->depthStencil);
532 normalTexture->rt = rhi->newTextureRenderTarget(rtDesc);
533 normalTexture->rt->setName(QByteArrayLiteral(
"Normal texture RT"));
534 normalTexture->rpDesc = normalTexture->rt->newCompatibleRenderPassDescriptor();
535 normalTexture->rt->setRenderPassDescriptor(normalTexture->rpDesc);
536 if (!normalTexture->rt->create()) {
537 qWarning(
"Failed to build render target for normal texture");
538 normalTexture->reset();
543 rhiPrepareNormalPass(rhiCtx.get(),
this, ps, normalTexture->rpDesc, data, sortedOpaqueObjects);
546void NormalPass::renderPass(QSSGRenderer &renderer)
548 using namespace RenderHelpers;
550 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
551 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
552 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
553 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D normal texture"));
555 if (Q_LIKELY(normalTexture && normalTexture->isValid())) {
556 bool needsSetViewport =
true;
557 cb->beginPass(normalTexture->rt, Qt::transparent, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
558 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(normalTexture->rt));
559 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
561 rhiRenderNormalPass(rhiCtx.get(), ps, sortedOpaqueObjects, &needsSetViewport);
564 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
565 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"normal_texture"));
585 QSSG_ASSERT(!data.renderedCameras.isEmpty(),
return);
586 QSSGRenderCamera *camera = data.renderedCameras[0];
588 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
589 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
590 rhiScreenTexture = data.getRenderResult(QSSGFrameData::RenderResult::ScreenTexture);
591 auto &layer = data.layer;
592 const auto &layerPrepResult = data.layerPrepResult;
593 wantsMips = layerPrepResult.getFlags().requiresMipmapsForScreenTexture();
594 sortedOpaqueObjects = data.getSortedOpaqueRenderableObjects(*camera);
595 ps = data.getPipelineState();
597 ps.viewCount = data.layer.viewCount;
599 if (layer.background == QSSGRenderLayer::Background::Color)
600 clearColor = QColor::fromRgbF(layer.clearColor.x(), layer.clearColor.y(), layer.clearColor.z());
602 if (rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
603 if (layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap && layer.skyBoxCubeMap) {
604 if (!skyboxCubeMapPass)
605 skyboxCubeMapPass = SkyboxCubeMapPass();
607 skyboxCubeMapPass->skipTonemapping =
true;
608 skyboxCubeMapPass->renderPrep(renderer, data);
613 skyboxCubeMapPass->ps.samples = ps.samples;
615 skyboxPass = std::nullopt;
616 }
else if (layer.background == QSSGRenderLayer::Background::SkyBox && layer.lightProbe) {
618 skyboxPass = SkyboxPass();
620 skyboxPass->skipTonemapping =
true;
621 skyboxPass->renderPrep(renderer, data);
623 skyboxPass->ps.samples = ps.samples;
625 skyboxCubeMapPass = std::nullopt;
630 if (Q_LIKELY(rhiScreenTexture && rhiPrepareScreenTexture(rhiCtx.get(), layerPrepResult.textureDimensions(), wantsMips, rhiScreenTexture, layer.viewCount))) {
632 if (skyboxCubeMapPass)
633 skyboxCubeMapPass->rpDesc = rhiScreenTexture->rpDesc;
635 skyboxPass->rpDesc = rhiScreenTexture->rpDesc;
639 shaderFeatures = data.getShaderFeatures();
640 shaderFeatures.disableTonemapping();
641 const auto &sortedOpaqueObjects = data.getSortedOpaqueRenderableObjects(*camera);
642 for (
const auto &handle : sortedOpaqueObjects) {
644 bool recRef = handle.obj->renderableFlags.receivesReflections();
645 handle.obj->renderableFlags.setReceivesReflections(
false);
646 rhiPrepareRenderable(rhiCtx.get(),
this, data, *handle.obj, rhiScreenTexture->rpDesc, &ps, shaderFeatures, 1, data.layer.viewCount);
647 handle.obj->renderableFlags.setReceivesReflections(recRef);
651 if (Q_UNLIKELY(!ready))
652 rhiScreenTexture =
nullptr;
669 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
670 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
671 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
673 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D screen texture"));
675 if (Q_LIKELY(rhiScreenTexture && rhiScreenTexture->isValid())) {
676 cb->beginPass(rhiScreenTexture->rt, clearColor, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
677 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rhiScreenTexture->rt));
678 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
680 bool needsSetViewport =
true;
681 for (
const auto &handle : std::as_const(sortedOpaqueObjects))
682 rhiRenderRenderable(rhiCtx.get(), ps, *handle.obj, &needsSetViewport);
684 if (skyboxCubeMapPass)
685 skyboxCubeMapPass->renderPass(renderer);
687 skyboxPass->renderPass(renderer);
689 QRhiResourceUpdateBatch *rub =
nullptr;
691 rub = rhiCtx->rhi()->nextResourceUpdateBatch();
692 rub->generateMips(rhiScreenTexture->texture);
695 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
696 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"screen_texture"));
718 QSSG_ASSERT(!data.renderedCameras.isEmpty(),
return);
719 QSSGRenderCamera *camera = data.renderedCameras[0];
721 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
722 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
723 rhiScreenTexture = data.getRenderResult(QSSGFrameData::RenderResult::ScreenTexture);
724 QSSG_ASSERT_X(rhiScreenTexture && rhiScreenTexture->isValid(),
"Invalid screen texture!",
return);
726 const auto &layer = data.layer;
727 const auto shaderFeatures = data.getShaderFeatures();
728 const bool layerEnableDepthTest = layer.layerFlags.testFlag(QSSGRenderLayer::LayerFlag::EnableDepthTest);
730 QRhiRenderPassDescriptor *mainRpDesc = rhiCtx->mainRenderPassDescriptor();
731 const int samples = rhiCtx->mainPassSampleCount();
732 const int viewCount = data.layer.viewCount;
735 ps = data.getPipelineState();
736 const bool depthTestEnabled = (data.screenMapPass.ps.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled));
737 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, depthTestEnabled);
738 const bool depthWriteEnabled = (data.screenMapPass.ps.flags.testFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled));
739 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, depthWriteEnabled);
740 sortedScreenTextureObjects = data.getSortedScreenTextureRenderableObjects(*camera);
741 for (
const auto &handle : std::as_const(sortedScreenTextureObjects)) {
742 QSSGRenderableObject *theObject = handle.obj;
743 const auto depthWriteMode = theObject->depthWriteMode;
744 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled, theObject->renderableFlags.hasTransparency());
745 const bool curDepthWriteEnabled = !(depthWriteMode == QSSGDepthDrawMode::Never || depthWriteMode == QSSGDepthDrawMode::OpaquePrePass
746 || data.isZPrePassActive() || !layerEnableDepthTest);
747 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, curDepthWriteEnabled);
748 RenderHelpers::rhiPrepareRenderable(rhiCtx.get(),
this, data, *theObject, mainRpDesc, &ps, shaderFeatures, samples, viewCount);
784 QSSGRhiGraphicsPipelineState &ps,
785 QSSGShaderFeatures shaderFeatures,
786 QRhiRenderPassDescriptor *rpDesc,
787 const QSSGRenderableObjectList &sortedOpaqueObjects)
789 const auto &rhiCtx = ctx.rhiContext();
790 QSSG_ASSERT(rpDesc && rhiCtx->rhi()->isRecordingFrame(),
return);
792 const auto &layer = data.layer;
793 const bool layerEnableDepthTest = layer.layerFlags.testFlag(QSSGRenderLayer::LayerFlag::EnableDepthTest);
795 for (
const auto &handle : std::as_const(sortedOpaqueObjects)) {
796 QSSGRenderableObject *theObject = handle.obj;
797 const auto depthWriteMode = theObject->depthWriteMode;
798 const bool curDepthWriteEnabled = !(depthWriteMode == QSSGDepthDrawMode::Never ||
799 depthWriteMode == QSSGDepthDrawMode::OpaquePrePass ||
800 data.isZPrePassActive() || !layerEnableDepthTest);
801 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, curDepthWriteEnabled);
802 RenderHelpers::rhiPrepareRenderable(rhiCtx.get(), passKey, data, *theObject, rpDesc, &ps, shaderFeatures, ps.samples, ps.viewCount);
821 auto *ctx = renderer.contextInterface();
822 const auto &rhiCtx = ctx->rhiContext();
823 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
824 QSSG_ASSERT(!data.renderedCameras.isEmpty() && data.renderedCameraData.has_value() ,
return);
825 QSSGRenderCamera *camera = data.renderedCameras[0];
827 ps = data.getPipelineState();
828 ps.samples = rhiCtx->mainPassSampleCount();
829 ps.viewCount = data.layer.viewCount;
830 ps.depthFunc = QRhiGraphicsPipeline::LessOrEqual;
831 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
834 sortedOpaqueObjects = data.getSortedOpaqueRenderableObjects(*camera);
835 shaderFeatures = data.getShaderFeatures();
837 QRhiRenderPassDescriptor *mainRpDesc = rhiCtx->mainRenderPassDescriptor();
838 prep(*ctx, data,
this, ps, shaderFeatures, mainRpDesc, sortedOpaqueObjects);
867 QSSGRhiGraphicsPipelineState &ps,
868 QSSGShaderFeatures shaderFeatures,
869 QRhiRenderPassDescriptor *rpDesc,
870 const QSSGRenderableObjectList &sortedTransparentObjects,
873 const auto &rhiCtx = ctx.rhiContext();
874 QSSG_ASSERT(rpDesc && rhiCtx->rhi()->isRecordingFrame(),
return);
876 const bool zPrePassActive = data.isZPrePassActive();
877 for (
const auto &handle : std::as_const(sortedTransparentObjects)) {
878 QSSGRenderableObject *theObject = handle.obj;
879 const auto depthWriteMode = theObject->depthWriteMode;
880 const bool curDepthWriteEnabled = (depthWriteMode == QSSGDepthDrawMode::Always && !zPrePassActive);
881 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, curDepthWriteEnabled);
882 if (!(theObject->renderableFlags.isCompletelyTransparent())) {
883 RenderHelpers::rhiPrepareRenderable(rhiCtx.get(), passKey, data, *theObject, rpDesc, &ps, shaderFeatures,
884 ps.samples, ps.viewCount,
nullptr,
nullptr, QSSGRenderTextureCubeFaceNone,
nullptr, oit);
908 auto *ctx = renderer.contextInterface();
909 const auto &rhiCtx = ctx->rhiContext();
911 QSSG_ASSERT(!data.renderedCameras.isEmpty() && data.renderedCameraData.has_value() ,
return);
912 QSSGRenderCamera *camera = data.renderedCameras[0];
914 QRhiRenderPassDescriptor *mainRpDesc = rhiCtx->mainRenderPassDescriptor();
916 ps = data.getPipelineState();
917 ps.samples = rhiCtx->mainPassSampleCount();
918 ps.viewCount = data.layer.viewCount;
921 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
922 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
924 shaderFeatures = data.getShaderFeatures();
925 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
927 prep(*ctx, data,
this, ps, shaderFeatures, mainRpDesc, sortedTransparentObjects);
981 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
982 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
985 QRhiShaderResourceBindings *srb = layer->skyBoxSrb;
988 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
989 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"Quick3D render skybox"));
994 QSSGRenderLayer::TonemapMode tonemapMode = skipTonemapping && (layer->tonemapMode != QSSGRenderLayer::TonemapMode::Custom) ? QSSGRenderLayer::TonemapMode::None : layer->tonemapMode;
995 const auto &shaderCache = renderer.contextInterface()->shaderCache();
996 auto shaderPipeline = shaderCache->getBuiltInRhiShaders().getRhiSkyBoxShader(tonemapMode, layer->skyBoxIsRgbe8, layer->viewCount);
998 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
999 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rpDesc, { QSSGRhiQuadRenderer::DepthTest | QSSGRhiQuadRenderer::RenderBehind });
1000 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"skybox_map"));
1056 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1057 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1058 const auto &layer = data.layer;
1060 const auto &item2Ds = data.getRenderableItem2Ds();
1061 prepdItem2DRenderers.reserve(size_t(item2Ds.size()));
1066 renderer.beginSubLayerRender(data);
1067 const auto &rpd = data.getItem2DRenderPassDescriptor();
1069 for (
const auto *item2D: std::as_const(item2Ds)) {
1071 auto item2DData = data.getItem2DRenderer(*item2D);
1072 const auto &mvps = data.getItem2DMvps(*item2D);
1073 QSGRenderer *renderer2d = item2DData;
1078 if (renderer2d && renderer2d->currentRhi() != rhiCtx->rhi()) {
1079 static bool contextWarningShown =
false;
1080 if (!contextWarningShown) {
1081 qWarning () <<
"Scene with embedded 2D content can only be rendered in one window.";
1082 contextWarningShown =
true;
1089 auto layerPrepResult = data.layerPrepResult;
1091 QRhiRenderTarget *renderTarget = rhiCtx->renderTarget();
1092 renderer2d->setDevicePixelRatio(renderTarget->devicePixelRatio());
1093 const QRect deviceRect(QPoint(0, 0), renderTarget->pixelSize());
1094 const int viewCount = data.layer.viewCount;
1095 if (layer.scissorRect.isValid()) {
1096 QRect effScissor = layer.scissorRect & layerPrepResult.getViewport().toRect();
1097 QMatrix4x4 correctionMat = correctMVPForScissor(layerPrepResult.getViewport(),
1099 rhiCtx->rhi()->isYUpInNDC());
1100 for (
int viewIndex = 0; viewIndex < viewCount; ++viewIndex) {
1101 const QMatrix4x4 projectionMatrix = correctionMat * mvps[viewIndex];
1102 renderer2d->setProjectionMatrix(projectionMatrix, viewIndex);
1104 renderer2d->setViewportRect(effScissor);
1106 for (
int viewIndex = 0; viewIndex < viewCount; ++viewIndex)
1107 renderer2d->setProjectionMatrix(mvps[viewIndex], viewIndex);
1108 renderer2d->setViewportRect(RenderHelpers::correctViewportCoordinates(layerPrepResult.getViewport(), deviceRect));
1110 renderer2d->setDeviceRect(deviceRect);
1111 QSGRenderTarget sgRt(renderTarget, rpd.get(), rhiCtx->commandBuffer());
1112 sgRt.multiViewCount = data.layer.viewCount;
1113 renderer2d->setRenderTarget(sgRt);
1114 renderer2d->prepareSceneInline();
1115 prepdItem2DRenderers.push_back(renderer2d);
1117 renderer.endSubLayerRender(data);
1147 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1148 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1149 QSSG_ASSERT(!data.renderedCameras.isEmpty(),
return);
1150 QSSG_ASSERT(data.renderedCameras.count() == data.layer.viewCount,
return);
1151 layer = &data.layer;
1154 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1155 gridShader = shaderCache->getBuiltInRhiShaders().getRhiGridShader(data.layer.viewCount);
1157 ps = data.getPipelineState();
1158 ps.samples = rhiCtx->mainPassSampleCount();
1159 ps.viewCount = data.layer.viewCount;
1160 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1161 ps.polygonMode = QRhiGraphicsPipeline::Fill;
1163 RenderHelpers::rhiPrepareGrid(rhiCtx.get(),
this, *layer, data.renderedCameras, renderer);
1168 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1169 QSSG_ASSERT(gridShader && rhiCtx->rhi()->isRecordingFrame(),
return);
1170 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1172 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D render grid"));
1173 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1174 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"Quick3D render grid"));
1175 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, gridShader.get());
1176 QRhiShaderResourceBindings *srb = layer->gridSrb;
1177 QRhiRenderPassDescriptor *rpDesc = rhiCtx->mainRenderPassDescriptor();
1178 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rpDesc, { QSSGRhiQuadRenderer::DepthTest });
1179 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"render_grid"));
1190 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1191 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1192 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1193 QSSG_ASSERT(!data.renderedCameras.isEmpty(),
return);
1194 QSSG_ASSERT(data.renderedCameras.count() == data.layer.viewCount,
return);
1196 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1197 debugObjectShader = shaderCache->getBuiltInRhiShaders().getRhiDebugObjectShader(data.layer.viewCount);
1198 ps = data.getPipelineState();
1199 ps.samples = rhiCtx->mainPassSampleCount();
1200 ps.viewCount = data.layer.viewCount;
1203 const auto &debugDraw = renderer.contextInterface()->debugDrawSystem();
1204 if (debugDraw && debugDraw->hasContent()) {
1205 QRhi *rhi = rhiCtx->rhi();
1206 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
1207 debugDraw->prepareGeometry(rhiCtx.get(), rub);
1208 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({
this,
nullptr,
nullptr, 0 });
1210 dcd.ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 * data.renderedCameras.count());
1213 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
1214 QMatrix4x4 viewProjection(Qt::Uninitialized);
1215 QMatrix4x4 cameraGlobalTransform(Qt::Uninitialized);
1216 for (qsizetype viewIdx = 0; viewIdx < data.renderedCameras.count(); ++viewIdx) {
1217 cameraGlobalTransform = data.getGlobalTransform(*data.renderedCameras[viewIdx]);
1218 data.renderedCameras[viewIdx]->calculateViewProjectionMatrix(cameraGlobalTransform, viewProjection);
1219 viewProjection = rhi->clipSpaceCorrMatrix() * viewProjection;
1220 memcpy(ubufData, viewProjection.constData() + viewIdx * 64, 64);
1222 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
1224 QSSGRhiShaderResourceBindingList bindings;
1225 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::VertexStage, dcd.ubuf);
1226 dcd.srb = rhiCtxD->srb(bindings);
1228 rhiCtx->commandBuffer()->resourceUpdate(rub);
1234 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1235 QSSG_ASSERT(debugObjectShader && rhiCtx->rhi()->isRecordingFrame(),
return);
1236 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1237 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1239 const auto &debugDraw = renderer.contextInterface()->debugDrawSystem();
1240 if (debugDraw && debugDraw->hasContent()) {
1241 cb->debugMarkBegin(QByteArrayLiteral(
"Quick 3D debug objects"));
1242 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral(
"Quick 3D debug objects"));
1243 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1244 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, debugObjectShader.get());
1245 QSSGRhiDrawCallData &dcd = rhiCtxD->drawCallData({
this,
nullptr,
nullptr, 0 });
1246 QRhiShaderResourceBindings *srb = dcd.srb;
1247 QRhiRenderPassDescriptor *rpDesc = rhiCtx->mainRenderPassDescriptor();
1248 debugDraw->recordRenderDebugObjects(rhiCtx.get(), &ps, srb, rpDesc);
1250 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"debug_objects"));
1292 auto *ctx = renderer.contextInterface();
1293 const auto &rhiCtx = ctx->rhiContext();
1294 auto *rhi = rhiCtx->rhi();
1296 QSSG_ASSERT(!data.renderedCameras.isEmpty() && data.renderedCameraData.has_value() ,
return);
1297 QSSGRenderCamera *camera = data.renderedCameras[0];
1299 ps = data.getPipelineState();
1300 ps.samples = rhiCtx->mainPassSampleCount();
1301 ps.viewCount = rhiCtx->mainPassViewCount();
1303 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1304 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1306 shaderFeatures = data.getShaderFeatures();
1307 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
1309 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1310 ps.colorAttachmentCount = 2;
1312 rhiAccumTexture = data.getRenderResult(QSSGFrameData::RenderResult::AccumTexture);
1313 rhiRevealageTexture = data.getRenderResult(QSSGFrameData::RenderResult::RevealageTexture);
1315 rhiDepthTexture = data.getRenderResult(QSSGFrameData::RenderResult::DepthTextureMS);
1317 rhiDepthTexture = data.getRenderResult(QSSGFrameData::RenderResult::DepthTexture);
1318 if (!rhiDepthTexture->isValid())
1320 auto &oitrt = data.getOitRenderContext();
1321 if (!oitrt.oitRenderTarget || oitrt.oitRenderTarget->pixelSize() != data.layerPrepResult.textureDimensions()
1322 || rhiDepthTexture->texture != oitrt.oitRenderTarget->description().depthTexture()
1323 || ps.samples != oitrt.oitRenderTarget->sampleCount()) {
1324 if (oitrt.oitRenderTarget) {
1325 rhiAccumTexture->texture->destroy();
1326 rhiRevealageTexture->texture->destroy();
1327 oitrt.oitRenderTarget->destroy();
1328 oitrt.renderPassDescriptor->destroy();
1329 oitrt.oitRenderTarget =
nullptr;
1331 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget;
1332 if (ps.viewCount >= 2) {
1333 rhiAccumTexture->texture = rhi->newTextureArray(QRhiTexture::RGBA16F, ps.viewCount, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1334 rhiRevealageTexture->texture = rhi->newTextureArray(QRhiTexture::R16F, ps.viewCount, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1336 rhiAccumTexture->texture = rhi->newTexture(QRhiTexture::RGBA16F, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1337 rhiRevealageTexture->texture = rhi->newTexture(QRhiTexture::R16F, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1339 rhiAccumTexture->texture->create();
1340 rhiRevealageTexture->texture->create();
1342 QRhiTextureRenderTargetDescription desc;
1343 desc.setColorAttachments({{rhiAccumTexture->texture}, {rhiRevealageTexture->texture}});
1344 desc.setDepthTexture(rhiDepthTexture->texture);
1346 if (oitrt.oitRenderTarget ==
nullptr) {
1347 oitrt.oitRenderTarget = rhi->newTextureRenderTarget(desc, QRhiTextureRenderTarget::PreserveDepthStencilContents);
1348 oitrt.renderPassDescriptor = oitrt.oitRenderTarget->newCompatibleRenderPassDescriptor();
1349 oitrt.oitRenderTarget->setRenderPassDescriptor(oitrt.renderPassDescriptor);
1350 oitrt.oitRenderTarget->create();
1352 renderTarget = oitrt.oitRenderTarget;
1355 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1356 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1357 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearMRTShader();
1359 QSSGRhiShaderResourceBindingList bindings;
1360 QVector4D clearData[2];
1361 clearData[0] = QVector4D(0.0, 0.0, 0.0, 0.0);
1362 clearData[1] = QVector4D(1.0, 1.0, 1.0, 1.0);
1364 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this,
nullptr,
nullptr, 0 }));
1365 QRhiBuffer *&ubuf = dcd.ubuf;
1366 const int ubufSize =
sizeof(clearData);
1368 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
1372 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
1373 rub->updateDynamicBuffer(ubuf, 0, ubufSize, &clearData);
1374 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx.get(), rub);
1376 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1378 clearSrb = rhiCtxD->srb(bindings);
1380 ps.targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One;
1381 ps.targetBlend[0].srcColor = QRhiGraphicsPipeline::One;
1382 ps.targetBlend[0].dstAlpha = QRhiGraphicsPipeline::One;
1383 ps.targetBlend[0].dstColor = QRhiGraphicsPipeline::One;
1384 ps.targetBlend[1].srcAlpha = QRhiGraphicsPipeline::Zero;
1385 ps.targetBlend[1].srcColor = QRhiGraphicsPipeline::Zero;
1386 ps.targetBlend[1].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1387 ps.targetBlend[1].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1389 TransparentPass::prep(*ctx, data,
this, ps, shaderFeatures, oitrt.renderPassDescriptor, sortedTransparentObjects,
true);
1395 auto *ctx = renderer.contextInterface();
1396 const auto &rhiCtx = ctx->rhiContext();
1397 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1398 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1400 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1401 if (Q_LIKELY(renderTarget)) {
1402 cb->beginPass(renderTarget, Qt::black, {});
1404 QRhiShaderResourceBindings *srb = clearSrb;
1406 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
1407 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, clearPipeline.get());
1408 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, renderTarget->renderPassDescriptor(), {});
1409 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1411 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D render order-independent alpha"));
1412 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1413 Q_TRACE(QSSG_renderPass_entry, QStringLiteral(
"Quick3D render order-independent alpha"));
1414 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled,
true);
1415 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1416 TransparentPass::render(*ctx, ps, sortedTransparentObjects);
1418 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"transparent_order_independent_pass"));
1419 Q_TRACE(QSSG_renderPass_exit);
1469 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1470 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1471 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1473 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1475 if (!rhiAccumTexture->texture || !rhiRevealageTexture->texture)
1478 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1479 QSSGRhiShaderResourceBindingList bindings;
1481 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest,
1482 QRhiSampler::Nearest,
1484 QRhiSampler::ClampToEdge,
1485 QRhiSampler::ClampToEdge,
1486 QRhiSampler::ClampToEdge });
1487 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, rhiAccumTexture->texture, sampler);
1488 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, rhiRevealageTexture->texture, sampler);
1490 compositeSrb = rhiCtxD->srb(bindings);
1492 QRhiShaderResourceBindings *srb = compositeSrb;
1495 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D revealage"));
1496 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, compositeShaderPipeline.get());
1497 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1498 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(),
1499 { QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::DepthTest | QSSGRhiQuadRenderer::PremulBlend});
1500 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"revealage"));