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

source code of qtdeclarative/src/quick/scenegraph/coreapi/qsgrendernode.cpp