Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qsgmaterial.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
// Qt-Security score:significant reason:default
4
5
#
include
"qsgmaterial.h"
6
#
include
"qsgrenderer_p.h"
7
8
QT_BEGIN_NAMESPACE
9
10
/*!
11
\group qtquick-scenegraph-materials
12
\title Qt Quick Scene Graph Material Classes
13
\brief classes used to define materials in the Qt Quick Scene Graph.
14
15
This page lists the material classes in \l {Qt Quick}'s
16
\l{Qt Quick Scene Graph}{scene graph}.
17
*/
18
19
#
ifndef
QT_NO_DEBUG
20
static
int
qt_material_count
= 0;
21
22
static
void
qt_print_material_count
()
23
{
24
qCDebug(lcQsgLeak,
"Number of leaked materials: %i"
,
qt_material_count
);
25
qt_material_count
= -1;
26
}
27
#
endif
28
29
/*!
30
\class QSGMaterialType
31
\brief The QSGMaterialType class is used as a unique type token in combination with QSGMaterial.
32
\inmodule QtQuick
33
\ingroup qtquick-scenegraph-materials
34
35
It serves no purpose outside the QSGMaterial::type() function.
36
37
\note All classes with QSG prefix should be used solely on the scene graph's
38
rendering thread. See \l {Scene Graph and Rendering} for more information.
39
*/
40
41
/*!
42
\class QSGMaterial
43
\brief The QSGMaterial class encapsulates rendering state for a shader program.
44
\inmodule QtQuick
45
\ingroup qtquick-scenegraph-materials
46
47
QSGMaterial and QSGMaterialShader subclasses form a tight relationship. For
48
one scene graph (including nested graphs), there is one unique
49
QSGMaterialShader instance which encapsulates the shaders the scene graph
50
uses to render that material, such as a shader to flat coloring of
51
geometry. Each QSGGeometryNode can have a unique QSGMaterial containing the
52
how the shader should be configured when drawing that node, such as the
53
actual color to used to render the geometry.
54
55
QSGMaterial has two virtual functions that both need to be implemented. The
56
function type() should return a unique instance for all instances of a
57
specific subclass. The createShader() function should return a new instance
58
of QSGMaterialShader, specific to that subclass of QSGMaterial.
59
60
A minimal QSGMaterial implementation could look like this:
61
\code
62
class Material : public QSGMaterial
63
{
64
public:
65
QSGMaterialType *type() const override { static QSGMaterialType type; return &type; }
66
QSGMaterialShader *createShader(QSGRendererInterface::RenderMode) const override { return new Shader; }
67
};
68
\endcode
69
70
See the \l{Scene Graph - Custom Material}{Custom Material example} for an introduction
71
on implementing a QQuickItem subclass backed by a QSGGeometryNode and a custom
72
material.
73
74
\note createShader() is called only once per QSGMaterialType, to reduce
75
redundant work with shader preparation. If a QSGMaterial is backed by
76
multiple sets of vertex and fragment shader combinations, the implementation
77
of type() must return a different, unique QSGMaterialType pointer for each
78
combination of shaders.
79
80
\note All classes with QSG prefix should be used solely on the scene graph's
81
rendering thread. See \l {Scene Graph and Rendering} for more information.
82
83
\sa QSGMaterialShader, {Scene Graph - Custom Material}, {Scene Graph - Two Texture Providers}, {Scene Graph - Graph}
84
*/
85
86
/*!
87
\internal
88
*/
89
90
QSGMaterial::QSGMaterial()
91
{
92
Q_UNUSED(m_reserved);
93
#
ifndef
QT_NO_DEBUG
94
if
(lcQsgLeak().isDebugEnabled()) {
95
++qt_material_count;
96
static
bool
atexit_registered =
false
;
97
if
(!atexit_registered) {
98
atexit(qt_print_material_count);
99
atexit_registered =
true
;
100
}
101
}
102
#
endif
103
}
104
105
106
/*!
107
\internal
108
*/
109
110
QSGMaterial::~QSGMaterial()
111
{
112
#
ifndef
QT_NO_DEBUG
113
if
(lcQsgLeak().isDebugEnabled()) {
114
--qt_material_count;
115
if
(qt_material_count < 0)
116
qCDebug(lcQsgLeak,
"Material destroyed after qt_print_material_count() was called."
);
117
}
118
#
endif
119
}
120
121
122
123
/*!
124
\enum QSGMaterial::Flag
125
126
\value Blending Set this flag to true if the material requires blending to be
127
enabled during rendering.
128
129
\value RequiresDeterminant Set this flag to true if the material relies on
130
the determinant of the matrix of the geometry nodes for rendering.
131
132
\value RequiresFullMatrixExceptTranslate Set this flag to true if the material
133
relies on the full matrix of the geometry nodes for rendering, except the translation part.
134
135
\value RequiresFullMatrix Set this flag to true if the material relies on
136
the full matrix of the geometry nodes for rendering.
137
138
\value NoBatching Set this flag to true if the material uses shaders that are
139
incompatible with the \l{Qt Quick Scene Graph Default Renderer}{scene graph's batching
140
mechanism}. This is relevant in certain advanced usages, such as, directly
141
manipulating \c{gl_Position.z} in the vertex shader. Such solutions are often tied to
142
a specific scene structure, and are likely not safe to use with arbitrary contents in
143
a scene. Thus this flag should only be set after appropriate investigation, and will
144
never be needed for the vast majority of materials. Setting this flag can lead to
145
reduced performance due to having to issue more draw calls. This flag was introduced
146
in Qt 6.3.
147
148
\value CustomCompileStep In Qt 6 this flag is identical to NoBatching. Prefer using
149
NoBatching instead.
150
151
\omitvalue MultiView2
152
\omitvalue MultiView3
153
\omitvalue MultiView4
154
*/
155
156
/*!
157
\fn QSGMaterial::Flags QSGMaterial::flags() const
158
159
Returns the material's flags.
160
*/
161
162
163
164
/*!
165
Sets the flags \a flags on this material if \a on is true;
166
otherwise clears the attribute.
167
*/
168
169
void
QSGMaterial::setFlag(Flags flags,
bool
on)
170
{
171
if
(on)
172
m_flags |= flags;
173
else
174
m_flags &= ~flags;
175
}
176
177
178
179
/*!
180
Compares this material to \a other and returns 0 if they are equal; -1 if
181
this material should sort before \a other and 1 if \a other should sort
182
before.
183
184
The scene graph can reorder geometry nodes to minimize state changes.
185
The compare function is called during the sorting process so that
186
the materials can be sorted to minimize state changes in each
187
call to QSGMaterialShader::updateState().
188
189
The this pointer and \a other is guaranteed to have the same type().
190
*/
191
192
int
QSGMaterial::compare(
const
QSGMaterial *other)
const
193
{
194
Q_ASSERT(other && type() == other->type());
195
const
qintptr diff = qintptr(
this
) - qintptr(other);
196
return
diff < 0 ? -1 : (diff > 0 ? 1 : 0);
197
}
198
199
200
201
/*!
202
\fn QSGMaterialType *QSGMaterial::type() const
203
204
This function is called by the scene graph to query an identifier that is
205
unique to the QSGMaterialShader instantiated by createShader().
206
207
For many materials, the typical approach will be to return a pointer to a
208
static, and so globally available, QSGMaterialType instance. The
209
QSGMaterialType is an opaque object. Its purpose is only to serve as a
210
type-safe, simple way to generate unique material identifiers.
211
\code
212
QSGMaterialType *type() const override
213
{
214
static QSGMaterialType type;
215
return &type;
216
}
217
\endcode
218
*/
219
220
221
222
/*!
223
\fn QSGMaterialShader *QSGMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
224
225
This function returns a new instance of a the QSGMaterialShader
226
implementation used to render geometry for a specific implementation
227
of QSGMaterial.
228
229
The function will be called only once for each combination of material type and \a renderMode
230
and will be cached internally.
231
232
For most materials, the \a renderMode can be ignored. A few materials may need
233
custom handling for specific render modes. For instance if the material implements
234
antialiasing in a way that needs to account for perspective transformations when
235
RenderMode3D is in use.
236
*/
237
238
/*!
239
\return The number of views in case of the material is used in multiview
240
rendering.
241
242
\note The return value is valid only when called from createShader(), and
243
afterwards. The value is not necessarily up-to-date before createShader()
244
is invokved by the scene graph.
245
246
Normally the return value is \c 1. A view count greater than 2 implies a
247
\e{multiview render pass}. Materials that support multiview are expected to
248
query viewCount() in createShader(), or in their QSGMaterialShader
249
constructor, and ensure the appropriate shaders are picked. The vertex
250
shader is then expected to use
251
\c{gl_ViewIndex} to index the modelview-projection matrix array as there
252
are multiple matrices in multiview mode. (one for each view)
253
254
As an example, take the following simple vertex shader:
255
256
\badcode
257
#version 440
258
259
layout(location = 0) in vec4 vertexCoord;
260
layout(location = 1) in vec4 vertexColor;
261
262
layout(location = 0) out vec4 color;
263
264
layout(std140, binding = 0) uniform buf {
265
mat4 matrix[2];
266
float opacity;
267
};
268
269
void main()
270
{
271
gl_Position = matrix[gl_ViewIndex] * vertexCoord;
272
color = vertexColor * opacity;
273
}
274
\endcode
275
276
This shader is prepared to handle 2 views, and 2 views only. It is not
277
compatible with other view counts. When conditioning the shader, the \c qsb
278
tool has to be invoked with \c{--view-count 2} or, if using the CMake
279
integration,
280
\c{VIEW_COUNT 2} must be specified in the \c{qt_add_shaders()} command.
281
282
\note A line with \c{#extension GL_EXT_multiview : require} is injected
283
automatically by \c qsb whenever a view count of 2 or greater is set.
284
285
Developers are encouraged to use the automatically injected preprocessor
286
variable \c{QSHADER_VIEW_COUNT} to simplify the handling of the different
287
number of views. For example, if there is a need to support both
288
non-multiview and multiview with a view count of 2 in the same source file,
289
the following could be done:
290
291
\badcode
292
#version 440
293
294
layout(location = 0) in vec4 vertexCoord;
295
layout(location = 1) in vec4 vertexColor;
296
297
layout(location = 0) out vec4 color;
298
299
layout(std140, binding = 0) uniform buf {
300
#if QSHADER_VIEW_COUNT >= 2
301
mat4 matrix[QSHADER_VIEW_COUNT];
302
#else
303
mat4 matrix;
304
#endif
305
float opacity;
306
};
307
308
void main()
309
{
310
#if QSHADER_VIEW_COUNT >= 2
311
gl_Position = matrix[gl_ViewIndex] * vertexCoord;
312
#else
313
gl_Position = matrix * vertexCoord;
314
#endif
315
color = vertexColor * opacity;
316
}
317
\endcode
318
319
The same source file can now be run through \c qsb or \c{qt_add_shaders()}
320
twice, once without specify the view count, and once with the view count
321
set to 2. The material can then pick the appropriate .qsb file based on
322
viewCount() at run time.
323
324
With CMake, this could looks similar to the following. With this example
325
the corresponding QSGMaterialShader is expected to choose between
326
\c{:/shaders/example.vert.qsb} and \c{:/shaders/multiview/example.vert.qsb}
327
based on the value of viewCount(). (same goes for the fragment shader)
328
329
\badcode
330
qt_add_shaders(application "application_shaders"
331
PREFIX
332
/
333
FILES
334
shaders/example.vert
335
shaders/example.frag
336
)
337
338
qt_add_shaders(application "application_multiview_shaders"
339
GLSL
340
330,300es
341
HLSL
342
61
343
MSL
344
12
345
VIEW_COUNT
346
2
347
PREFIX
348
/
349
FILES
350
shaders/example.vert
351
shaders/example.frag
352
OUTPUTS
353
shaders/multiview/example.vert
354
shaders/multiview/example.frag
355
)
356
\endcode
357
358
\note The fragment shader should be treated the same way the vertex shader
359
is, even though the fragment shader code cannot have any dependency on the
360
view count (\c{gl_ViewIndex}), for maximum portability. There are two
361
reasons for including fragment shaders too in the multiview set. One is that
362
mixing different shader versions within the same graphics pipeline can be
363
problematic, depending on the underlying graphics API: with D3D12 for
364
example, mixing HLSL shaders for shader model 5.0 and 6.1 would generate an
365
error. The other is that having \c QSHADER_VIEW_COUNT defined in fragment
366
shaders can be very useful, for example when sharing a uniform buffer layout
367
between the vertex and fragment stages.
368
369
\note For OpenGL the minimum GLSL version for vertex shaders relying on
370
\c{gl_ViewIndex} is \c 330. Lower versions may be accepted at build time,
371
but may lead to an error at run time, depending on the OpenGL implementation.
372
373
As a convenience, there is also a \c MULTIVIEW option for qt_add_shaders().
374
This first runs the \c qsb tool normally, then overrides \c VIEW_COUNT to
375
\c 2, sets \c GLSL, \c HLSL, \c MSL to some suitable defaults, and runs \c
376
qsb again, this time outputting .qsb files with a suffix added. The material
377
implementation can then use the \l QSGMaterialShader::setShaderFileName()
378
overload taking a \c viewCount argument, that automatically picks the
379
correct .qsb file.
380
381
The following is therefore mostly equivalent to the example call shown
382
above, except that no manually managed output files need to be specified.
383
Note that there can be cases when the automatically chosen shading language
384
versions are not sufficient, in which case applications should continue
385
specify everything explicitly.
386
387
\badcode
388
qt_add_shaders(application "application_multiview_shaders"
389
MULTIVIEW
390
PREFIX
391
/
392
FILES
393
shaders/example.vert
394
shaders/example.frag
395
)
396
\endcode
397
398
See \l QRhi::MultiView, \l QRhiColorAttachment::setMultiViewCount(), and
399
\l QRhiGraphicsPipeline::setMultiViewCount() for further, lower-level details
400
on multiview support in Qt. The Qt Quick scene graph renderer is prepared to
401
recognize multiview render targets, when specified via \l
402
QQuickRenderTarget::fromRhiRenderTarget() or the 3D API specific functions,
403
such as \l{QQuickRenderTarget::}{fromVulkanImage()} with an \c arraySize
404
argument greater than 1. The renderer will then propagate the view count to
405
graphics pipelines and the materials.
406
407
\since 6.8
408
*/
409
int
QSGMaterial::viewCount()
const
410
{
411
if
(m_flags.testFlag(MultiView4))
412
return
4;
413
if
(m_flags.testFlag(MultiView3))
414
return
3;
415
if
(m_flags.testFlag(MultiView2))
416
return
2;
417
return
1;
418
}
419
420
QT_END_NAMESPACE
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
qt_material_count
static QT_BEGIN_NAMESPACE int qt_material_count
\group qtquick-scenegraph-materials \title Qt Quick Scene Graph Material Classes
Definition
qsgmaterial.cpp:20
qt_print_material_count
static void qt_print_material_count()
Definition
qsgmaterial.cpp:22
qtdeclarative
src
quick
scenegraph
coreapi
qsgmaterial.cpp
Generated on
for Qt by
1.18.0