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 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 deactive() 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 explicitely.
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 specifc 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.