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
qquick3drenderpass.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5
7
8#include <QtQuick3D/private/qquick3dscenemanager_p.h>
9#include <QtQuick3DUtils/private/qssgassert_p.h>
10#include <QtQuick3DRuntimeRender/private/qssgrenderuserpass_p.h>
11#include <QtQuick3DRuntimeRender/private/qssgshadermaterialadapter_p.h>
12
13#include <QtCore/QLoggingCategory>
14
16
17Q_LOGGING_CATEGORY(lcQuick3DRenderPass, "qt.quick3d.renderpass")
18
19/*!
20 \qmltype RenderPass
21 \inherits Object3D
22 \inqmlmodule QtQuick3D
23 \brief Defines a custom render pass for rendering 3D content.
24 \since 6.11
25
26 A RenderPass defines a rendering step and the render target it writes
27 into. It is the combination of three concerns:
28
29 \list
30 \li \b {Where to render} — one or more output textures declared as
31 \l ColorAttachment or \l DepthTextureAttachment commands in
32 \l {RenderPass::commands}{commands}.
33 \li \b {What to render} — which scene objects the pass draws,
34 controlled by \l RenderablesFilter commands. Sub-divisions of
35 work within the same render target are described using
36 \l SubRenderPass commands.
37 \li \b {How to render} — the \l materialMode and any
38 \l PipelineStateOverride commands.
39 \endlist
40
41 A RenderPass becomes active for a scene when it is placed as a child
42 of a \l View3D or a \l Node, or of another RenderPass.
43
44 \section1 Render order
45
46 Nesting a RenderPass inside another RenderPass expresses ordering:
47 nested passes render \e before their parent, so a pass that produces a
48 texture consumed by another pass is declared as a child of its
49 consumer, and results merge towards the top of the pass hierarchy.
50 Only RenderPass ancestors count towards the nesting depth; other
51 ancestors, such as \l Node items used for grouping, do not affect the
52 order. The relative render order of passes at the same nesting depth
53 is not defined; use nesting to express an ordering requirement.
54
55 Nesting affects ordering only; a nested pass still renders into its
56 own render target. To render into the parent pass's render target,
57 reference the pass from a \l SubRenderPass command instead. A pass
58 referenced by a SubRenderPass command is invoked by its parent and
59 never renders on its own.
60
61 The following example sets up a simple off-screen pass that renders
62 all scene objects into a custom texture, which can then be consumed
63 by a material or a \l SimpleQuadRenderer:
64
65 \qml
66 import QtQuick3D
67
68 View3D {
69 // Declare the off-screen color buffer
70 RenderPassTexture {
71 id: myColorTexture
72 format: RenderPassTexture.RGBA8
73 }
74
75 // The render pass: where + what + how
76 RenderPass {
77 id: myRenderPass
78 commands: [
79 // Where: attach the texture as the color output
80 ColorAttachment {
81 name: "color0"
82 target: myColorTexture
83 },
84 // What: render all objects into it
85 RenderablesFilter {
86 renderableTypes: RenderablesFilter.Opaque | RenderablesFilter.Transparent
87 }
88 ]
89 }
90 }
91 \endqml
92
93 \section1 Exposing data to the shaders
94
95 As with Effects and Custom Materials, the RenderPass will expose and
96 update user-defined properties to the shaders automatically. Any QML
97 properties declared on a RenderPass subtype will be available as
98 uniforms in the shader.
99
100 \sa SubRenderPass, RenderOutputProvider, RenderablesFilter
101*/
102
103QQuick3DRenderPass::QQuick3DRenderPass(QQuick3DObject *parent)
104 : QQuick3DObject(*(new QQuick3DObjectPrivate(QQuick3DObjectPrivate::Type::RenderPass, QQuick3DObjectPrivate::Flags::RequiresSecondaryUpdate)), parent)
105 , QQuick3DPropertyChangedTracker(this, QQuick3DSuperClassInfo<QQuick3DRenderPass>())
106{
107}
108
109QSSGRenderGraphObject *QQuick3DRenderPass::updateSpatialNode(QSSGRenderGraphObject *node)
110{
111 QSSGRenderUserPass *renderPassNode = static_cast<QSSGRenderUserPass *>(node);
112
113 bool newBackendNode = false;
114 if (!renderPassNode) {
115 renderPassNode = new QSSGRenderUserPass;
116 newBackendNode = true;
117 }
118
119 // The role follows the SubRenderPass reference count maintained by the
120 // commands referencing this pass. A role change forces a full update, which
121 // rebuilds the command list and thereby marks the scene manager's pass set
122 // dirty, so synchronize() re-derives the classification-dependent state
123 // (nesting depth, declaration order) for the new role.
124 const bool isSubPass = (m_subRenderPassRef > 0);
125 const bool subPassChanged = (renderPassNode->role == QSSGRenderUserPass::Role::SubPass) != isSubPass;
126
127 renderPassNode->role = isSubPass ? QSSGRenderUserPass::Role::SubPass : QSSGRenderUserPass::Role::TopLevel;
128
129 const bool fullUpdate = newBackendNode || subPassChanged || (m_dirtyAttributes & Dirty::TextureDirty) || (m_dirtyAttributes & CommandsDirty);
130
131 auto &shaderAugmentation = renderPassNode->shaderAugmentation;
132 auto &uniformProps = shaderAugmentation.propertyUniforms;
133
134 if (fullUpdate) {
135 markAllDirty();
136
137 // Properties -> uniforms.
138 uniformProps = extractProperties();
139
140 // Commands
141 renderPassNode->resetCommands();
142 clearDirty(Dirty::CommandsDirty);
143 for (QQuick3DShaderUtilsRenderCommand *command : std::as_const(m_commands)) {
144 if (auto *cmd = command->cloneCommand())
145 renderPassNode->commands.push_back(cmd);
146 else
147 markDirty(CommandsDirty, true); // Try again next time
148 }
149
150 // The command list drives the top-level/sub-pass classification (a pass
151 // referenced by a SubRenderPass command is a sub-pass). Rebuilding it may
152 // have changed that, so ask synchronize() to re-derive the classification.
153 if (QQuick3DSceneManager *sceneManager = QQuick3DObjectPrivate::get(this)->sceneManager)
154 sceneManager->userRenderPassesDirty = true;
155 }
156
157 // Update the property values
158 if (m_dirtyAttributes & Dirty::PropertyDirty) {
159 for (const auto &prop : std::as_const(uniformProps)) {
160 auto p = metaObject()->property(prop.pid);
161 if (Q_LIKELY(p.isValid())) {
162 QVariant v = p.read(this);
163 if (v.isValid()) {
164 if (v.metaType().id() == qMetaTypeId<QQuick3DTexture *>()) {
165 QQuick3DTexture *tex = v.value<QQuick3DTexture *>();
166 auto *po = QQuick3DObjectPrivate::get(tex);
167 QSSGRenderImage *ri = static_cast<QSSGRenderImage *>(po->spatialNode);
168 prop.value = QVariant::fromValue(ri);
169 } else {
170 prop.value = v;
171 }
172 }
173 }
174 }
175
176 clearDirty(Dirty(Dirty::PropertyDirty | Dirty::TextureDirty));
177 }
178
179 // Clear Dirty
180 if (m_dirtyAttributes & Dirty::ClearDirty) {
181 renderPassNode->renderTargetFlags = QRhiTextureRenderTarget::Flags(m_renderTargetFlags.toInt());
182 renderPassNode->clearColor = m_clearColor;
183 renderPassNode->depthStencilClearValue = { m_depthClearValue, m_stencilClearValue };
184
185 clearDirty(Dirty::ClearDirty);
186 }
187
188 if (m_dirtyAttributes & Dirty::PassTypeDirty) {
189 switch (m_passMode) {
190 case UserPass:
191 renderPassNode->passMode = QSSGRenderUserPass::UserPass;
192 break;
193 case SkyboxPass:
194 renderPassNode->passMode = QSSGRenderUserPass::SkyboxPass;
195 break;
196 case Item2DPass:
197 renderPassNode->passMode = QSSGRenderUserPass::Item2DPass;
198 break;
199 }
200
201 clearDirty(Dirty::PassTypeDirty);
202 }
203
204 // If not a user pass, we're done
205 if (m_passMode != UserPass)
206 return renderPassNode;
207
208 renderPassNode->materialMode = QSSGRenderUserPass::MaterialModes(m_materialMode);
209 clearDirty(Dirty::MaterialModeDirty);
210
211 if (renderPassNode->materialMode == QSSGRenderUserPass::OverrideMaterial) {
212 clearDirty(Dirty::OverrideMaterialDirty);
213 if (m_overrideMaterial) {
214 // Set the backend material
215 QSSGRenderGraphObject *graphObject = QQuick3DObjectPrivate::get(m_overrideMaterial)->spatialNode;
216 if (graphObject)
217 renderPassNode->overrideMaterial = graphObject;
218 else
219 markDirty(OverrideMaterialDirty, true); // Try again next time
220 } else {
221 // Set nullptr
222 renderPassNode->overrideMaterial = nullptr;
223 }
224 } else if (renderPassNode->materialMode == QSSGRenderUserPass::OriginalMaterial) {
225 // Nothing to do
226 } else if (renderPassNode->materialMode == QSSGRenderUserPass::AugmentMaterial) {
227 // Augment Shaders
228 if (m_dirtyAttributes & AugmentShaderDirty) {
229 if (!m_augmentShader.isEmpty()) {
230 const QQmlContext *context = qmlContext(this);
231 QByteArray shaderPathKey("augment material --");
232 QByteArray augment = QSSGShaderUtils::resolveShader(m_augmentShader, context, shaderPathKey);
233 QByteArray augmentSnippet;
234 QByteArray augmentPreamble;
235
236 // We have to pick apart the shader string such that the contents of the:
237 // void MAIN_FRAGMENT_AUGMENT() { }
238 // function are taken out, and will get added to the end of the shader generation
239 // and the goal is to overwrite the "output" of the shader
240
241 // We also need to scan the who shader code for certain "keywords" so that we know
242 // what features to enable in the original material.
243
244 // Everything else outsode of MAIN_FRAGMENT_AUGMENT function ends up being preamble code
245 // that will get pasted in before the real main(). So that will include helper functions and
246 // resolvable #includes etc.
247
248 static const char *mainFuncStart = "void MAIN_FRAGMENT_AUGMENT()";
249 qsizetype mainFuncIdx = augment.indexOf(mainFuncStart);
250 if (mainFuncIdx != -1) {
251 qsizetype braceOpenIdx = augment.indexOf('{', mainFuncIdx + int(strlen(mainFuncStart)));
252 if (braceOpenIdx != -1) {
253 qsizetype braceCloseIdx = braceOpenIdx;
254 qsizetype openBraces = 1;
255 while (openBraces > 0 && braceCloseIdx + 1 < augment.size()) {
256 braceCloseIdx++;
257 if (augment[braceCloseIdx] == '{')
258 openBraces++;
259 else if (augment[braceCloseIdx] == '}')
260 openBraces--;
261 }
262 if (openBraces == 0) {
263 // We found the closing brace
264 augmentSnippet = augment.mid(braceOpenIdx + 1, braceCloseIdx - braceOpenIdx - 1);
265 augmentPreamble = augment.left(mainFuncIdx);
266 augmentPreamble += augment.mid(braceCloseIdx + 1);
267 } else {
268 qWarning("QQuick3DRenderPass: Could not find the closing brace of MAIN_FRAGMENT_AUGMENT() in shader %s", qPrintable(m_augmentShader.toString()));
269 }
270 } else {
271 qWarning("QQuick3DRenderPass: Could not find the opening brace of MAIN_FRAGMENT_AUGMENT() in shader %s", qPrintable(m_augmentShader.toString()));
272 }
273 } else {
274 qWarning("QQuick3DRenderPass: Could not find MAIN_FRAGMENT_AUGMENT() function in shader %s", qPrintable(m_augmentShader.toString()));
275 }
276
277 renderPassNode->shaderAugmentation.body = augmentSnippet;
278 renderPassNode->shaderAugmentation.preamble = augmentPreamble;
279 renderPassNode->markDirty(QSSGRenderUserPass::DirtyFlag::ShaderDirty);
280 }
281 }
282 clearDirty(Dirty::AugmentShaderDirty);
283 }
284
285 return renderPassNode;
286}
287
288void QQuick3DRenderPass::itemChange(ItemChange change, const ItemChangeData &value)
289{
290 if (change == QQuick3DObject::ItemSceneChange) {
291 updateSceneManager(value.sceneManager);
292 } else if (change == QQuick3DObject::ItemParentHasChanged) {
293 // The parent determines the pass's validity and nesting depth, both
294 // derived in synchronize(). A same-manager reparent does not travel
295 // through pass registration or removal, so mark the set dirty here.
296 if (QQuick3DSceneManager *sceneManager = QQuick3DObjectPrivate::get(this)->sceneManager)
297 sceneManager->userRenderPassesDirty = true;
298 }
299}
300
301void QQuick3DRenderPass::markTrackedPropertyDirty(QMetaProperty property, DirtyPropertyHint hint)
302{
303 Q_UNUSED(property);
304
305 // FIXME: As with the property tracking for Effects and Custom materials we
306 // should really track which property changed and only update that one.
307 if (hint == DirtyPropertyHint::Reference) {
308 // FIXME: We should verify that the property is actually a texture property.
309 markDirty(Dirty::TextureDirty);
310 } else {
311 markDirty(Dirty::PropertyDirty);
312 }
313}
314
315void QQuick3DRenderPass::onMaterialDestroyed(QObject *object)
316{
317 if (m_overrideMaterial == object) {
318 m_overrideMaterial = nullptr;
319 emit overrideMaterialChanged();
320 markDirty(OverrideMaterialDirty);
321 }
322}
323
324void QQuick3DRenderPass::onCommandChanged()
325{
326 markDirty(CommandsDirty);
327}
328
329void QQuick3DRenderPass::qmlAppendCommand(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> *list, QQuick3DShaderUtilsRenderCommand *command)
330{
331 if (!command)
332 return;
333
334 QQuick3DRenderPass *that = qobject_cast<QQuick3DRenderPass *>(list->object);
335
336 if (!command->parentItem())
337 command->setParentItem(that);
338
339 that->m_commands.push_back(command);
340 that->markDirty(CommandsDirty);
341
342 // Re-clone commands whenever a property changes so the render thread
343 // sees the updated state.
344 QObject::connect(command, &QQuick3DShaderUtilsRenderCommand::changed, that, &QQuick3DRenderPass::onCommandChanged);
345}
346
347QQuick3DShaderUtilsRenderCommand *QQuick3DRenderPass::qmlCommandAt(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> *list, qsizetype index)
348{
349 QQuick3DRenderPass *that = qobject_cast<QQuick3DRenderPass *>(list->object);
350 return that->m_commands.at(index);
351}
352
353qsizetype QQuick3DRenderPass::qmlCommandCount(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> *list)
354{
355 QQuick3DRenderPass *that = qobject_cast<QQuick3DRenderPass *>(list->object);
356 return that->m_commands.size();
357}
358
359void QQuick3DRenderPass::qmlCommandClear(QQmlListProperty<QQuick3DShaderUtilsRenderCommand> *list)
360{
361 QQuick3DRenderPass *that = qobject_cast<QQuick3DRenderPass *>(list->object);
362 for (QQuick3DShaderUtilsRenderCommand *cmd : std::as_const(that->m_commands))
363 QObject::disconnect(cmd, nullptr, that, nullptr);
364 that->m_commands.clear();
365 that->markDirty(CommandsDirty);
366}
367
368void QQuick3DRenderPass::updateSceneManager(QQuick3DSceneManager *sceneManager)
369{
370 if (sceneManager) {
371 // Handle inline override material that may not have had a scene manager when it was set
372 if (m_overrideMaterial && !m_overrideMaterial->parentItem() && !QQuick3DObjectPrivate::get(m_overrideMaterial)->sceneManager) {
373 if (!m_overrideMaterialRefed) {
374 QQuick3DObjectPrivate::refSceneManager(m_overrideMaterial, *sceneManager);
375 m_overrideMaterialRefed = true;
376 }
377 }
378 } else {
379 // Deref the material when scene manager is removed
380 if (m_overrideMaterial && m_overrideMaterialRefed) {
381 QQuick3DObjectPrivate::derefSceneManager(m_overrideMaterial);
382 m_overrideMaterialRefed = false;
383 }
384 }
385}
386
387void QQuick3DRenderPass::markDirty(Dirty type, bool requestSecondaryUpdate)
388{
389 if (!(m_dirtyAttributes & quint32(type))) {
390 m_dirtyAttributes |= quint32(type);
391 update();
392 }
393
394 if (requestSecondaryUpdate)
395 QQuick3DObjectPrivate::get(this)->requestSecondaryUpdate();
396}
397
398void QQuick3DRenderPass::clearDirty(Dirty type)
399{
400 m_dirtyAttributes &= ~quint32(type);
401}
402
403/*!
404 \qmlproperty list<RenderCommand> RenderPass::commands
405 This property holds the list of render commands for the render pass.
406
407 The commands in the list are executed in the order they appear in the list.
408
409 \note The commands for RenderPass and Effects are similar but not the same, only
410 those marked as compatible can be used with this RenderPass.
411
412 \sa SubRenderPass,
413 PipelineStateOverride,
414 RenderablesFilter,
415 RenderPassTexture,
416 ColorAttachment,
417 DepthTextureAttachment,
418 DepthStencilAttachment,
419 AddDefine,
420 renderTargetBlend
421*/
422
423QQmlListProperty<QQuick3DShaderUtilsRenderCommand> QQuick3DRenderPass::commands()
424{
425 return QQmlListProperty<QQuick3DShaderUtilsRenderCommand>(this,
426 nullptr,
427 QQuick3DRenderPass::qmlAppendCommand,
428 QQuick3DRenderPass::qmlCommandCount,
429 QQuick3DRenderPass::qmlCommandAt,
430 QQuick3DRenderPass::qmlCommandClear);
431}
432
433/*!
434 \qmlproperty color RenderPass::clearColor
435 This property holds the clear color for the render pass.
436
437 \default Qt.black
438*/
439QColor QQuick3DRenderPass::clearColor() const
440{
441 return m_clearColor;
442}
443
444void QQuick3DRenderPass::setClearColor(const QColor &newClearColor)
445{
446 if (m_clearColor == newClearColor)
447 return;
448 m_clearColor = newClearColor;
449 emit clearColorChanged();
450 markDirty(ClearDirty);
451}
452
453/*!
454 \qmlproperty RenderPass::MaterialModes RenderPass::materialMode
455 Controls how object materials are handled when rendering into this pass.
456
457 \value RenderPass.OriginalMaterial
458 Objects are rendered using their own assigned materials, with full
459 lighting, textures, and material properties applied normally. This is
460 the standard mode for rendering a faithful copy of the scene into a
461 custom render target — for example, a secondary viewpoint for a
462 reflection probe, a rear-view camera, or a picture-in-picture effect.
463 The \c overrideMaterial, \c augmentShader, and \c shaders properties
464 are not used in this mode.
465
466 \value RenderPass.AugmentMaterial
467 Each object is rendered with its own material, but the contents of
468 the \c {MAIN_FRAGMENT_AUGMENT()} function defined in \l augmentShader
469 are injected after the original material's output definition. This
470 allows the augment code to read the material's computed color and write
471 to additional color outputs defined by \l ColorAttachment commands in
472 the pass. This is useful for multi-render-target (MRT) passes that need
473 per-material shading, such as writing the lit color to one attachment
474 and a world-space normal to another in a single draw call.
475
476 \value RenderPass.OverrideMaterial
477 All objects rendered by this pass use the single \l overrideMaterial
478 instead of their own. This is useful for depth-only passes, shadow maps,
479 silhouette or outline effects, and any other case where you want all
480 geometry to be shaded identically regardless of what material is
481 assigned to it. The \c augmentShader property is not used in this mode.
482
483 \default RenderPass.OriginalMaterial
484*/
485QQuick3DRenderPass::MaterialModes QQuick3DRenderPass::materialMode() const
486{
487 return m_materialMode;
488}
489
490void QQuick3DRenderPass::setMaterialMode(MaterialModes newMaterialMode)
491{
492 if (m_materialMode == newMaterialMode)
493 return;
494 m_materialMode = newMaterialMode;
495 emit materialModeChanged();
496 markDirty(MaterialModeDirty);
497}
498
499/*!
500 \qmlproperty Material RenderPass::overrideMaterial
501 This property holds the override material for the render pass when
502 \l{RenderPass::materialMode}{materialMode} is set to \c OverrideMaterial.
503*/
504QQuick3DMaterial *QQuick3DRenderPass::overrideMaterial() const
505{
506 return m_overrideMaterial;
507}
508
509void QQuick3DRenderPass::setOverrideMaterial(QQuick3DMaterial *newOverrideMaterial)
510{
511 if (m_overrideMaterial == newOverrideMaterial)
512 return;
513
514 // Deref the old material if we had ref'd it
515 if (m_overrideMaterial && m_overrideMaterialRefed) {
516 QQuick3DObjectPrivate::derefSceneManager(m_overrideMaterial);
517 m_overrideMaterialRefed = false;
518 }
519
520 QQuick3DObjectPrivate::attachWatcher(this, &QQuick3DRenderPass::setOverrideMaterial, newOverrideMaterial, m_overrideMaterial);
521
522 m_overrideMaterial = newOverrideMaterial;
523
524 // Handle inline material declarations by ensuring they get registered with the scene manager
525 if (m_overrideMaterial && m_overrideMaterial->parentItem() == nullptr) {
526 // If the material has no parent, check if it has a hierarchical parent that's a QQuick3DObject
527 // and re-parent it to that, e.g., inline materials
528 QQuick3DObject *parentItem = qobject_cast<QQuick3DObject *>(m_overrideMaterial->parent());
529 if (parentItem) {
530 m_overrideMaterial->setParentItem(parentItem);
531 } else {
532 // If no valid parent was found, make sure the material refs our scene manager
533 const auto &sceneManager = QQuick3DObjectPrivate::get(this)->sceneManager;
534 if (sceneManager) {
535 QQuick3DObjectPrivate::refSceneManager(m_overrideMaterial, *sceneManager);
536 m_overrideMaterialRefed = true;
537 }
538 // else: If there's no scene manager, defer until one is set, see itemChange()
539 }
540 }
541
542 emit overrideMaterialChanged();
543 markDirty(OverrideMaterialDirty);
544}
545
546/*!
547 \qmlproperty url RenderPass::augmentShader
548 This property holds the augment shader URL for the render pass when
549 \l{RenderPass::materialMode}{materialMode} is set to \c AugmentMaterial.
550
551 The shader file should contain a function with the following signature:
552 \badcode
553 void MAIN_FRAGMENT_AUGMENT() {
554 // Custom shader code here
555 }
556 \endcode
557
558 This function will be combined with the existing fragment shader of the material
559 being used by the object being rendered in this render pass. Allowing users to
560 augment the existing material shader with custom code.
561*/
562QUrl QQuick3DRenderPass::augmentShader() const
563{
564 return m_augmentShader;
565}
566
567void QQuick3DRenderPass::setAugmentShader(const QUrl &newAugmentShader)
568{
569 if (m_augmentShader == newAugmentShader)
570 return;
571 m_augmentShader = newAugmentShader;
572 emit augmentShaderChanged();
573 markDirty(AugmentShaderDirty);
574}
575
576/*!
577 \qmlproperty RenderPass::PassMode RenderPass::passMode
578 This property holds the pass mode for the render pass.
579
580 In addition to standard user render passes, Qt Quick 3D supports
581 users to manually triggering internal render passes for rendering
582 the skybox and 2D items.
583
584 \value RenderPass.UserPass A user specified render pass.
585 \value RenderPass.SkyboxPass Qt Quick 3D's built-in skybox render pass.
586 \value RenderPass.Item2DPass Qt Quick 3D's built-in 2D item render pass.
587 \default RenderPass.UserPass
588*/
589
590QQuick3DRenderPass::PassMode QQuick3DRenderPass::passMode() const
591{
592 return m_passMode;
593}
594
595void QQuick3DRenderPass::setPassMode(PassMode newPassMode)
596{
597 if (m_passMode == newPassMode)
598 return;
599 m_passMode = newPassMode;
600 emit passModeChanged();
601 markDirty(PassTypeDirty);
602}
603
604/*!
605 \qmlproperty real RenderPass::depthClearValue
606 This property holds the depth clear value for the render pass.
607
608 \default 1.0
609*/
610float QQuick3DRenderPass::depthClearValue() const
611{
612 return m_depthClearValue;
613}
614
615void QQuick3DRenderPass::setDepthClearValue(float newDepthClearValue)
616{
617 if (qFuzzyCompare(m_depthClearValue, newDepthClearValue))
618 return;
619 m_depthClearValue = newDepthClearValue;
620 emit depthClearValueChanged();
621 markDirty(ClearDirty);
622}
623
624/*!
625 \qmlproperty int RenderPass::stencilClearValue
626 This property holds the stencil clear value for the render pass.
627
628 \default 0
629*/
630quint32 QQuick3DRenderPass::stencilClearValue() const
631{
632 return m_stencilClearValue;
633}
634
635void QQuick3DRenderPass::setStencilClearValue(quint32 newStencilClearValue)
636{
637 if (m_stencilClearValue == newStencilClearValue)
638 return;
639 m_stencilClearValue = newStencilClearValue;
640 emit stencilClearValueChanged();
641 markDirty(ClearDirty);
642}
643
644/*!
645 \qmlproperty RenderPass::RenderTargetFlags RenderPass::renderTargetFlags
646 This property holds the render target flags for the render pass. These flags affect how
647 the render target contents are handled at the beginning and end of each frame.
648
649 \value RenderPass.None No special behavior. Color and depth/stencil contents are cleared at the start of each frame.
650 \value RenderPass.PreserveColorContents Preserve the color contents of the render target between frames, so the previous frame's output remains until explicitly overwritten.
651 \value RenderPass.PreserveDepthStencilContents Preserve the depth and stencil contents of the render target between frames.
652 \value RenderPass.DoNotStoreDepthStencilContents Do not store the depth and stencil contents of the render target after rendering (may improve performance on tiled GPUs).
653
654 \default RenderPass.None
655
656 \sa QRhiTextureRenderTarget::Flags
657*/
658
659QQuick3DRenderPass::RenderTargetFlags QQuick3DRenderPass::renderTargetFlags() const
660{
661 return m_renderTargetFlags;
662}
663
664void QQuick3DRenderPass::setRenderTargetFlags(RenderTargetFlags newRenderTargetFlags)
665{
666 if (m_renderTargetFlags == newRenderTargetFlags)
667 return;
668 m_renderTargetFlags = newRenderTargetFlags;
669 emit renderTargetFlagsChanged();
670 markDirty(ClearDirty);
671}
672
673// A reference change can flip the pass's role, so the pass is updated to
674// mirror the new role to its backend node, and the scene manager's pass set is
675// marked dirty so the classification-dependent state (nesting depth,
676// declaration order) is re-derived. The scene manager may be null when the
677// pass has not entered a scene yet; registration sets the flag then.
678static void notifySubPassRefChange(QQuick3DRenderPass *pass)
679{
680 pass->update();
681 if (QQuick3DSceneManager *sceneManager = QQuick3DObjectPrivate::get(pass)->sceneManager)
682 sceneManager->userRenderPassesDirty = true;
683}
684
685void QQuick3DRenderPassPrivateHelper::subPassRef(QQuick3DRenderPass *pass)
686{
687 Q_ASSERT(pass);
688 ++pass->m_subRenderPassRef;
690}
691
692void QQuick3DRenderPassPrivateHelper::subPassDeref(QQuick3DRenderPass *pass)
693{
694 Q_ASSERT(pass);
695 if (QSSG_GUARD(pass->m_subRenderPassRef > 0))
696 --pass->m_subRenderPassRef;
698}
699
700QT_END_NAMESPACE
void subPassDeref(QQuick3DRenderPass *pass)
void subPassRef(QQuick3DRenderPass *pass)
Combined button and popup list for selecting options.
static void notifySubPassRefChange(QQuick3DRenderPass *pass)