1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtQml module of the Qt Toolkit.
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 Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
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 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include "qsgmaterial.h"
43
#include "qsgrenderer_p.h"
49
\class QSGMaterialShader
50
\brief The QSGMaterialShader class represents an OpenGL shader program
54
The QSGMaterialShader API is very low-level. A more convenient API, which
55
provides almost all the same features, is available through
56
QSGSimpleMaterialShader.
58
The QSGMaterial and QSGMaterialShader form a tight relationship. For one
59
scene graph (including nested graphs), there is one unique QSGMaterialShader
60
instance which encapsulates the QOpenGLShaderProgram the scene graph uses
61
to render that material, such as a shader to flat coloring of geometry.
62
Each QSGGeometryNode can have a unique QSGMaterial containing the
63
how the shader should be configured when drawing that node, such as
64
the actual color used to render the geometry.
66
An instance of QSGMaterialShader is never created explicitly by the user,
67
it will be created on demand by the scene graph through
68
QSGMaterial::createShader(). The scene graph will make sure that there
69
is only one instance of each shader implementation through a scene graph.
71
The source code returned from vertexShader() is used to control what the
72
material does with the vertiex data that comes in from the geometry.
73
The source code returned from the fragmentShader() is used to control
74
what how the material should fill each individual pixel in the geometry.
75
The vertex and fragment source code is queried once during initialization,
76
changing what is returned from these functions later will not have
79
The activate() function is called by the scene graph when a shader is
80
is starting to be used. The deactivate function is called by the scene
81
graph when the shader is no longer going to be used. While active,
82
the scene graph may make one or more calls to updateState() which
83
will update the state of the shader for each individual geometry to
86
The attributeNames() returns the name of the attributes used in the
87
vertexShader(). These are used in the default implementation of
88
activate() and deactivate() to decide whice vertex registers are enabled.
90
The initialize() function is called during program creation to allow
91
subclasses to prepare for use, such as resolve uniform names in the
92
vertexShader() and fragmentShader().
96
class Shader : public QSGMaterialShader
99
const char *vertexShader() const {
101
"attribute highp vec4 vertex; \n"
102
"uniform highp mat4 matrix; \n"
104
" gl_Position = matrix * vertex; \n"
108
const char *fragmentShader() const {
110
"uniform lowp float opacity; \n"
112
" gl_FragColor = vec4(1, 0, 0, 1) * opacity; \n"
116
char const *const *attributeNames() const
118
static char const *const names[] = { "vertex", 0 };
124
QSGMaterialShader::initialize();
125
m_id_matrix = program()->uniformLocation("matrix");
126
m_id_opacity = program()->uniformLocation("opacity");
129
void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
131
Q_ASSERT(program()->isLinked());
132
if (state.isMatrixDirty())
133
program()->setUniformValue(m_id_matrix, state.combinedMatrix());
134
if (state.isOpacityDirty())
135
program()->setUniformValue(m_id_opacity, state.opacity());
144
\warning Instances of QSGMaterialShader belongs to the Scene Graph rendering
145
thread, and cannot be used from the GUI thread.
152
Creates a new QSGMaterialShader.
154
QSGMaterialShader::QSGMaterialShader()
159
\fn QSGMaterialShader::~QSGMaterialShader()
164
\fn char const *const *QSGMaterialShader::attributeNames() const
166
Returns a zero-terminated array describing the names of the
167
attributes used in the vertex shader.
169
This function is called when the shader is compiled to specify
170
which attributes exist. The order of the attribute names
171
defines the attribute register position in the vertex shader.
176
\fn const char *QSGMaterialShader::vertexShader() const
178
Called when the shader is being initialized to get the vertex
181
The contents returned from this function should never change.
186
\fn const char *QSGMaterialShader::fragmentShader() const
188
Called when the shader is being initialized to get the fragment
191
The contents returned from this function should never change.
196
\fn QOpenGLShaderProgram *QSGMaterialShader::program()
198
Returns the shader program used by this QSGMaterialShader.
203
\fn void QSGMaterialShader::initialize()
205
Reimplement this function to do one-time initialization when the
206
shader program is compiled. The OpenGL shader program is compiled
207
and linked, but not bound, when this function is called.
212
This function is called by the scene graph to indicate that geometry is
213
about to be rendered using this shader.
215
State that is global for all uses of the shader, independent of the geometry
216
that is being drawn, can be setup in this function.
218
If reimplemented, make sure to either call the base class implementation to
219
enable the vertex attribute registers.
222
void QSGMaterialShader::activate()
224
Q_ASSERT(program()->isLinked());
227
char const *const *attr = attributeNames();
228
for (int i = 0; attr[i]; ++i) {
230
program()->enableAttributeArray(i);
237
This function is called by the scene graph to indicate that geometry will
238
no longer to be rendered using this shader.
240
If reimplemented, make sure to either call the base class implementation to
241
disable the vertex attribute registers.
244
void QSGMaterialShader::deactivate()
246
char const *const *attr = attributeNames();
247
for (int i = 0; attr[i]; ++i) {
249
program()->disableAttributeArray(i);
256
This function is called by the scene graph before geometry is rendered
257
to make sure the shader is in the right state.
259
The current rendering \a state is passed from the scene graph. If the state
260
indicates that any state is dirty, the updateState implementation must
261
update accordingly for the geometry to render correctly.
263
The subclass specific state, such as the color of a flat color material, should
264
be extracted from \a newMaterial to update the color uniforms accordingly.
266
The \a oldMaterial can be used to minimze state changes when updating
267
material states. The \a oldMaterial is 0 if this shader was just activated.
269
\sa activate(), deactivate()
272
void QSGMaterialShader::updateState(const RenderState & /* state */, QSGMaterial * /* newMaterial */, QSGMaterial * /* oldMaterial */)
279
This function is called when the shader is initialized to compile the
280
actual QOpenGLShaderProgram. Do not call it explicitly.
282
The default implementation will extract the vertexShader() and
283
fragmentShader() and bind the names returned from attributeNames()
284
to consecutive vertex attribute registers starting at 0.
287
void QSGMaterialShader::compile()
289
Q_ASSERT_X(!m_program.isLinked(), "QSGSMaterialShader::compile()", "Compile called multiple times!");
291
program()->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShader());
292
program()->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShader());
294
char const *const *attr = attributeNames();
296
int maxVertexAttribs = 0;
297
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
298
for (int i = 0; attr[i]; ++i) {
299
if (i >= maxVertexAttribs) {
300
qFatal("List of attribute names is either too long or not null-terminated.\n"
301
"Maximum number of attributes on this hardware is %i.\n"
302
"Vertex shader:\n%s\n"
303
"Fragment shader:\n%s\n",
304
maxVertexAttribs, vertexShader(), fragmentShader());
307
program()->bindAttributeLocation(attr[i], i);
310
for (int i = 0; attr[i]; ++i) {
312
program()->bindAttributeLocation(attr[i], i);
316
if (!program()->link()) {
317
qWarning("QSGMaterialShader: Shader compilation failed:");
318
qWarning() << program()->log();
325
\class QSGMaterialShader::RenderState
326
\brief The QSGMaterialShader::RenderState encapsulates the current rendering state
327
during a call to QSGMaterialShader::updateState().
329
The render state contains a number of accessors that the shader needs to respect
330
in order to conform to the current state of the scene graph.
332
The instance is only valid inside a call to QSGMaterialShader::updateState() and
333
should not be used outisde this function.
339
\enum QSGMaterialShader::RenderState::DirtyState
341
\value DirtyMatrix Used to indicate that the matrix has changed and must be updated.
343
\value DirtyOpacity Used to indicate that the opacity has changed and must be updated.
349
\fn bool QSGMaterialShader::RenderState::isMatrixDirty() const
351
Returns \c true if the dirtyStates() contain the dirty matrix state,
352
otherwise returns \c false.
358
\fn bool QSGMaterialShader::RenderState::isOpacityDirty() const
360
Returns \c true if the dirtyStates() contains the dirty opacity state,
361
otherwise returns \c false.
367
\fn QSGMaterialShader::RenderState::DirtyStates QSGMaterialShader::RenderState::dirtyStates() const
369
Returns which rendering states that have changed and needs to be updated
370
for geometry rendered with this material to conform to the current
377
Returns the accumulated opacity to be used for rendering.
380
float QSGMaterialShader::RenderState::opacity() const
383
return static_cast<const QSGRenderer *>(m_data)->currentOpacity();
387
Returns the modelview determinant to be used for rendering.
390
float QSGMaterialShader::RenderState::determinant() const
393
return static_cast<const QSGRenderer *>(m_data)->determinant();
397
Returns the matrix combined of modelview matrix and project matrix.
400
QMatrix4x4 QSGMaterialShader::RenderState::combinedMatrix() const
403
return static_cast<const QSGRenderer *>(m_data)->currentCombinedMatrix();
409
Returns the model view matrix.
411
If the material has the RequiresFullMatrix flag
412
set, this is guaranteed to be the complete transform
413
matrix calculated from the scenegraph.
415
However, if this flag is not set, the renderer may
416
choose to alter this matrix. For example, it may
417
pre-transform vertices on the CPU and set this matrix
420
In a situation such as the above, it is still possible
421
to retrieve the actual matrix determinant by setting
422
the RequiresDeterminant flag in the material and
423
calling the determinant() accessor.
426
QMatrix4x4 QSGMaterialShader::RenderState::modelViewMatrix() const
429
return static_cast<const QSGRenderer *>(m_data)->currentModelViewMatrix();
435
Returns the viewport rect of the surface being rendered to.
438
QRect QSGMaterialShader::RenderState::viewportRect() const
441
return static_cast<const QSGRenderer *>(m_data)->viewportRect();
447
Returns the device rect of the surface being rendered to
450
QRect QSGMaterialShader::RenderState::deviceRect() const
453
return static_cast<const QSGRenderer *>(m_data)->deviceRect();
459
Returns the QOpenGLContext that is being used for rendering
462
QOpenGLContext *QSGMaterialShader::RenderState::context() const
464
return static_cast<const QSGRenderer *>(m_data)->glContext();
469
static int qt_material_count = 0;
471
static void qt_print_material_count()
473
qDebug("Number of leaked materials: %i", qt_material_count);
474
qt_material_count = -1;
479
\class QSGMaterialType
480
\brief The QSGMaterialType class is used as a unique type token in combination with QSGMaterial.
483
It serves no purpose outside the QSGMaterial::type() function.
488
\brief The QSGMaterial class encapsulates rendering state for a shader program.
491
The QSGMaterial API is very low-level. A more convenient API, which
492
provides almost all the same features, is available through
493
QSGSimpleMaterialShader.
495
The QSGMaterial and QSGMaterialShader subclasses form a tight relationship. For
496
one scene graph (including nested graphs), there is one unique QSGMaterialShader
497
instance which encapsulates the QOpenGLShaderProgram the scene graph uses
498
to render that material, such as a shader to flat coloring of geometry.
499
Each QSGGeometryNode can have a unique QSGMaterial containing the
500
how the shader should be configured when drawing that node, such as
501
the actual color to used to render the geometry.
503
The QSGMaterial has two virtual functions that both need to be implemented.
504
The function type() should return a unique instance for all instances of a
505
specific subclass. The createShader() function should return a new instance
506
of QSGMaterialShader, specific to the subclass of QSGMaterial.
508
A minimal QSGMaterial implementation could look like this:
510
class Material : public QSGMaterial
513
QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
514
QSGMaterialShader *createShader() const { return new Shader; }
518
\warning Instances of QSGMaterial belongs to the Scene Graph rendering thread,
519
and cannot be used from the GUI thread.
526
QSGMaterial::QSGMaterial()
531
static bool atexit_registered = false;
532
if (!atexit_registered) {
533
atexit(qt_print_material_count);
534
atexit_registered = true;
544
QSGMaterial::~QSGMaterial()
548
if (qt_material_count < 0)
549
qDebug("Material destroyed after qt_print_material_count() was called.");
556
\enum QSGMaterial::Flag
558
\value Blending Set this flag to true if the material requires GL_BLEND to be
559
enabled during rendering.
561
\value RequiresDeterminant Set this flag to true if the material relies on
562
the determinant of the matrix of the geometry nodes for rendering.
564
\value RequiresFullMatrixExceptTranslate Set this flag to true if the material
565
relies on the full matrix of the geometry nodes for rendering, except the translation part.
567
\value RequiresFullMatrix Set this flag to true if the material relies on
568
the full matrix of the geometry nodes for rendering.
572
\fn QSGMaterial::Flags QSGMaterial::flags() const
574
Returns the material's flags.
580
Sets the flags \a flags on this material if \a on is true;
581
otherwise clears the attribute.
584
void QSGMaterial::setFlag(Flags flags, bool on)
595
Compares this material to \a other and returns 0 if they are equal; -1 if
596
this material should sort before \a other and 1 if \a other should sort
599
The scene graph can reorder geometry nodes to minimize state changes.
600
The compare function is called during the sorting process so that
601
the materials can be sorted to minimize state changes in each
602
call to QSGMaterialShader::updateState().
604
The this pointer and \a other is guaranteed to have the same type().
607
int QSGMaterial::compare(const QSGMaterial *other) const
609
Q_ASSERT(other && type() == other->type());
610
return qint64(this) - qint64(other);
616
\fn QSGMaterialType QSGMaterial::type() const
618
This function is called by the scene graph to return a unique instance
625
\fn QSGMaterialShader *QSGMaterial::createShader() const
627
This function returns a new instance of a the QSGMaterialShader
628
implementatation used to render geometry for a specific implementation
631
The function will be called only once for each material type that
632
exists in the scene graph and will be cached internally.