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
qsgrendernode.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
8
9/*!
10 \class QSGRenderNode
11 \brief The QSGRenderNode class represents a set of custom rendering commands
12 targeting the graphics API that is in use by the scenegraph.
13 \inmodule QtQuick
14 \since 5.8
15
16 QSGRenderNode allows creating scene graph nodes that perform their own
17 custom rendering via QRhi (the common approach from Qt 6.6 on), directly
18 via a 3D graphics API such as OpenGL, Vulkan, or Metal, or, when the \c
19 software backend is in use, via QPainter.
20
21 QSGRenderNode is the enabler for one of the three ways to integrate custom
22 2D/3D rendering into a Qt Quick scene. The other two options are to perform
23 the rendering \c before or \c after the Qt Quick scene's own rendering,
24 or to generate a whole separate render pass targeting a dedicated render
25 target (a texture) and then have an item in the scene display the texture.
26 The QSGRenderNode-based approach is similar to the former, in the sense
27 that no additional render passes or render targets are involved, and allows
28 injecting custom rendering commands "inline" with the Qt Quick scene's
29 own rendering. See \l{Qt Quick Scene Graph} for a further discussion of
30 the three approaches.
31
32 \sa {Scene Graph - Custom QSGRenderNode}
33 */
34
35QSGRenderNode::QSGRenderNode()
36 : QSGNode(RenderNodeType),
37 d(new QSGRenderNodePrivate)
38{
39}
40
41/*!
42 Destructs the render node. Derived classes are expected to perform cleanup
43 similar to releaseResources() in here.
44
45 With QRhi and resources such as QRhiBuffer, QRhiTexture,
46 QRhiGraphicsPipeline, etc., it is often good practice to use smart pointers,
47 such as std::unique_ptr, which can often avoid the need to implement a
48 destructor, and lead to more compact source code. Keep in mind, however,
49 that implementing releaseResources(), likely containing a number of reset()
50 calls on the unique_ptrs, is still important.
51
52 \sa releaseResources()
53 */
54QSGRenderNode::~QSGRenderNode()
55{
56 delete d;
57}
58
59QSGRenderNodePrivate::QSGRenderNodePrivate()
60 : m_matrix(nullptr)
61 , m_clip_list(nullptr)
62 , m_opacity(1)
63{
64 m_projectionMatrix.resize(1);
65}
66
67/*!
68 This function should return a mask where each bit represents graphics states
69 changed by the \l render() function.
70
71 \note With Qt 6 and QRhi-based rendering the only relevant values are
72 ViewportState and ScissorState. Other values can be returned but are
73 ignored in practice.
74
75 \value ViewportState Viewport
76 \value ScissorState Scissor test enabled state, scissor rectangle
77 \value DepthState This value has no effect in Qt 6.
78 \value StencilState This value has no effect in Qt 6.
79 \value ColorState This value has no effect in Qt 6.
80 \value BlendState This value has no effect in Qt 6.
81 \value CullState This value has no effect in Qt 6.
82 \value RenderTargetState This value has no effect in Qt 6.
83
84 \note The \c software backend exposes its QPainter and saves and restores
85 before and after invoking render(). Therefore reporting any changed states
86 from here is not necessary.
87
88 The default implementation returns 0, meaning no relevant state was changed
89 in render().
90
91 \note This function may be called before render().
92 */
93QSGRenderNode::StateFlags QSGRenderNode::changedStates() const
94{
95 return {};
96}
97
98/*!
99 Called from the frame preparation phase. There is a call to this function
100 before each invocation of render().
101
102 Unlike render(), this function is called before the scenegraph starts
103 recording the render pass for the current frame on the underlying command
104 buffer. This is useful when doing rendering with graphics APIs, such as
105 Vulkan, where copy type of operations will need to be recorded before the
106 render pass.
107
108 The default implementation is empty.
109
110 When implementing a QSGRenderNode that uses QRhi to render, query the QRhi
111 object from the QQuickWindow via \l{QQuickWindow::rhi()}. To get a
112 QRhiCommandBuffer for submitting work to, call commandBuffer(). To query
113 information about the active render target, call renderTarget(). See the
114 \l{{Scene Graph - Custom QSGRenderNode}} example for details.
115
116 \since 6.0
117 */
118void QSGRenderNode::prepare()
119{
120}
121
122/*!
123 \fn void QSGRenderNode::render(const RenderState *state)
124
125 This function is called by the renderer and should paint this node with
126 directly invoking commands via QRhi or directly via the underlying graphics
127 API (OpenGL, Direct3D, etc.).
128
129 The effective opacity can be retrieved with \l inheritedOpacity().
130
131 The projection matrix is available through \a state, while the model-view
132 matrix can be fetched with \l matrix(). The combined matrix is then the
133 projection matrix times the model-view matrix. The correct stacking of the
134 items in the scene is ensured by the projection matrix.
135
136 When using the provided matrices, the coordinate system for vertex data
137 follows the usual QQuickItem conventions: top-left is (0, 0), bottom-right
138 is the corresponding QQuickItem's width() and height() minus one. For
139 example, assuming a two float (x-y) per vertex coordinate layout, a
140 triangle covering half of the item can be specified as (width - 1, height - 1),
141 (0, 0), (0, height - 1) using counter-clockwise direction.
142
143 \note QSGRenderNode is provided as a means to implement custom 2D or 2.5D Qt
144 Quick items. It is not intended for integrating true 3D content into the Qt
145 Quick scene. That use case is better supported by the other methods for
146 integrating custom rendering.
147
148 \note QSGRenderNode can perform significantly better than texture-based
149 approaches (such as, QQuickRhiItem), especially on systems where
150 the fragment processing power is limited. This is because it avoids
151 rendering to a texture and then drawing a textured quad. Rather,
152 QSGRenderNode allows recording draw calls in line with the scenegraph's
153 other commands, avoiding an additional render target and the potentially
154 expensive texturing and blending.
155
156 Clip information is calculated before the function is called.
157 Implementations wishing to take clipping into account can set up scissoring
158 or stencil based on the information in \a state. The stencil buffer is
159 filled with the necessary clip shapes, but it is up to the implementation
160 to enable stencil testing.
161
162 Some scenegraph backends, software in particular, use no scissor or
163 stencil. There the clip region is provided as an ordinary QRegion.
164
165 When implementing a QSGRenderNode that uses QRhi to render, query the QRhi
166 object from the QQuickWindow via \l{QQuickWindow::rhi()}. To get a
167 QRhiCommandBuffer for submitting work to, call commandBuffer(). To query
168 information about the active render target, call renderTarget(). See the
169 \l{{Scene Graph - Custom QSGRenderNode}} example for details.
170
171 With Qt 6 and its QRhi-based scene graph renderer, no assumptions should be
172 made about the active (OpenGL) state when this function is called, even
173 when OpenGL is in use. Assume nothing about the pipelines and dynamic
174 states bound on the command list/buffer when this function is called.
175
176 \note Depth writes are expected to be disabled. Enabling depth writes can
177 lead to unexpected results, depending on the scenegraph backend in use and
178 the content in the scene, so exercise caution with this.
179
180 \note In Qt 6, \l changedStates() has limited use. See the documentation
181 for changedStates() for more information.
182
183 With some graphics APIs, including when using QRhi directly, it can be
184 necessary to reimplement prepare() in addition, or alternatively connect to
185 the QQuickWindow::beforeRendering() signal. These are called/emitted before
186 recording the beginning of a renderpass on the command buffer
187 (vkCmdBeginRenderPass with Vulkan, or starting to encode via
188 MTLRenderCommandEncoder in case of Metal. Recording copy operations cannot
189 be done inside render() with such APIs. Rather, do such operations either
190 in prepare() or the slot connected to beforeRendering (with
191 DirectConnection).
192
193 \sa QSGRendererInterface, QQuickWindow::rendererInterface()
194 */
195
196/*!
197 This function is called when all custom graphics resources allocated by
198 this node have to be freed immediately. In case the node does not directly
199 allocate graphics resources (buffers, textures, render targets, fences,
200 etc.) through the graphics API that is in use, there is nothing to do here.
201
202 Failing to release all custom resources can lead to incorrect behavior in
203 graphics device loss scenarios on some systems since subsequent
204 reinitialization of the graphics system may fail.
205
206 \note Some scenegraph backends may choose not to call this function.
207 Therefore it is expected that QSGRenderNode implementations perform cleanup
208 both in their destructor and in releaseResources().
209
210 Unlike with the destructor, it is expected that render() can reinitialize
211 all resources it needs when called after a call to releaseResources().
212
213 With OpenGL, the scenegraph's OpenGL context will be current both when
214 calling the destructor and this function.
215 */
216void QSGRenderNode::releaseResources()
217{
218}
219
220/*!
221 \enum QSGRenderNode::StateFlag
222
223 This enum contains the possible values for use in the bitmask returned from changedStates().
224
225 \value ViewportState Viewport
226 \value ScissorState Scissor test enabled state, scissor rectangle
227 \value DepthState This value has no effect in Qt 6.
228 \value StencilState This value has no effect in Qt 6.
229 \value ColorState This value has no effect in Qt 6.
230 \value BlendState This value has no effect in Qt 6.
231 \value CullState This value has no effect in Qt 6.
232 \value RenderTargetState This value has no effect in Qt 6.
233 */
234
235/*!
236 \enum QSGRenderNode::RenderingFlag
237
238 Possible values for the bitmask returned from flags().
239
240 \value BoundedRectRendering Indicates that the implementation of render()
241 does not render outside the area reported from rect() in item
242 coordinates. Such node implementations can lead to more efficient rendering,
243 depending on the scenegraph backend. For example, the \c software backend can
244 continue to use the more optimal partial update path when all render nodes
245 in the scene have this flag set.
246
247 \value DepthAwareRendering Indicates that the implementations of render()
248 conforms to scenegraph expectations by only generating a Z value of 0 in
249 scene coordinates which is then transformed by the matrices retrieved from
250 RenderState::projectionMatrix() and matrix(), as described in the notes for
251 render(). Such node implementations can lead to more efficient rendering,
252 depending on the scenegraph backend. For example, the batching OpenGL
253 renderer can continue to use a more optimal path when all render nodes in
254 the scene have this flag set.
255
256 \value OpaqueRendering Indicates that the implementation of render() writes
257 out opaque pixels for the entire area reported from rect(). By default the
258 renderers must assume that render() can also output semi or fully
259 transparent pixels. Setting this flag can improve performance in some
260 cases.
261
262 \value NoExternalRendering Indicates that the implementations of prepare()
263 and render() exclusively use the QRhi family of APIs, instead of
264 directly calling a 3D API such as OpenGL, Vulkan, or Metal.
265
266 \sa render(), prepare(), rect(), QRhi
267 */
268
269/*!
270 \return flags describing the behavior of this render node.
271
272 The default implementation returns 0.
273
274 \sa RenderingFlag, rect()
275 */
276QSGRenderNode::RenderingFlags QSGRenderNode::flags() const
277{
278 return {};
279}
280
281/*!
282 \return the bounding rectangle in item coordinates for the area render()
283 touches. The value is only in use when flags() includes
284 BoundedRectRendering, ignored otherwise.
285
286 Reporting the rectangle in combination with BoundedRectRendering is
287 particularly important with the \c software backend because otherwise
288 having a rendernode in the scene would trigger fullscreen updates, skipping
289 all partial update optimizations.
290
291 For rendernodes covering the entire area of a corresponding QQuickItem the
292 return value will be (0, 0, item->width(), item->height()).
293
294 \note Nodes are also free to render outside the boundaries specified by the
295 item's width and height, since the scenegraph nodes are not bounded by the
296 QQuickItem geometry, as long as this is reported correctly from this function.
297
298 \sa flags()
299*/
300QRectF QSGRenderNode::rect() const
301{
302 return QRectF();
303}
304
305/*!
306 \return pointer to the current projection matrix.
307
308 In render() this is the same matrix that is returned from
309 RenderState::projectionMatrix(). This getter exists so that prepare() also
310 has a way to query the projection matrix.
311
312 When working with a modern graphics API, or Qt's own graphics abstraction
313 layer, it is more than likely that one will want to load
314 \c{*projectionMatrix() * *matrix()} into a uniform buffer. That is however
315 something that needs to be done in prepare(), so outside the recording of a
316 render pass. That is why both matrices are queriable directly from the
317 QSGRenderNode, both in prepare() and render().
318
319 \since 6.5
320 */
321const QMatrix4x4 *QSGRenderNode::projectionMatrix() const
322{
323 return &d->m_projectionMatrix[0];
324}
325
326/*!
327 \internal
328 */
329const QMatrix4x4 *QSGRenderNode::projectionMatrix(qsizetype index) const
330{
331 return &d->m_projectionMatrix[index];
332}
333
334/*!
335 \return pointer to the current model-view matrix.
336 */
337const QMatrix4x4 *QSGRenderNode::matrix() const
338{
339 return d->m_matrix;
340}
341
342/*!
343 \return the current clip list.
344 */
345const QSGClipNode *QSGRenderNode::clipList() const
346{
347 return d->m_clip_list;
348}
349
350/*!
351 \return the current effective opacity.
352 */
353qreal QSGRenderNode::inheritedOpacity() const
354{
355 return d->m_opacity;
356}
357
358/*!
359 \return the current render target.
360
361 This is provided mainly to enable prepare() and render() implementations
362 that use QRhi accessing the QRhiRenderTarget's
363 \l{QRhiRenderPassDescriptor}{renderPassDescriptor} or
364 \l{QRhiRenderTarget::pixelSize()}{pixel size}.
365
366 To build a QRhiGraphicsPipeline, which implies having to provide a
367 QRhiRenderPassDescriptor, query the renderPassDescriptor from the render
368 target. Be aware however that the render target may change over the
369 lifetime of the custom QQuickItem and the QSGRenderNode. For example,
370 consider what happens when dynamically setting \c{layer.enabled: true} on
371 the item or an ancestor of it: this triggers rendering into a texture, not
372 directly to the window, which means the QSGRenderNode is going to work with
373 a different render target from then on. The new render target may then have
374 a different pixel format, which can make already built graphics pipelines
375 incompatible. This can be handled with logic such as the following:
376
377 \code
378 if (m_pipeline && renderTarget()->renderPassDescriptor()->serializedFormat() != m_renderPassFormat) {
379 delete m_pipeline;
380 m_pipeline = nullptr;
381 }
382 if (!m_pipeline) {
383 // Build a new QRhiGraphicsPipeline.
384 // ...
385 // Store the serialized format for fast and simple comparisons later on.
386 m_renderPassFormat = renderTarget()->renderPassDescriptor()->serializedFormat();
387 }
388 \endcode
389
390 \since 6.6
391
392 \sa commandBuffer()
393 */
394QRhiRenderTarget *QSGRenderNode::renderTarget() const
395{
396 return d->m_rt.rt;
397}
398
399/*!
400 \return the current command buffer.
401
402 \since 6.6
403
404 \sa renderTarget()
405 */
406QRhiCommandBuffer *QSGRenderNode::commandBuffer() const
407{
408 return d->m_rt.cb;
409}
410
411QSGRenderNode::RenderState::~RenderState()
412{
413}
414
415/*!
416 \class QSGRenderNode::RenderState
417 \brief Provides information about the projection matrix and clipping.
418 \inmodule QtQuick
419
420 The render state contains information for the renderer when invoking
421 commands to the scenegraph backends.
422
423 \sa QSGRenderNode::render()
424 */
425
426/*!
427 \fn const QMatrix4x4 *QSGRenderNode::RenderState::projectionMatrix() const
428
429 \return pointer to the current projection matrix.
430
431 The model-view matrix can be retrieved with QSGRenderNode::matrix().
432 Typically \c{projection * modelview} is the matrix that is then used in the
433 vertex shader to transform the vertices.
434 */
435
436/*!
437 \fn const QMatrix4x4 *QSGRenderNode::RenderState::scissorRect() const
438
439 \return the current scissor rectangle when clipping is active. x and y are
440 the bottom left coordinates.
441 */
442
443/*!
444 \fn const QMatrix4x4 *QSGRenderNode::RenderState::scissorEnabled() const
445
446 \return the current state of scissoring.
447
448 \note Only relevant for graphics APIs that have a dedicated on/off state of
449 scissoring.
450 */
451
452/*!
453 \fn const QMatrix4x4 *QSGRenderNode::RenderState::stencilValue() const
454
455 \return the current stencil reference value when clipping is active.
456 */
457
458/*!
459 \fn const QMatrix4x4 *QSGRenderNode::RenderState::stencilEnabled() const
460
461 \return the current state of stencil testing.
462
463 \note With graphics APIs where stencil testing is enabled in pipeline state
464 objects, instead of individual state-setting commands, it is up to the
465 implementation of render() to enable stencil testing with operations
466 \c KEEP, comparison function \c EQUAL, and a read and write mask of \c 0xFF.
467 */
468
469/*!
470 \fn const QRegion *QSGRenderNode::RenderState::clipRegion() const
471
472 \return the current clip region or null for backends where clipping is
473 implemented via stencil or scissoring.
474
475 The \c software backend uses no projection, scissor or stencil, meaning most
476 of the render state is not in use. However, the clip region that can be set
477 on the QPainter still has to be communicated since reconstructing this
478 manually in render() is not reasonable. It can therefore be queried via
479 this function. The region is in world coordinates and can be passed
480 to QPainter::setClipRegion() with Qt::ReplaceClip. This must be done before
481 calling QPainter::setTransform() since the clip region is already mapped to
482 the transform provided in QSGRenderNode::matrix().
483 */
484
485/*!
486 \return pointer to a \a state value.
487
488 Reserved for future use.
489 */
490void *QSGRenderNode::RenderState::get(const char *state) const
491{
492 Q_UNUSED(state);
493 return nullptr;
494}
495
496QT_END_NAMESPACE