Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qssgrenderpass.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
9#include "extensionapi/qssgrenderextensions.h"
11
12#include "../utils/qssgassert_p.h"
13
14#include <QtQuick/private/qsgrenderer_p.h>
15#include <qtquick3d_tracepoints_p.h>
16
18
19static inline QMatrix4x4 correctMVPForScissor(QRectF viewportRect, QRect scissorRect, bool isYUp) {
20 const auto &scissorCenter = scissorRect.center();
21 const auto &viewCenter = viewportRect.center();
22 const float scaleX = viewportRect.width() / float(scissorRect.width());
23 const float scaleY = viewportRect.height() / float(scissorRect.height());
24 const float dx = 2 * (viewCenter.x() - scissorCenter.x()) / scissorRect.width();
25 const float dyRect = isYUp ? (scissorCenter.y() - viewCenter.y())
26 : (viewCenter.y() - scissorCenter.y());
27 const float dy = 2 * dyRect / scissorRect.height();
28
29 return QMatrix4x4(scaleX, 0.0f, 0.0f, dx,
30 0.0f, scaleY, 0.0f, dy,
31 0.0f, 0.0f, 1.0f, 0.0f,
32 0.0f, 0.0f, 0.0f, 1.0f);
33}
34
39
40// SHADOW PASS
41
43{
44 Q_UNUSED(renderer)
45 using namespace RenderHelpers;
46
47 QSSG_ASSERT(!data.renderedCameras.isEmpty(), return);
48 camera = data.renderedCameras[0];
49
50 const auto &renderedDepthWriteObjects = data.getSortedRenderedDepthWriteObjects(*camera);
51 const auto &renderedOpaqueDepthPrepassObjects = data.getSortedrenderedOpaqueDepthPrepassObjects(*camera);
52
53 QSSG_ASSERT(shadowPassObjects.isEmpty(), shadowPassObjects.clear());
54
55 for (const auto &handles : { &renderedDepthWriteObjects, &renderedOpaqueDepthPrepassObjects }) {
56 for (const auto &handle : *handles) {
57 if (handle.obj->renderableFlags.castsShadows())
58 shadowPassObjects.push_back(handle);
59 }
60 }
61
62 globalLights = data.globalLights;
63
64 enabled = !shadowPassObjects.isEmpty() || !globalLights.isEmpty();
65
66 if (enabled) {
67 shadowMapManager = data.requestShadowMapManager();
68
69 ps = data.getPipelineState();
70 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled };
71 // Try reducing self-shadowing and artifacts.
72 ps.depthBias = 2;
73 ps.slopeScaledDepthBias = 1.5f;
74
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;
81
82 if (!debugCamera) {
83 debugCamera = std::make_unique<QSSGRenderCamera>(QSSGRenderGraphObject::Type::OrthographicCamera);
84 }
85 }
86}
87
89{
90 using namespace RenderHelpers;
91
92 // INPUT: Sorted opaque and transparent + depth, global lights (scoped lights not supported) and camera.
93
94 // DEPENDECY: None
95
96 // OUTPUT: Texture (Shadowmap Texture Atlas)
97
98 // CONDITION: Lights (shadowPassObjects)
99
100 if (enabled) {
101 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
102 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
103 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
104 cb->debugMarkBegin(QByteArrayLiteral("Quick3D shadow map"));
105 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral("Quick3D shadow map"));
106 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
107
108 QSSG_CHECK(shadowMapManager);
109 rhiRenderShadowMap(rhiCtx.get(),
110 this,
111 ps,
112 *shadowMapManager,
113 *camera,
114 debugCamera.get(),
115 globalLights, // scoped lights are not relevant here
116 shadowPassObjects,
117 renderer,
118 castingObjectsBox,
119 receivingObjectsBox);
120
121 cb->debugMarkEnd();
122 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("shadow_map"));
123 }
124}
125
127{
128 enabled = false;
129 camera = nullptr;
130 castingObjectsBox = {};
131 receivingObjectsBox = {};
132 ps = {};
133 shadowPassObjects.clear();
134 globalLights.clear();
135}
136
137// REFLECTIONMAP PASS
138
140{
141 Q_UNUSED(renderer);
142 Q_UNUSED(data);
143
144 QSSG_ASSERT(!data.renderedCameras.isEmpty(), return);
145 QSSGRenderCamera *camera = data.renderedCameras[0];
146
147 ps = data.getPipelineState();
148 ps.flags |= { QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled,
149 QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
150 QSSGRhiGraphicsPipelineState::Flag::BlendEnabled };
151
152 reflectionProbes = { data.reflectionProbesView.begin(), data.reflectionProbesView.end() };
153 reflectionMapManager = data.requestReflectionMapManager();
154
155 const auto &sortedOpaqueObjects = data.getSortedOpaqueRenderableObjects(*camera);
156 const auto &sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
157 const auto &sortedScreenTextureObjects = data.getSortedScreenTextureRenderableObjects(*camera);
158
159 QSSG_ASSERT(reflectionPassObjects.isEmpty(), reflectionPassObjects.clear());
160
161 // NOTE: We should consider keeping track of the reflection casting objects to avoid
162 // filtering this list on each prep.
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);
167 }
168 }
169}
170
172{
173 using namespace RenderHelpers;
174
175 // INPUT: Reflection probes, sorted opaque and transparent
176
177 // DEPENDECY: None
178
179 // OUTPUT: Cube maps (1 per probe)
180
181 // NOTE: Full pass with a sky box pass
182
183 // CONDITION: Probes and sorted opaque and transparent
184
185 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
186 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
187 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
188
189 const auto *layerData = QSSGLayerRenderData::getCurrent(renderer);
190 QSSG_ASSERT(layerData, return);
191
192 QSSG_CHECK(reflectionMapManager);
193 if (!reflectionPassObjects.isEmpty() || !reflectionProbes.isEmpty()) {
194 cb->debugMarkBegin(QByteArrayLiteral("Quick3D reflection map"));
195 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral("Quick3D reflection map"));
196 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
197 rhiRenderReflectionMap(rhiCtx.get(),
198 this,
199 *layerData,
200 &ps,
201 *reflectionMapManager,
202 reflectionProbes,
203 reflectionPassObjects,
204 renderer);
205
206 cb->debugMarkEnd();
207 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("reflection_map"));
208 }
209}
210
212{
213 ps = {};
214 reflectionProbes.clear();
215 reflectionPassObjects.clear();
216}
217
218// ZPrePass
220{
221 using namespace RenderHelpers;
222
223 // INPUT: Item2Ds + depth write + depth prepass
224
225 // DEPENDECY: none
226
227 // OUTPUT: Depth buffer attchment for current target
228
229 // NOTE: Could we make the depth pass more complete and just do a blit here?
230 //
231 // 1. If we have a depth map, just do a blit and then update with the rest
232 // 2. If we don't have a depth map (and/or SSAO) consider using a lower lod level.
233
234 // CONDITION: Input + globally enabled or ?
235
236 QSSG_ASSERT(!data.renderedCameras.isEmpty(), return);
237 QSSGRenderCamera *camera = data.renderedCameras[0];
238
239 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
240 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
241 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
242 ps = data.getPipelineState();
243
244 renderedDepthWriteObjects = data.getSortedRenderedDepthWriteObjects(*camera);
245 renderedOpaqueDepthPrepassObjects = data.getSortedrenderedOpaqueDepthPrepassObjects(*camera);
246
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);
254 cb->debugMarkEnd();
255 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("prepare_z_prepass"));
256}
257
259{
260 using namespace RenderHelpers;
261
262 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
263 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
264
265 bool needsSetViewport = true;
266 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
267
268 if (active) {
269 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
270 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral("Quick3D render Z prepass"));
271 cb->debugMarkBegin(QByteArrayLiteral("Quick3D render Z prepass"));
272 rhiRenderDepthPass(rhiCtx.get(), ps, renderedDepthWriteObjects, renderedOpaqueDepthPrepassObjects, &needsSetViewport);
273 cb->debugMarkEnd();
274 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("render_z_prepass"));
275 }
276}
277
279{
280 renderedDepthWriteObjects.clear();
281 renderedOpaqueDepthPrepassObjects.clear();
282 ps = {};
283 active = false;
284}
285
286// SSAO PASS
288{
289 using namespace RenderHelpers;
290
291 // Assumption for now is that all passes are keept alive and only reset once a frame is done.
292 // I.e., holding data like this should be safe (If that's no longer the case we need to do ref counting
293 // for shared data).
294
295 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
296 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
297
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);
303
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 };
307
308 ps = data.getPipelineState();
309 const auto &layerPrepResult = data.layerPrepResult;
310 const bool ready = rhiAoTexture && rhiPrepareAoTexture(rhiCtx.get(), layerPrepResult.textureDimensions(), rhiAoTexture, data.layer.viewCount);
311
312 if (Q_UNLIKELY(!ready))
313 rhiAoTexture = nullptr;
314}
315
317{
318 using namespace RenderHelpers;
319
320 // INPUT: Camera + depth map
321
322 // DEPENDECY: Depth map (zprepass)
323
324 // OUTPUT: AO Texture
325
326 // NOTE:
327
328 // CONDITION: SSAO enabled
329 QSSG_ASSERT(camera && rhiDepthTexture && rhiDepthTexture->isValid(), return);
330
331 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
332 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
333
334 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
335 cb->debugMarkBegin(QByteArrayLiteral("Quick3D SSAO map"));
336 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral("Quick3D SSAO map"));
337 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
338
339 if (Q_LIKELY(rhiAoTexture && rhiAoTexture->isValid())) {
340 rhiRenderAoTexture(rhiCtx.get(),
341 this,
342 renderer,
343 *ssaoShaderPipeline,
344 ps,
345 aoSettings,
346 *rhiAoTexture,
347 *rhiDepthTexture,
348 *camera);
349 }
350
351 cb->debugMarkEnd();
352 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("ssao_map"));
353}
354
356{
357 rhiDepthTexture = nullptr;
358 rhiAoTexture = nullptr;
359 camera = nullptr;
360 ps = {};
361 aoSettings = {};
362}
363
364// DEPTH TEXTURE PASS
365void DepthMapPass::renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data)
366{
367 using namespace RenderHelpers;
368
369 QSSG_ASSERT(!data.renderedCameras.isEmpty(), return);
370 QSSGRenderCamera *camera = data.renderedCameras[0];
371
372 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
373 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
374 const auto &layerPrepResult = data.layerPrepResult;
375 bool ready = false;
376 ps = data.getPipelineState();
377
378 if (m_multisampling) {
379 ps.samples = rhiCtx->mainPassSampleCount();
380 rhiDepthTexture = data.getRenderResult(QSSGFrameData::RenderResult::DepthTextureMS);
381 } else {
382 ps.samples = 1;
383 rhiDepthTexture = data.getRenderResult(QSSGFrameData::RenderResult::DepthTexture);
384 }
385
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);
389 // the depth texture is always non-MSAA, but is a 2D array with multiview
390 ready = rhiPrepareDepthPass(rhiCtx.get(), this, ps, rhiDepthTexture->rpDesc, data,
391 sortedOpaqueObjects, sortedTransparentObjects,
392 ps.samples, data.layer.viewCount);
393 }
394
395 if (Q_UNLIKELY(!ready))
396 rhiDepthTexture = nullptr;
397}
398
399void DepthMapPass::renderPass(QSSGRenderer &renderer)
400{
401 using namespace RenderHelpers;
402
403 // INPUT: sorted objects (opaque + transparent) (maybe...)
404
405 // DEPENDECY: If this is only used for the AO case, that dictates if this should be done or not.
406
407 // OUTPUT: Texture
408
409 // NOTE: Why are we prepping opaque + transparent object if we're not using them? And why are we staying compatible with 5.15?
410 // Only used for AO? Merge into the AO pass?
411
412 // NOTES:
413 //
414 // 1: If requested, use this and blit it in the z-pre pass.
415 // 2. Why are we handling the transparent objects in the render prep (only)?
416
417 // CONDITION:
418
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"));
423
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);
429 // NB! We do not pass sortedTransparentObjects in the 4th
430 // argument to stay compatible with the 5.15 code base,
431 // which also does not include semi-transparent objects in
432 // the depth texture. In addition, capturing after the
433 // opaque pass, not including transparent objects, is part
434 // of the contract for screen reading custom materials,
435 // both for depth and color.
436 rhiRenderDepthPass(rhiCtx.get(), ps, sortedOpaqueObjects, {}, &needsSetViewport);
437 cb->endPass();
438 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
439 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("depth_texture"));
440 }
441
442 cb->debugMarkEnd();
443}
444
445void DepthMapPass::resetForFrame()
446{
447 rhiDepthTexture = nullptr;
448 sortedOpaqueObjects.clear();
449 sortedTransparentObjects.clear();
450 ps = {};
451}
452
453// NORMAL TEXTURE PASS
454
455void NormalPass::renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data)
456{
457 using namespace RenderHelpers;
458
459 QSSG_ASSERT(!data.renderedCameras.isEmpty(), return);
460 QSSGRenderCamera *camera = data.renderedCameras[0];
461
462 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
463 QRhi *rhi = rhiCtx->rhi();
464 QSSG_ASSERT(rhi->isRecordingFrame(), return);
465 const auto &layerPrepResult = data.layerPrepResult;
466
467 // the normal texture is not multiview-dependent and it is always a 2D texture
468 // (so not an array with multiview either)
469
470 // the normal texture is always non-MSAA
471
472 ps = data.getPipelineState();
473 ps.samples = 1;
474 ps.viewCount = 1;
475
476 sortedOpaqueObjects = data.getSortedOpaqueRenderableObjects(*camera);
477
478 // transparent objects are not included in the normal texture pass
479
480 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
481 shaderFeatures.set(QSSGShaderFeatures::Feature::NormalPass, true);
482
483 normalTexture = data.getRenderResult(QSSGFrameData::RenderResult::NormalTexture);
484
485 const QSize size = layerPrepResult.textureDimensions();
486 bool needsBuild = false;
487
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;
493 }
494 normalTexture->texture = rhiCtx->rhi()->newTexture(format, size, 1, QRhiTexture::RenderTarget);
495 needsBuild = true;
496 normalTexture->texture->setName(QByteArrayLiteral("Normal texture"));
497 } else if (normalTexture->texture->pixelSize() != size) {
498 normalTexture->texture->setPixelSize(size);
499 needsBuild = true;
500 }
501
502 if (!normalTexture->depthStencil) {
503 normalTexture->depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size);
504 needsBuild = true;
505 } else if (normalTexture->depthStencil->pixelSize() != size) {
506 normalTexture->depthStencil->setPixelSize(size);
507 needsBuild = true;
508 }
509
510 if (needsBuild) {
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();
515 return;
516 }
517
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();
522 return;
523 }
524
525 normalTexture->resetRenderTarget();
526
527 QRhiTextureRenderTargetDescription rtDesc;
528 QRhiColorAttachment colorAttachment(normalTexture->texture);
529 rtDesc.setColorAttachments({ colorAttachment });
530 rtDesc.setDepthStencilBuffer(normalTexture->depthStencil);
531
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();
539 return;
540 }
541 }
542
543 rhiPrepareNormalPass(rhiCtx.get(), this, ps, normalTexture->rpDesc, data, sortedOpaqueObjects);
544}
545
546void NormalPass::renderPass(QSSGRenderer &renderer)
547{
548 using namespace RenderHelpers;
549
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"));
554
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);
560
561 rhiRenderNormalPass(rhiCtx.get(), ps, sortedOpaqueObjects, &needsSetViewport);
562
563 cb->endPass();
564 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
565 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("normal_texture"));
566 }
567
568 cb->debugMarkEnd();
569}
570
571void NormalPass::resetForFrame()
572{
573 normalTexture = nullptr;
574 depthBuffer = nullptr;
575 sortedOpaqueObjects.clear();
576 ps = {};
577}
578
579// SCREEN TEXTURE PASS
580
582{
583 using namespace RenderHelpers;
584
585 QSSG_ASSERT(!data.renderedCameras.isEmpty(), return);
586 QSSGRenderCamera *camera = data.renderedCameras[0];
587
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();
596 ps.samples = 1; // screen texture is always non-MSAA
597 ps.viewCount = data.layer.viewCount; // but is a 2D texture array when multiview
598
599 if (layer.background == QSSGRenderLayer::Background::Color)
600 clearColor = QColor::fromRgbF(layer.clearColor.x(), layer.clearColor.y(), layer.clearColor.z());
601
602 if (rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
603 if (layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap && layer.skyBoxCubeMap) {
604 if (!skyboxCubeMapPass)
605 skyboxCubeMapPass = SkyboxCubeMapPass();
606
607 skyboxCubeMapPass->skipTonemapping = true;
608 skyboxCubeMapPass->renderPrep(renderer, data);
609
610 // The pass expects to output to the main render target, but we have
611 // our own texture here, possibly with a differing sample count, so
612 // override the relevant settings once renderPrep() is done.
613 skyboxCubeMapPass->ps.samples = ps.samples;
614
615 skyboxPass = std::nullopt;
616 } else if (layer.background == QSSGRenderLayer::Background::SkyBox && layer.lightProbe) {
617 if (!skyboxPass)
618 skyboxPass = SkyboxPass();
619
620 skyboxPass->skipTonemapping = true;
621 skyboxPass->renderPrep(renderer, data);
622
623 skyboxPass->ps.samples = ps.samples;
624
625 skyboxCubeMapPass = std::nullopt;
626 }
627 }
628
629 bool ready = false;
630 if (Q_LIKELY(rhiScreenTexture && rhiPrepareScreenTexture(rhiCtx.get(), layerPrepResult.textureDimensions(), wantsMips, rhiScreenTexture, layer.viewCount))) {
631 ready = true;
632 if (skyboxCubeMapPass)
633 skyboxCubeMapPass->rpDesc = rhiScreenTexture->rpDesc;
634 if (skyboxPass)
635 skyboxPass->rpDesc = rhiScreenTexture->rpDesc;
636 // NB: not compatible with disabling LayerEnableDepthTest
637 // because there are effectively no "opaque" objects then.
638 // Disable Tonemapping for all materials in the screen pass texture
639 shaderFeatures = data.getShaderFeatures();
640 shaderFeatures.disableTonemapping();
641 const auto &sortedOpaqueObjects = data.getSortedOpaqueRenderableObjects(*camera);
642 for (const auto &handle : sortedOpaqueObjects) {
643 // Reflection cube maps are not available at this point, make sure they are turned off.
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);
648 }
649 }
650
651 if (Q_UNLIKELY(!ready))
652 rhiScreenTexture = nullptr;
653}
654
656{
657 using namespace RenderHelpers;
658
659 // INPUT: Sorted opaque objects + depth objects
660
661 // DEPENDECY: Depth pass (if enabled)
662
663 // OUTPUT: Texture (screen texture).
664
665 // NOTE: Used for refrection and effects (?)
666
667 // CONDITION:
668
669 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
670 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
671 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
672
673 cb->debugMarkBegin(QByteArrayLiteral("Quick3D screen texture"));
674
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);
679
680 bool needsSetViewport = true;
681 for (const auto &handle : std::as_const(sortedOpaqueObjects))
682 rhiRenderRenderable(rhiCtx.get(), ps, *handle.obj, &needsSetViewport);
683
684 if (skyboxCubeMapPass)
685 skyboxCubeMapPass->renderPass(renderer);
686 else if (skyboxPass)
687 skyboxPass->renderPass(renderer);
688
689 QRhiResourceUpdateBatch *rub = nullptr;
690 if (wantsMips) {
691 rub = rhiCtx->rhi()->nextResourceUpdateBatch();
692 rub->generateMips(rhiScreenTexture->texture);
693 }
694 cb->endPass(rub);
695 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
696 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("screen_texture"));
697 }
698
699 cb->debugMarkEnd();
700}
701
703{
704 rhiScreenTexture = nullptr;
705 if (skyboxPass)
706 skyboxPass->resetForFrame();
707 if (skyboxCubeMapPass)
708 skyboxCubeMapPass->resetForFrame();
709 ps = {};
710 wantsMips = false;
711 clearColor = Qt::transparent;
712 shaderFeatures = {};
713 sortedOpaqueObjects.clear();
714}
715
717{
718 QSSG_ASSERT(!data.renderedCameras.isEmpty(), return);
719 QSSGRenderCamera *camera = data.renderedCameras[0];
720
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);
725
726 const auto &layer = data.layer;
727 const auto shaderFeatures = data.getShaderFeatures();
728 const bool layerEnableDepthTest = layer.layerFlags.testFlag(QSSGRenderLayer::LayerFlag::EnableDepthTest);
729
730 QRhiRenderPassDescriptor *mainRpDesc = rhiCtx->mainRenderPassDescriptor();
731 const int samples = rhiCtx->mainPassSampleCount();
732 const int viewCount = data.layer.viewCount;
733
734 // NOTE: We're piggybacking on the screen map pass for now, but we could do better.
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);
749 }
750}
751
753{
754 if (QSSG_GUARD(rhiScreenTexture && rhiScreenTexture->isValid())) {
755 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
756 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
757 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
758
759 // 3. Screen texture depended objects
760 cb->debugMarkBegin(QByteArrayLiteral("Quick3D render screen texture dependent"));
761 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
762 Q_TRACE(QSSG_renderPass_entry, QStringLiteral("Quick3D render screen texture dependent"));
763 bool needsSetViewport = true;
764 for (const auto &handle : std::as_const(sortedScreenTextureObjects)) {
765 QSSGRenderableObject *theObject = handle.obj;
766 RenderHelpers::rhiRenderRenderable(rhiCtx.get(), ps, *theObject, &needsSetViewport);
767 }
768 cb->debugMarkEnd();
769 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("screen_texture_dependent"));
770 Q_TRACE(QSSG_renderPass_exit);
771 }
772}
773
775{
776 sortedScreenTextureObjects.clear();
777 rhiScreenTexture = nullptr;
778 ps = {};
779}
780
783 QSSGPassKey passKey,
784 QSSGRhiGraphicsPipelineState &ps,
785 QSSGShaderFeatures shaderFeatures,
786 QRhiRenderPassDescriptor *rpDesc,
787 const QSSGRenderableObjectList &sortedOpaqueObjects)
788{
789 const auto &rhiCtx = ctx.rhiContext();
790 QSSG_ASSERT(rpDesc && rhiCtx->rhi()->isRecordingFrame(), return);
791
792 const auto &layer = data.layer;
793 const bool layerEnableDepthTest = layer.layerFlags.testFlag(QSSGRenderLayer::LayerFlag::EnableDepthTest);
794
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);
803 }
804}
805
807 const QSSGRhiGraphicsPipelineState &ps,
808 const QSSGRenderableObjectList &sortedOpaqueObjects)
809{
810 const auto &rhiCtx = ctx.rhiContext();
811 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
812 bool needsSetViewport = true;
813 for (const auto &handle : std::as_const(sortedOpaqueObjects)) {
814 QSSGRenderableObject *theObject = handle.obj;
815 RenderHelpers::rhiRenderRenderable(rhiCtx.get(), ps, *theObject, &needsSetViewport);
816 }
817}
818
820{
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];
826
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);
832
833 // opaque objects (or, this list is empty when LayerEnableDepthTest is disabled)
834 sortedOpaqueObjects = data.getSortedOpaqueRenderableObjects(*camera);
835 shaderFeatures = data.getShaderFeatures();
836
837 QRhiRenderPassDescriptor *mainRpDesc = rhiCtx->mainRenderPassDescriptor();
838 prep(*ctx, data, this, ps, shaderFeatures, mainRpDesc, sortedOpaqueObjects);
839}
840
842{
843 auto *ctx = renderer.contextInterface();
844 const auto &rhiCtx = ctx->rhiContext();
845 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
846 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
847
848 cb->debugMarkBegin(QByteArrayLiteral("Quick3D render opaque"));
849 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
850 Q_TRACE(QSSG_renderPass_entry, QStringLiteral("Quick3D render opaque"));
851 render(*ctx, ps, sortedOpaqueObjects);
852 cb->debugMarkEnd();
853 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("opaque_pass"));
854 Q_TRACE(QSSG_renderPass_exit);
855}
856
858{
859 sortedOpaqueObjects.clear();
860 ps = {};
861 shaderFeatures = {};
862}
863
866 QSSGPassKey passKey,
867 QSSGRhiGraphicsPipelineState &ps,
868 QSSGShaderFeatures shaderFeatures,
869 QRhiRenderPassDescriptor *rpDesc,
870 const QSSGRenderableObjectList &sortedTransparentObjects,
871 bool oit)
872{
873 const auto &rhiCtx = ctx.rhiContext();
874 QSSG_ASSERT(rpDesc && rhiCtx->rhi()->isRecordingFrame(), return);
875
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);
885 }
886 }
887}
888
890 const QSSGRhiGraphicsPipelineState &ps,
891 const QSSGRenderableObjectList &sortedTransparentObjects)
892{
893 const auto &rhiCtx = ctx.rhiContext();
894 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
895 // If scissorRect is set, Item2Ds will be drawn by a workaround of modifying
896 // viewport, not using actual 3D scissor test.
897 // It means non-opaque objects may be affected by this viewport setting.
898 bool needsSetViewport = true;
899 for (const auto &handle : std::as_const(sortedTransparentObjects)) {
900 QSSGRenderableObject *theObject = handle.obj;
901 if (!theObject->renderableFlags.isCompletelyTransparent())
902 RenderHelpers::rhiRenderRenderable(rhiCtx.get(), ps, *theObject, &needsSetViewport);
903 }
904}
905
907{
908 auto *ctx = renderer.contextInterface();
909 const auto &rhiCtx = ctx->rhiContext();
910
911 QSSG_ASSERT(!data.renderedCameras.isEmpty() && data.renderedCameraData.has_value() , return);
912 QSSGRenderCamera *camera = data.renderedCameras[0];
913
914 QRhiRenderPassDescriptor *mainRpDesc = rhiCtx->mainRenderPassDescriptor();
915
916 ps = data.getPipelineState();
917 ps.samples = rhiCtx->mainPassSampleCount();
918 ps.viewCount = data.layer.viewCount;
919
920 // transparent objects (or, without LayerEnableDepthTest, all objects)
921 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled, true);
922 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, false);
923
924 shaderFeatures = data.getShaderFeatures();
925 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
926
927 prep(*ctx, data, this, ps, shaderFeatures, mainRpDesc, sortedTransparentObjects);
928}
929
931{
932 auto *ctx = renderer.contextInterface();
933 const auto &rhiCtx = ctx->rhiContext();
934 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
935 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
936
937 cb->debugMarkBegin(QByteArrayLiteral("Quick3D render alpha"));
938 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
939 Q_TRACE(QSSG_renderPass_entry, QStringLiteral("Quick3D render alpha"));
940 render(*ctx, ps, sortedTransparentObjects);
941 cb->debugMarkEnd();
942 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("transparent_pass"));
943 Q_TRACE(QSSG_renderPass_exit);
944}
945
947{
948 sortedTransparentObjects.clear();
949 ps = {};
950 shaderFeatures = {};
951}
952
954{
955 if (!skipPrep) {
956 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
957 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
958 QSSG_ASSERT(!data.renderedCameras.isEmpty(), return);
959 QSSG_ASSERT(data.renderedCameras.count() == data.layer.viewCount, return);
960 layer = &data.layer;
961 QSSG_ASSERT(layer, return);
962
963 rpDesc = rhiCtx->mainRenderPassDescriptor();
964 ps = data.getPipelineState();
965 ps.samples = rhiCtx->mainPassSampleCount();
966 ps.viewCount = data.layer.viewCount;
967 ps.polygonMode = QRhiGraphicsPipeline::Fill;
968
969 // When there are effects, then it is up to the last pass of the
970 // last effect to perform tonemapping, neither the skybox nor the
971 // main render pass should alter the colors then.
972 skipTonemapping = layer->firstEffect != nullptr;
973
974 RenderHelpers::rhiPrepareSkyBox(rhiCtx.get(), this, *layer, data.renderedCameras, renderer);
975 skipPrep = true;
976 }
977}
978
980{
981 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
982 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
983 QSSG_ASSERT(layer, return);
984
985 QRhiShaderResourceBindings *srb = layer->skyBoxSrb;
986 QSSG_ASSERT(srb, return);
987
988 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
989 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral("Quick3D render skybox"));
990
991 // Note: We get the shader here, as the screen map pass might modify the state of
992 // the tonemap mode.
993
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);
997 QSSG_CHECK(shaderPipeline);
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"));
1001}
1002
1004{
1005 ps = {};
1006 layer = nullptr;
1007 skipPrep = false;
1008}
1009
1011{
1012 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1013 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
1014 QSSG_ASSERT(!data.renderedCameras.isEmpty(), return);
1015 QSSG_ASSERT(data.renderedCameras.count() == data.layer.viewCount, return);
1016 layer = &data.layer;
1017 QSSG_ASSERT(layer, return);
1018
1019 rpDesc = rhiCtx->mainRenderPassDescriptor();
1020 ps = data.getPipelineState();
1021 ps.samples = rhiCtx->mainPassSampleCount();
1022 ps.viewCount = data.layer.viewCount;
1023 ps.polygonMode = QRhiGraphicsPipeline::Fill;
1024
1025 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1026 skyBoxCubeShader = shaderCache->getBuiltInRhiShaders().getRhiSkyBoxCubeShader(data.layer.viewCount);
1027
1028 RenderHelpers::rhiPrepareSkyBox(rhiCtx.get(), this, *layer, data.renderedCameras, renderer);
1029}
1030
1032{
1033 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1034 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
1035 QSSG_ASSERT(layer && skyBoxCubeShader, return);
1036
1037 QRhiShaderResourceBindings *srb = layer->skyBoxSrb;
1038 QSSG_ASSERT(srb, return);
1039
1040 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1041 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral("Quick3D render skybox"));
1042
1043 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, skyBoxCubeShader.get());
1044 renderer.rhiCubeRenderer()->recordRenderCube(rhiCtx.get(), &ps, srb, rpDesc, { QSSGRhiQuadRenderer::DepthTest | QSSGRhiQuadRenderer::RenderBehind });
1045 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("skybox_cube"));
1046}
1047
1049{
1050 ps = {};
1051 layer = nullptr;
1052}
1053
1055{
1056 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1057 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
1058 const auto &layer = data.layer;
1059
1060 const auto &item2Ds = data.getRenderableItem2Ds();
1061 prepdItem2DRenderers.reserve(size_t(item2Ds.size()));
1062 // NOTE: This marks the start of the 2D sub-scene rendering as it might result in
1063 // a nested 3D scene to be rendered and if we don't save the state here, we can
1064 // end up with a mismatched state in the QtQuick3D renderer.
1065 // See the end of this function for the corresponding end call (endSubLayerRender()).
1066 renderer.beginSubLayerRender(data);
1067 const auto &rpd = data.getItem2DRenderPassDescriptor();
1068 QSSG_ASSERT(rpd, return);
1069 for (const auto *item2D: std::as_const(item2Ds)) {
1070 // Find data for item
1071 auto item2DData = data.getItem2DRenderer(*item2D);
1072 const auto &mvps = data.getItem2DMvps(*item2D);
1073 QSGRenderer *renderer2d = item2DData;
1074
1075 QSSG_ASSERT(renderer2d, continue);
1076
1077 // NOTE: We shouldn't get into this state...
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;
1083 }
1084 continue;
1085 }
1086
1087 // Set the projection matrix
1088
1089 auto layerPrepResult = data.layerPrepResult;
1090
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(),
1098 effScissor,
1099 rhiCtx->rhi()->isYUpInNDC());
1100 for (int viewIndex = 0; viewIndex < viewCount; ++viewIndex) {
1101 const QMatrix4x4 projectionMatrix = correctionMat * mvps[viewIndex];
1102 renderer2d->setProjectionMatrix(projectionMatrix, viewIndex);
1103 }
1104 renderer2d->setViewportRect(effScissor);
1105 } else {
1106 for (int viewIndex = 0; viewIndex < viewCount; ++viewIndex)
1107 renderer2d->setProjectionMatrix(mvps[viewIndex], viewIndex);
1108 renderer2d->setViewportRect(RenderHelpers::correctViewportCoordinates(layerPrepResult.getViewport(), deviceRect));
1109 }
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);
1116 }
1117 renderer.endSubLayerRender(data);
1118}
1119
1121{
1122 QSSG_ASSERT(prepdItem2DRenderers.size() > 0, return);
1123
1124 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1125 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
1126 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1127
1128 cb->debugMarkBegin(QByteArrayLiteral("Quick3D render 2D sub-scene"));
1129 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1130 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral("Quick3D render 2D sub-scene"));
1131 QSSGLayerRenderData *data = QSSGLayerRenderData::getCurrent(renderer);
1132 renderer.beginSubLayerRender(*data);
1133 for (QSGRenderer *renderer2d : std::as_const(prepdItem2DRenderers))
1134 renderer2d->renderSceneInline();
1135 renderer.endSubLayerRender(*data);
1136 cb->debugMarkEnd();
1137 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("2D_sub_scene"));
1138}
1139
1141{
1142 prepdItem2DRenderers.clear();
1143}
1144
1146{
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;
1152 QSSG_ASSERT(layer, return);
1153
1154 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1155 gridShader = shaderCache->getBuiltInRhiShaders().getRhiGridShader(data.layer.viewCount);
1156
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;
1162
1163 RenderHelpers::rhiPrepareGrid(rhiCtx.get(), this, *layer, data.renderedCameras, renderer);
1164}
1165
1167{
1168 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1169 QSSG_ASSERT(gridShader && rhiCtx->rhi()->isRecordingFrame(), return);
1170 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1171
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"));
1180}
1181
1183{
1184 ps = {};
1185 layer = nullptr;
1186}
1187
1189{
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);
1195
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;
1201
1202 // debug objects
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 });
1209 if (!dcd.ubuf) {
1210 dcd.ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64 * data.renderedCameras.count());
1211 dcd.ubuf->create();
1212 }
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);
1221 }
1222 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
1223
1224 QSSGRhiShaderResourceBindingList bindings;
1225 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::VertexStage, dcd.ubuf);
1226 dcd.srb = rhiCtxD->srb(bindings);
1227
1228 rhiCtx->commandBuffer()->resourceUpdate(rub);
1229 }
1230}
1231
1233{
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());
1238
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);
1249 cb->debugMarkEnd();
1250 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("debug_objects"));
1251 }
1252}
1253
1255{
1256 ps = {};
1257}
1258
1260{
1261 Q_UNUSED(renderer);
1262 auto &frameData = data.getFrameData();
1263 for (const auto &p : std::as_const(extensions)) {
1264 p->prepareRender(frameData);
1265 if (p->mode() == QSSGRenderExtension::RenderMode::Standalone)
1266 p->render(frameData);
1267 }
1268}
1269
1271{
1272 auto *data = QSSGLayerRenderData::getCurrent(renderer);
1273 QSSG_ASSERT(data, return);
1274 auto &frameData = data->getFrameData();
1275 for (const auto &p : std::as_const(extensions)) {
1276 if (p->mode() == QSSGRenderExtension::RenderMode::Main)
1277 p->render(frameData);
1278 }
1279}
1280
1282{
1283 for (const auto &p : std::as_const(extensions))
1284 p->resetForFrame();
1285
1286 // TODO: We should track if we need to update this list.
1287 extensions.clear();
1288}
1289
1291{
1292 auto *ctx = renderer.contextInterface();
1293 const auto &rhiCtx = ctx->rhiContext();
1294 auto *rhi = rhiCtx->rhi();
1295
1296 QSSG_ASSERT(!data.renderedCameras.isEmpty() && data.renderedCameraData.has_value() , return);
1297 QSSGRenderCamera *camera = data.renderedCameras[0];
1298
1299 ps = data.getPipelineState();
1300 ps.samples = rhiCtx->mainPassSampleCount();
1301 ps.viewCount = rhiCtx->mainPassViewCount();
1302
1303 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled, true);
1304 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, false);
1305
1306 shaderFeatures = data.getShaderFeatures();
1307 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
1308
1309 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1310 ps.colorAttachmentCount = 2;
1311
1312 rhiAccumTexture = data.getRenderResult(QSSGFrameData::RenderResult::AccumTexture);
1313 rhiRevealageTexture = data.getRenderResult(QSSGFrameData::RenderResult::RevealageTexture);
1314 if (ps.samples > 1)
1315 rhiDepthTexture = data.getRenderResult(QSSGFrameData::RenderResult::DepthTextureMS);
1316 else
1317 rhiDepthTexture = data.getRenderResult(QSSGFrameData::RenderResult::DepthTexture);
1318 if (!rhiDepthTexture->isValid())
1319 return;
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;
1330 }
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);
1335 } else {
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);
1338 }
1339 rhiAccumTexture->texture->create();
1340 rhiRevealageTexture->texture->create();
1341
1342 QRhiTextureRenderTargetDescription desc;
1343 desc.setColorAttachments({{rhiAccumTexture->texture}, {rhiRevealageTexture->texture}});
1344 desc.setDepthTexture(rhiDepthTexture->texture);
1345
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();
1351
1352 renderTarget = oitrt.oitRenderTarget;
1353 }
1354 }
1355 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1356 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1357 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearMRTShader();
1358
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);
1363
1364 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ this, nullptr, nullptr, 0 }));
1365 QRhiBuffer *&ubuf = dcd.ubuf;
1366 const int ubufSize = sizeof(clearData);
1367 if (!ubuf) {
1368 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
1369 ubuf->create();
1370 }
1371
1372 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
1373 rub->updateDynamicBuffer(ubuf, 0, ubufSize, &clearData);
1374 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx.get(), rub);
1375
1376 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1377
1378 clearSrb = rhiCtxD->srb(bindings);
1379
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;
1388
1389 TransparentPass::prep(*ctx, data, this, ps, shaderFeatures, oitrt.renderPassDescriptor, sortedTransparentObjects, true);
1390 }
1391}
1392
1394{
1395 auto *ctx = renderer.contextInterface();
1396 const auto &rhiCtx = ctx->rhiContext();
1397 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
1398 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1399
1400 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1401 if (Q_LIKELY(renderTarget)) {
1402 cb->beginPass(renderTarget, Qt::black, {});
1403
1404 QRhiShaderResourceBindings *srb = clearSrb;
1405 QSSG_ASSERT(srb, return);
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);
1410
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);
1417 cb->debugMarkEnd();
1418 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("transparent_order_independent_pass"));
1419 Q_TRACE(QSSG_renderPass_exit);
1420
1421 cb->endPass();
1422 }
1423 }
1424}
1425
1427{
1428 if (method == QSSGRenderLayer::OITMethod::WeightedBlended)
1429 return Type::Standalone;
1430 return Type::Main;
1431}
1432
1433
1435{
1436 sortedTransparentObjects.clear();
1437 ps = {};
1438 shaderFeatures = {};
1439 rhiAccumTexture = nullptr;
1440 rhiRevealageTexture = nullptr;
1441 rhiDepthTexture = nullptr;
1442}
1443
1445{
1446 using namespace RenderHelpers;
1447
1448 QSSG_ASSERT(!data.renderedCameras.isEmpty(), return);
1449
1450 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1451 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
1452 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1453
1454 ps = data.getPipelineState();
1455 ps.samples = rhiCtx->mainPassSampleCount();
1456 ps.viewCount = rhiCtx->mainPassViewCount();
1457
1458 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1459 rhiAccumTexture = data.getRenderResult(QSSGFrameData::RenderResult::AccumTexture);
1460 rhiRevealageTexture = data.getRenderResult(QSSGFrameData::RenderResult::RevealageTexture);
1461 compositeShaderPipeline = shaderCache->getBuiltInRhiShaders().getRhiOitCompositeShader(method, ps.samples > 1 ? true : false);
1462 }
1463}
1464
1466{
1467 using namespace RenderHelpers;
1468
1469 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1470 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(), return);
1471 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1472
1473 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1474
1475 if (!rhiAccumTexture->texture || !rhiRevealageTexture->texture)
1476 return;
1477
1478 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1479 QSSGRhiShaderResourceBindingList bindings;
1480
1481 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest,
1482 QRhiSampler::Nearest,
1483 QRhiSampler::None,
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);
1489
1490 compositeSrb = rhiCtxD->srb(bindings);
1491
1492 QRhiShaderResourceBindings *srb = compositeSrb;
1493 QSSG_ASSERT(srb, return);
1494
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"));
1501 cb->debugMarkEnd();
1502 }
1503}
1504
1506{
1507 ps = {};
1508 shaderFeatures = {};
1509 rhiAccumTexture = nullptr;
1510 rhiRevealageTexture = nullptr;
1511}
1512
1513QT_END_NAMESPACE
void renderPass(QSSGRenderer &renderer) final
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
void resetForFrame() final
void renderPass(QSSGRenderer &renderer) final
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
void resetForFrame() final
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
void renderPass(QSSGRenderer &renderer) final
void resetForFrame() final
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
void resetForFrame() final
void renderPass(QSSGRenderer &renderer) final
void resetForFrame() final
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
Type passType() const final
void renderPass(QSSGRenderer &renderer) final
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
void resetForFrame() final
void renderPass(QSSGRenderer &renderer) final
virtual ~QSSGRenderPass()
friend class QSSGRenderContextInterface
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
void renderPass(QSSGRenderer &renderer) final
void resetForFrame() final
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
void resetForFrame() final
void renderPass(QSSGRenderer &renderer) final
const QSSGRenderCamera * camera
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
void renderPass(QSSGRenderer &renderer) final
void resetForFrame() final
void renderPass(QSSGRenderer &renderer) final
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
QSSGRenderCamera * camera
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
void resetForFrame() final
void renderPass(QSSGRenderer &renderer) final
void renderPass(QSSGRenderer &renderer) final
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
void resetForFrame() final
void renderPass(QSSGRenderer &renderer) final
void resetForFrame() final
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
void renderPass(QSSGRenderer &renderer) final
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
void resetForFrame() final
void renderPass(QSSGRenderer &renderer) final
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
void resetForFrame() final
void resetForFrame() final
void renderPass(QSSGRenderer &renderer) final
void renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data) final
#define QSSG_ASSERT_X(cond, msg, action)
#define QSSG_CHECK(cond)
#define QSSG_ASSERT(cond, action)
#define QSSG_GUARD(cond)
static QT_BEGIN_NAMESPACE QMatrix4x4 correctMVPForScissor(QRectF viewportRect, QRect scissorRect, bool isYUp)