1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** 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();
340 Returns the matrix combined of modelview matrix and project matrix.
343 QMatrix4x4 QSGMaterialShader::RenderState::combinedMatrix() const
346 return static_cast<const QSGRenderer *>(m_data)->currentCombinedMatrix();
352 Returns the model view matrix.
355 QMatrix4x4 QSGMaterialShader::RenderState::modelViewMatrix() const
358 return static_cast<const QSGRenderer *>(m_data)->currentModelViewMatrix();
364 Returns the viewport rect of the surface being rendered to.
367 QRect QSGMaterialShader::RenderState::viewportRect() const
370 return static_cast<const QSGRenderer *>(m_data)->viewportRect();
376 Returns the device rect of the surface being rendered to
379 QRect QSGMaterialShader::RenderState::deviceRect() const
382 return static_cast<const QSGRenderer *>(m_data)->deviceRect();
388 Returns the QOpenGLContext that is being used for rendering
391 QOpenGLContext *QSGMaterialShader::RenderState::context() const
393 return static_cast<const QSGRenderer *>(m_data)->glContext();
398 static int qt_material_count = 0;
400 static void qt_print_material_count()
402 qDebug("Number of leaked materials: %i", qt_material_count);
403 qt_material_count = -1;
408 \class QSGMaterialType
409 \brief The QSGMaterialType class is used as a unique type token in combination with QSGMaterial.
411 It serves no purpose outside the QSGMaterial::type() function.
416 \brief The QSGMaterial class encapsulates rendering state for a shader program.
418 The QSGMaterial and QSGMaterialShader subclasses form a tight relationship. For
419 one scene graph (including nested graphs), there is one unique QSGMaterialShader
420 instance which encapsulates the QOpenGLShaderProgram the scene graph uses
421 to render that material, such as a shader to flat coloring of geometry.
422 Each QSGGeometryNode can have a unique QSGMaterial containing the
423 how the shader should be configured when drawing that node, such as
424 the actual color to used to render the geometry.
426 The QSGMaterial has two virtual functions that both need to be implemented.
427 The function type() should return a unique instance for all instances of a
428 specific subclass. The createShader() function should return a new instance
429 of QSGMaterialShader, specific to the subclass of QSGMaterial.
431 A minimal QSGMaterial implementation could look like this:
433 class Material : public QSGMaterial
436 QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
437 QSGMaterialShader *createShader() const { return new Shader; }
441 \warning Instances of QSGMaterial belongs to the Scene Graph rendering thread,
442 and cannot be used from the GUI thread.
445 QSGMaterial::QSGMaterial()
450 static bool atexit_registered = false;
451 if (!atexit_registered) {
452 atexit(qt_print_material_count);
453 atexit_registered = true;
458 QSGMaterial::~QSGMaterial()
462 if (qt_material_count < 0)
463 qDebug("Material destroyed after qt_print_material_count() was called.");
470 \enum QSGMaterial::Flag
472 \value Blending Set this flag to true if the material requires GL_BLEND to be
473 enabled during rendering.
479 Sets the flags \a flags on this material if \a on is true;
480 otherwise clears the attribute.
483 void QSGMaterial::setFlag(Flags flags, bool on)
494 Compares this material to \a other and returns 0 if they are equal; -1 if
495 this material should sort before \a other and 1 if \a other should sort
498 The scene graph can reorder geometry nodes to minimize state changes.
499 The compare function is called during the sorting process so that
500 the materials can be sorted to minimize state changes in each
501 call to QSGMaterialShader::updateState().
503 The this pointer and \a other is guaranteed to have the same type().
506 int QSGMaterial::compare(const QSGMaterial *other) const
508 Q_ASSERT(other && type() == other->type());
509 return qint64(this) - qint64(other);
515 \fn QSGMaterialType QSGMaterial::type() const
517 This function is called by the scene graph to return a unique instance
524 \fn QSGMaterialShader *QSGMaterial::createShader() const
526 This function returns a new instance of a the QSGMaterialShader
527 implementatation used to render geometry for a specifc implementation
530 The function will be called only once for each material type that
531 exists in the scene graph and will be cached internally.