1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qsgmaterial.h"
43 #include "qsgrenderer_p.h"
49 \class QSGMaterialShader
50 \brief The QSGMaterialShader class implements a material renders geometry.
52 The QSGMaterial and QSGMaterialShader form a tight relationship. For one
53 scene graph (including nested graphs), there is one unique QSGMaterialShader
54 instance which encapsulates the QOpenGLShaderProgram the scene graph uses
55 to render that material, such as a shader to flat coloring of geometry.
56 Each QSGGeometryNode can have a unique QSGMaterial containing the
57 how the shader should be configured when drawing that node, such as
58 the actual color to used to render the geometry.
60 An instance of QSGMaterialShader is never created explicitely by the user,
61 it will be created on demand by the scene graph through
62 QSGMaterial::createShader(). The scene graph will make sure that there
63 is only one instance of each shader implementation through a scene graph.
65 The source code returned from vertexShader() is used to control what the
66 material does with the vertiex data that comes in from the geometry.
67 The source code returned from the fragmentShader() is used to control
68 what how the material should fill each individual pixel in the geometry.
69 The vertex and fragment source code is queried once during initialization,
70 changing what is returned from these functions later will not have
73 The activate() function is called by the scene graph when a shader is
74 is starting to be used. The deactivate function is called by the scene
75 graph when the shader is no longer going to be used. While active,
76 the scene graph may make one or more calls to updateState() which
77 will update the state of the shader for each individual geometry to
80 The attributeNames() returns the name of the attributes used in the
81 vertexShader(). These are used in the default implementation of
82 activate() and deactive() to decide whice vertex registers are enabled.
84 The initialize() function is called during program creation to allow
85 subclasses to prepare for use, such as resolve uniform names in the
86 vertexShader() and fragmentShader().
90 class Shader : public QSGMaterialShader
93 const char *vertexShader() const {
95 "attribute highp vec4 vertex; \n"
96 "uniform highp mat4 matrix; \n"
98 " gl_Position = matrix * vertex; \n"
102 const char *fragmentShader() const {
104 "uniform lowp float opacity; \n"
106 " gl_FragColor = vec4(1, 0, 0, 1) * opacity; \n"
110 char const *const *attributeNames() const
112 static char const *const names[] = { "vertex", 0 };
118 QSGMaterialShader::initialize();
119 m_id_matrix = program()->uniformLocation("matrix");
120 m_id_opacity = program()->uniformLocation("opacity");
123 void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
125 Q_ASSERT(program()->isLinked());
126 if (state.isMatrixDirty())
127 program()->setUniformValue(m_id_matrix, state.combinedMatrix());
128 if (state.isOpacityDirty())
129 program()->setUniformValue(m_id_opacity, state.opacity());
138 \warning Instances of QSGMaterialShader belongs to the Scene Graph rendering
139 thread, and cannot be used from the GUI thread.
146 Creates a new QSGMaterialShader.
148 QSGMaterialShader::QSGMaterialShader()
155 \fn QOpenGLShaderProgram *QSGMaterialShader::program() const
157 Returns the shader program used by this QSGMaterialShader.
163 This function is called by the scene graph to indicate that geometry is
164 about to be rendered using this shader.
166 State that is global for all uses of the shader, independent of the geometry
167 that is being drawn, can be setup in this function.
169 If reimplemented, make sure to either call the base class implementation to
170 enable the vertex attribute registers.
173 void QSGMaterialShader::activate()
175 Q_ASSERT(program()->isLinked());
178 char const *const *attr = attributeNames();
179 for (int i = 0; attr[i]; ++i) {
181 program()->enableAttributeArray(i);
188 This function is called by the scene graph to indicate that geometry will
189 no longer to be rendered using this shader.
191 If reimplemented, make sure to either call the base class implementation to
192 disable the vertex attribute registers.
195 void QSGMaterialShader::deactivate()
197 char const *const *attr = attributeNames();
198 for (int i = 0; attr[i]; ++i) {
200 program()->disableAttributeArray(i);
207 This function is called by the scene graph before geometry is rendered
208 to make sure the shader is in the right state.
210 The current rendering \a state is passed from the scene graph. If the state
211 indicates that any state is dirty, the updateState implementation must
212 update accordingly for the geometry to render correctly.
214 The subclass specific state, such as the color of a flat color material, should
215 be extracted from \a newMaterial to update the color uniforms accordingly.
217 The \a oldMaterial can be used to minimze state changes when updating
218 material states. The \a oldMaterial is 0 if this shader was just activated.
220 \sa activate(), deactivate()
223 void QSGMaterialShader::updateState(const RenderState & /* state */, QSGMaterial * /* newMaterial */, QSGMaterial * /* oldMaterial */)
230 This function is called when the shader is initialized to compile the
231 actual QOpenGLShaderProgram. Do not call it explicitely.
233 The default implementation will extract the vertexShader() and
234 fragmentShader() and bind the names returned from attributeNames()
235 to consecutive vertex attribute registers starting at 0.
238 void QSGMaterialShader::compile()
240 Q_ASSERT_X(!m_program.isLinked(), "QSGSMaterialShader::compile()", "Compile called multiple times!");
242 program()->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShader());
243 program()->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShader());
245 char const *const *attr = attributeNames();
247 int maxVertexAttribs = 0;
248 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
249 for (int i = 0; attr[i]; ++i) {
250 if (i >= maxVertexAttribs) {
251 qFatal("List of attribute names is either too long or not null-terminated.\n"
252 "Maximum number of attributes on this hardware is %i.\n"
253 "Vertex shader:\n%s\n"
254 "Fragment shader:\n%s\n",
255 maxVertexAttribs, vertexShader(), fragmentShader());
258 program()->bindAttributeLocation(attr[i], i);
261 for (int i = 0; attr[i]; ++i) {
263 program()->bindAttributeLocation(attr[i], i);
267 if (!program()->link()) {
268 qWarning("QSGMaterialShader: Shader compilation failed:");
269 qWarning() << program()->log();
276 \class QSGMaterialShader::RenderState
277 \brief The QSGMaterialShader::RenderState encapsulates the current rendering state
278 during a call to QSGMaterialShader::updateState().
280 The render state contains a number of accessors that the shader needs to respect
281 in order to conform to the current state of the scene graph.
283 The instance is only valid inside a call to QSGMaterialShader::updateState() and
284 should not be used outisde this function.
290 \enum QSGMaterialShader::RenderState::DirtyState
292 \value DirtyMatrix Used to indicate that the matrix has changed and must be updated.
294 \value DirtyOpacity Used to indicate that the opacity has changed and must be updated.
300 \fn bool QSGMaterialShader::RenderState::isMatrixDirty() const
302 Convenience function to check if the dirtyStates() indicates that the matrix
309 \fn bool QSGMaterialShader::RenderState::isOpacityDirty() const
311 Conveience function to check if the dirtyStates() indicates that the opacity
318 \fn QSGMaterialShader::RenderState::DirtyStates QSGMaterialShader::RenderState::dirtyStates() const
320 Returns which rendering states that have changed and needs to be updated
321 for geometry rendered with this material to conform to the current
328 Returns the accumulated opacity to be used for rendering
331 float QSGMaterialShader::RenderState::opacity() const
334 return static_cast<const QSGRenderer *>(m_data)->currentOpacity();
338 Returns the modelview determinant to be used for rendering
341 float QSGMaterialShader::RenderState::determinant() const
344 return static_cast<const QSGRenderer *>(m_data)->determinant();
348 Returns the matrix combined of modelview matrix and project matrix.
351 QMatrix4x4 QSGMaterialShader::RenderState::combinedMatrix() const
354 return static_cast<const QSGRenderer *>(m_data)->currentCombinedMatrix();
360 Returns the model view matrix.
362 If the material has the RequiresFullMatrix flag
363 set, this is guaranteed to be the complete transform
364 matrix calculated from the scenegraph.
366 However, if this flag is not set, the renderer may
367 choose to alter this matrix. For example, it may
368 pre-transform vertices on the CPU and set this matrix
371 In a situation such as the above, it is still possible
372 to retrieve the actual matrix determinant by setting
373 the RequiresDeterminant flag in the material and
374 calling the determinant() accessor.
377 QMatrix4x4 QSGMaterialShader::RenderState::modelViewMatrix() const
380 return static_cast<const QSGRenderer *>(m_data)->currentModelViewMatrix();
386 Returns the viewport rect of the surface being rendered to.
389 QRect QSGMaterialShader::RenderState::viewportRect() const
392 return static_cast<const QSGRenderer *>(m_data)->viewportRect();
398 Returns the device rect of the surface being rendered to
401 QRect QSGMaterialShader::RenderState::deviceRect() const
404 return static_cast<const QSGRenderer *>(m_data)->deviceRect();
410 Returns the QOpenGLContext that is being used for rendering
413 QOpenGLContext *QSGMaterialShader::RenderState::context() const
415 return static_cast<const QSGRenderer *>(m_data)->glContext();
420 static int qt_material_count = 0;
422 static void qt_print_material_count()
424 qDebug("Number of leaked materials: %i", qt_material_count);
425 qt_material_count = -1;
430 \class QSGMaterialType
431 \brief The QSGMaterialType class is used as a unique type token in combination with QSGMaterial.
433 It serves no purpose outside the QSGMaterial::type() function.
438 \brief The QSGMaterial class encapsulates rendering state for a shader program.
440 The QSGMaterial and QSGMaterialShader subclasses form a tight relationship. For
441 one scene graph (including nested graphs), there is one unique QSGMaterialShader
442 instance which encapsulates the QOpenGLShaderProgram the scene graph uses
443 to render that material, such as a shader to flat coloring of geometry.
444 Each QSGGeometryNode can have a unique QSGMaterial containing the
445 how the shader should be configured when drawing that node, such as
446 the actual color to used to render the geometry.
448 The QSGMaterial has two virtual functions that both need to be implemented.
449 The function type() should return a unique instance for all instances of a
450 specific subclass. The createShader() function should return a new instance
451 of QSGMaterialShader, specific to the subclass of QSGMaterial.
453 A minimal QSGMaterial implementation could look like this:
455 class Material : public QSGMaterial
458 QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
459 QSGMaterialShader *createShader() const { return new Shader; }
463 \warning Instances of QSGMaterial belongs to the Scene Graph rendering thread,
464 and cannot be used from the GUI thread.
467 QSGMaterial::QSGMaterial()
472 static bool atexit_registered = false;
473 if (!atexit_registered) {
474 atexit(qt_print_material_count);
475 atexit_registered = true;
480 QSGMaterial::~QSGMaterial()
484 if (qt_material_count < 0)
485 qDebug("Material destroyed after qt_print_material_count() was called.");
492 \enum QSGMaterial::Flag
494 \value Blending Set this flag to true if the material requires GL_BLEND to be
495 enabled during rendering.
497 \value RequiresDeterminant Set this flag to true if the material relies on
498 the determinant of the matrix of the geometry nodes for rendering.
500 \value RequiresFullMatrix Set this flag to true if the material relies on
501 the full matrix of the geometry nodes for rendering.
507 Sets the flags \a flags on this material if \a on is true;
508 otherwise clears the attribute.
511 void QSGMaterial::setFlag(Flags flags, bool on)
522 Compares this material to \a other and returns 0 if they are equal; -1 if
523 this material should sort before \a other and 1 if \a other should sort
526 The scene graph can reorder geometry nodes to minimize state changes.
527 The compare function is called during the sorting process so that
528 the materials can be sorted to minimize state changes in each
529 call to QSGMaterialShader::updateState().
531 The this pointer and \a other is guaranteed to have the same type().
534 int QSGMaterial::compare(const QSGMaterial *other) const
536 Q_ASSERT(other && type() == other->type());
537 return qint64(this) - qint64(other);
543 \fn QSGMaterialType QSGMaterial::type() const
545 This function is called by the scene graph to return a unique instance
552 \fn QSGMaterialShader *QSGMaterial::createShader() const
554 This function returns a new instance of a the QSGMaterialShader
555 implementatation used to render geometry for a specifc implementation
558 The function will be called only once for each material type that
559 exists in the scene graph and will be cached internally.