1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQuick module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qsgmaterial.h"
41#include "qsgrenderer_p.h"
42
43QT_BEGIN_NAMESPACE
44
45#ifndef QT_NO_DEBUG
46bool qsg_material_failure = false;
47bool qsg_test_and_clear_material_failure()
48{
49 bool fail = qsg_material_failure;
50 qsg_material_failure = false;
51 return fail;
52}
53
54void qsg_set_material_failure()
55{
56 qsg_material_failure = true;
57}
58#endif
59
60#ifndef QT_NO_DEBUG
61static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK");
62#endif
63
64/*!
65 \group qtquick-scenegraph-materials
66 \title Qt Quick Scene Graph Material Classes
67 \brief classes used to define materials in the Qt Quick Scene Graph.
68
69 This page lists the material classes in \l {Qt Quick}'s
70 \l {scene graph}{Qt Quick Scene Graph}.
71 */
72
73#ifndef QT_NO_DEBUG
74static int qt_material_count = 0;
75
76static void qt_print_material_count()
77{
78 qDebug("Number of leaked materials: %i", qt_material_count);
79 qt_material_count = -1;
80}
81#endif
82
83/*!
84 \class QSGMaterialType
85 \brief The QSGMaterialType class is used as a unique type token in combination with QSGMaterial.
86 \inmodule QtQuick
87 \ingroup qtquick-scenegraph-materials
88
89 It serves no purpose outside the QSGMaterial::type() function.
90
91 \note All classes with QSG prefix should be used solely on the scene graph's
92 rendering thread. See \l {Scene Graph and Rendering} for more information.
93 */
94
95/*!
96 \class QSGMaterial
97 \brief The QSGMaterial class encapsulates rendering state for a shader program.
98 \inmodule QtQuick
99 \ingroup qtquick-scenegraph-materials
100
101 The QSGMaterial, QSGMaterialShader and QSGMaterialRhiShader subclasses
102 form a tight relationship. For one scene graph (including nested graphs),
103 there is one unique QSGMaterialShader or QSGMaterialRhiShader instance
104 which encapsulates the shaders the scene graph uses to render that
105 material, such as a shader to flat coloring of geometry. Each
106 QSGGeometryNode can have a unique QSGMaterial containing the how the shader
107 should be configured when drawing that node, such as the actual color to
108 used to render the geometry.
109
110 QSGMaterial has two virtual functions that both need to be implemented. The
111 function type() should return a unique instance for all instances of a
112 specific subclass. The createShader() function should return a new instance
113 of QSGMaterialShader or QSGMaterialRhiShader, specific to that subclass of
114 QSGMaterial.
115
116 A minimal QSGMaterial implementation could look like this:
117 \code
118 class Material : public QSGMaterial
119 {
120 public:
121 QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
122 QSGMaterialShader *createShader() const { return new Shader; }
123 };
124 \endcode
125
126 This is suitable only for the OpenGL-based, traditional renderer of the
127 scene graph. When using the new, graphics API abstracted renderer,
128 materials must create QSGMaterialRhiShader instances instead, or in
129 addition:
130 \code
131 class Material : public QSGMaterial
132 {
133 public:
134 Material() { setFlag(SupportsRhiShader, true); }
135 QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
136 QSGMaterialShader *createShader() {
137 if (flags().testFlag(RhiShaderWanted)) {
138 return new RhiShader;
139 } else {
140 // this is optional, relevant for materials that intend to be usable with the legacy OpenGL renderer as well
141 return new Shader;
142 }
143 }
144 };
145 \endcode
146
147 \note All classes with QSG prefix should be used solely on the scene graph's
148 rendering thread. See \l {Scene Graph and Rendering} for more information.
149 */
150
151/*!
152 \internal
153 */
154
155QSGMaterial::QSGMaterial()
156 : m_flags(nullptr)
157{
158 Q_UNUSED(m_reserved);
159#ifndef QT_NO_DEBUG
160 if (qsg_leak_check) {
161 ++qt_material_count;
162 static bool atexit_registered = false;
163 if (!atexit_registered) {
164 atexit(qt_print_material_count);
165 atexit_registered = true;
166 }
167 }
168#endif
169}
170
171
172/*!
173 \internal
174 */
175
176QSGMaterial::~QSGMaterial()
177{
178#ifndef QT_NO_DEBUG
179 if (qsg_leak_check) {
180 --qt_material_count;
181 if (qt_material_count < 0)
182 qDebug("Material destroyed after qt_print_material_count() was called.");
183 }
184#endif
185}
186
187
188
189/*!
190 \enum QSGMaterial::Flag
191
192 \value Blending Set this flag to true if the material requires GL_BLEND to be
193 enabled during rendering.
194
195 \value RequiresDeterminant Set this flag to true if the material relies on
196 the determinant of the matrix of the geometry nodes for rendering.
197
198 \value RequiresFullMatrixExceptTranslate Set this flag to true if the material
199 relies on the full matrix of the geometry nodes for rendering, except the translation part.
200
201 \value RequiresFullMatrix Set this flag to true if the material relies on
202 the full matrix of the geometry nodes for rendering.
203
204 \value CustomCompileStep Starting with Qt 5.2, the scene graph will not always call
205 QSGMaterialShader::compile() when its shader program is compiled and linked.
206 Set this flag to enforce that the function is called.
207
208 \value SupportsRhiShader Starting with Qt 5.14, the scene graph supports
209 QSGMaterialRhiShader as an alternative to the OpenGL-specific
210 QSGMaterialShader. Set this flag to indicate createShader() is capable of
211 returning QSGMaterialRhiShader instances when the RhiShaderWanted flag is
212 set.
213
214 \value RhiShaderWanted This flag is set by the scene graph, not by the
215 QSGMaterial. When set, and that can only happen when SupportsRhiShader was
216 set by the material, it indicates that createShader() must return a
217 QSGMaterialRhiShader instance instead of QSGMaterialShader.
218 */
219
220/*!
221 \fn QSGMaterial::Flags QSGMaterial::flags() const
222
223 Returns the material's flags.
224 */
225
226
227
228/*!
229 Sets the flags \a flags on this material if \a on is true;
230 otherwise clears the attribute.
231*/
232
233void QSGMaterial::setFlag(Flags flags, bool on)
234{
235 if (on)
236 m_flags |= flags;
237 else
238 m_flags &= ~flags;
239}
240
241
242
243/*!
244 Compares this material to \a other and returns 0 if they are equal; -1 if
245 this material should sort before \a other and 1 if \a other should sort
246 before.
247
248 The scene graph can reorder geometry nodes to minimize state changes.
249 The compare function is called during the sorting process so that
250 the materials can be sorted to minimize state changes in each
251 call to QSGMaterialShader::updateState().
252
253 The this pointer and \a other is guaranteed to have the same type().
254 */
255
256int QSGMaterial::compare(const QSGMaterial *other) const
257{
258 Q_ASSERT(other && type() == other->type());
259 return qint64(this) - qint64(other);
260}
261
262
263
264/*!
265 \fn QSGMaterialType QSGMaterial::type() const
266
267 This function is called by the scene graph to return a unique instance
268 per subclass.
269 */
270
271
272
273/*!
274 \fn QSGMaterialShader *QSGMaterial::createShader() const
275
276 This function returns a new instance of a the QSGMaterialShader
277 implementatation used to render geometry for a specific implementation
278 of QSGMaterial.
279
280 The function will be called only once for each material type that
281 exists in the scene graph and will be cached internally.
282
283 When the QSGMaterial reports SupportsRhiShader in flags(), the scene graph
284 may request a QSGMaterialRhiShader instead of QSGMaterialShader. This is
285 indicated by having the RhiShaderWanted flag set. In this case the return
286 value must be a QSGRhiMaterialShader subclass.
287*/
288
289QT_END_NAMESPACE
290