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
qquick3dsimplequadrenderpass.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/qquick3dobject_p.h>
9
10#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
11#include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
12#include <QtQuick3DRuntimeRender/private/qssgrhiquadrenderer_p.h>
13#include <QtQuick3DRuntimeRender/private/qssgrendershadercache_p.h>
14#include <QtQuick3DRuntimeRender/private/qssgrendererimplshaders_p.h>
15#include <QtQuick3DRuntimeRender/private/qssgrendercommands_p.h>
16
17#include <QtQuick3DRuntimeRender/private/qssgrenderbuffermanager_p.h>
18
19#include <ssg/qssgrendercontextcore.h>
20#include <ssg/qssgrenderextensions.h>
21
22#include <rhi/qrhi.h>
23
25
26/*!
27 \qmltype SimpleQuadRenderer
28 \nativetype QQuick3DSimpleQuadRenderer
29 \inqmlmodule QtQuick3D.Helpers
30 \inherits RenderExtension
31 \since 6.11
32 \brief Renders a full-screen textured quad to the main render target.
33
34 SimpleQuadRenderer is a \l RenderExtension that blits a \l Texture across
35 the entire screen. It runs at the \c PostColor stage in the \c Main render
36 mode, which means it executes after the scene has been drawn but before any
37 post-processing effects, and it writes directly into the \l View3D's main
38 render target, overwriting whatever was drawn by the scene.
39
40 The most common use case is building a fully custom rendering pipeline:
41 set \l {View3D::renderFormat}{View3D.renderFormat} to disable Qt Quick 3D's
42 built-in passes with \c {View3D.DisableInternalPasses}, render the scene
43 content into one or more \l RenderPass targets, and then use
44 SimpleQuadRenderer to composite the result back onto the screen.
45
46 \note SimpleQuadRenderer is automatically registered as an extension with the
47 scene — it does not need to be added to \l {View3D::extensions}{View3D.extensions}
48 manually.
49
50 \qml
51 import QtQuick3D
52 import QtQuick3D.Helpers
53
54 View3D {
55 // Disable the built-in render passes so we can provide our own output
56 renderFormat: View3D.DisableInternalPasses
57
58 // A custom offscreen pass that renders scene content
59 RenderPass {
60 id: mainColorPass
61 commands: [
62 RenderablesFilter { renderableTypes: RenderablesFilter.Opaque | RenderablesFilter.Transparent }
63 ]
64 }
65
66 // Blit the result of the custom pass to the screen
67 SimpleQuadRenderer {
68 texture: Texture {
69 textureProvider: RenderOutputProvider {
70 renderPass: mainColorPass
71 }
72 }
73 }
74 }
75 \endqml
76
77 \sa RenderOutputProvider, RenderPass, View3D
78*/
79
80/*!
81 \qmlproperty Texture SimpleQuadRenderer::texture
82 The texture to render across the full-screen quad. This can be any \l Texture,
83 including one whose \l {Texture::textureProvider}{textureProvider} is set to a
84 \l RenderOutputProvider to display output from a \l RenderPass or one of Qt Quick 3D's
85 built-in passes (such as the depth texture or AO texture).
86*/
87
89{
90 static constexpr FlagT flags = FlagT(Flags::HasGraphicsResources) | FlagT(QSSGRenderGraphObjectUtils::InternalFlags::AutoRegisterExtension);
91public:
96
98 {
99 if (srb)
100 srb->deleteLater();
101 }
102
103 virtual bool prepareData(QSSGFrameData &data) final
104 {
105 bool wasDirty = true;
106
107 if (image)
108 renderImage = data.contextInterface()->bufferManager()->loadRenderImage(image);
109 else
110 renderImage = QSSGRenderImageTexture();
111
112 wasDirty = (renderImage.m_texture != nullptr);
113
114 return wasDirty;
115 }
116
117 virtual void prepareRender(QSSGFrameData &data) final
118 {
119 if (renderImage.m_texture) {
120 const auto &rhiCtx = data.contextInterface()->rhiContext();
121 const auto &renderer = data.contextInterface()->renderer();
122 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
123 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx.get(), rub);
124 }
125 }
126
127 virtual void render(QSSGFrameData &data) final
128 {
129 if (renderImage.m_texture) {
130 const auto &rhiCtx = data.contextInterface()->rhiContext();
131 const auto &renderer = data.contextInterface()->renderer();
132 const auto &shaderCache = data.contextInterface()->shaderCache();
133
134 QSSGRhiGraphicsPipelineState ps = data.getPipelineState();
135 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
136 cb->debugMarkBegin(QByteArrayLiteral("QtQuick3D Blit Pass"));
137
138 const auto tonemapMode = QSSGLayerRenderData::getCurrent(data)->layer.tonemapMode;
139 const auto &shaderPipeline = shaderCache->getBuiltInRhiShaders().getRhiSimpleQuadShader(ps.viewCount, tonemapMode);
140
141 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
142 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge });
143 QSSGRhiShaderResourceBindingList bindings;
144 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, renderImage.m_texture, sampler);
145 // The texture is often a render pass output that is recreated on resize, so
146 // the srb is owned here and rebuilt when the bindings change. Going through
147 // the shared srb cache would leave an entry behind for every texture that was
148 // ever bound, and since the bindings carry nothing unique to this renderer,
149 // releasing the previous entry could pull it from under another renderer
150 // showing the same texture.
151 if (!srb || bindings != srbBindings) {
152 // render() can be called more than once in a frame, so the previous srb
153 // may already be referenced by commands recorded for this frame, so defer
154 // deletion until the next frame.
155 if (srb)
156 srb->deleteLater();
157 srb = rhiCtx->rhi()->newShaderResourceBindings();
158 srb->setBindings(bindings.v, bindings.v + bindings.p);
159 srbBindings = bindings;
160 if (!srb->create()) {
161 qWarning("Failed to build srb for the simple quad renderer");
162 srb->deleteLater();
163 srb = nullptr;
164 cb->debugMarkEnd();
165 return;
166 }
167 }
168
169 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, shaderPipeline.get());
170 renderer->rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(), QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::PremulBlend);
171 cb->debugMarkEnd();
172 }
173 }
174 virtual void resetForFrame() final {}
175 virtual RenderMode mode() const final { return RenderMode::Main; }
176 virtual RenderStage stage() const final { return RenderStage::PostColor; }
177
183};
184
185
186QQuick3DSimpleQuadRenderer::QQuick3DSimpleQuadRenderer() { }
187
188QSSGRenderGraphObject *QQuick3DSimpleQuadRenderer::updateSpatialNode(QSSGRenderGraphObject *node)
189{
190 if (!node)
192
193 QSSGRenderSimpleQuadRenderer *blitPass = static_cast<QSSGRenderSimpleQuadRenderer *>(node);
194 if (m_source)
195 blitPass->image = m_source->getRenderImage();
196 else
197 blitPass->image = nullptr;
198
199 return node;
200}
201
202void QQuick3DSimpleQuadRenderer::itemChange(QQuick3DObject::ItemChange change, const QQuick3DObject::ItemChangeData &value)
203{
204 if (change == QQuick3DObject::ItemSceneChange)
205 updateSceneManager(value.sceneManager);
206}
207
208QQuick3DTexture *QQuick3DSimpleQuadRenderer::texture() const
209{
210 return m_source;
211}
212
213void QQuick3DSimpleQuadRenderer::setTexture(QQuick3DTexture *newSource)
214{
215 if (m_source == newSource)
216 return;
217
218 QQuick3DObjectPrivate::attachWatcher(this, &QQuick3DSimpleQuadRenderer::setTexture, newSource, m_source);
219
220 m_source = newSource;
221 emit textureChanged();
222
223 update();
224}
225
226void QQuick3DSimpleQuadRenderer::updateSceneManager(QQuick3DSceneManager *sceneManager)
227{
228 if (sceneManager)
229 QQuick3DObjectPrivate::refSceneManager(m_source, *sceneManager);
230 else
231 QQuick3DObjectPrivate::derefSceneManager(m_source);
232}
233
234QT_END_NAMESPACE
\qmlproperty Texture SimpleQuadRenderer::texture The texture to render across the full-screen quad.
virtual void render(QSSGFrameData &data) final
Record the render pass.
virtual void resetForFrame() final
Called each time a new frame starts.
virtual RenderStage stage() const final
virtual void prepareRender(QSSGFrameData &data) final
Prepare data for rendering.
QSSGRhiShaderResourceBindingList srbBindings
virtual bool prepareData(QSSGFrameData &data) final
Called after scene data is collected, but before any render data or rendering in the current frame ha...
virtual RenderMode mode() const final
Combined button and popup list for selecting options.