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

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