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