Rename QDeclarative symbols to QQuick and QQml
[profile/ivi/qtdeclarative.git] / src / quick / scenegraph / coreapi / qsgmaterial.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qsgmaterial.h"
43 #include "qsgrenderer_p.h"
44
45 QT_BEGIN_NAMESPACE
46
47
48 /*!
49     \class QSGMaterialShader
50     \brief The QSGMaterialShader class implements a material renders geometry.
51
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.
59
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.
64
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
71     any effect.
72
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
78     render.
79
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.
83
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().
87
88     A minimal example:
89     \code
90         class Shader : public QSGMaterialShader
91         {
92         public:
93             const char *vertexShader() const {
94                 return
95                 "attribute highp vec4 vertex;          \n"
96                 "uniform highp mat4 matrix;            \n"
97                 "void main() {                         \n"
98                 "    gl_Position = matrix * vertex;    \n"
99                 "}";
100             }
101
102             const char *fragmentShader() const {
103                 return
104                 "uniform lowp float opacity;                            \n"
105                 "void main() {                                          \n"
106                         "    gl_FragColor = vec4(1, 0, 0, 1) * opacity; \n"
107                 "}";
108             }
109
110             char const *const *attributeNames() const
111             {
112                 static char const *const names[] = { "vertex", 0 };
113                 return names;
114             }
115
116             void initialize()
117             {
118                 QSGMaterialShader::initialize();
119                 m_id_matrix = program()->uniformLocation("matrix");
120                 m_id_opacity = program()->uniformLocation("opacity");
121             }
122
123             void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
124             {
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());
130             }
131
132         private:
133             int m_id_matrix;
134             int m_id_opacity;
135         };
136     \endcode
137
138     \warning Instances of QSGMaterialShader belongs to the Scene Graph rendering
139     thread, and cannot be used from the GUI thread.
140
141  */
142
143
144
145 /*!
146     Creates a new QSGMaterialShader.
147  */
148 QSGMaterialShader::QSGMaterialShader()
149 {
150 }
151
152
153
154 /*!
155     \fn QOpenGLShaderProgram *QSGMaterialShader::program() const
156
157     Returns the shader program used by this QSGMaterialShader.
158  */
159
160
161
162 /*!
163     This function is called by the scene graph to indicate that geometry is
164     about to be rendered using this shader.
165
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.
168
169     If reimplemented, make sure to either call the base class implementation to
170     enable the vertex attribute registers.
171  */
172
173 void QSGMaterialShader::activate()
174 {
175     Q_ASSERT(program()->isLinked());
176
177     program()->bind();
178     char const *const *attr = attributeNames();
179     for (int i = 0; attr[i]; ++i) {
180         if (*attr[i])
181             program()->enableAttributeArray(i);
182     }
183 }
184
185
186
187 /*!
188     This function is called by the scene graph to indicate that geometry will
189     no longer to be rendered using this shader.
190
191     If reimplemented, make sure to either call the base class implementation to
192     disable the vertex attribute registers.
193  */
194
195 void QSGMaterialShader::deactivate()
196 {
197     char const *const *attr = attributeNames();
198     for (int i = 0; attr[i]; ++i) {
199         if (*attr[i])
200             program()->disableAttributeArray(i);
201     }
202 }
203
204
205
206 /*!
207     This function is called by the scene graph before geometry is rendered
208     to make sure the shader is in the right state.
209
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.
213
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.
216
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.
219
220     \sa activate(), deactivate()
221  */
222
223 void QSGMaterialShader::updateState(const RenderState & /* state */, QSGMaterial * /* newMaterial */, QSGMaterial * /* oldMaterial */)
224 {
225 }
226
227
228
229 /*!
230     This function is called when the shader is initialized to compile the
231     actual QOpenGLShaderProgram. Do not call it explicitely.
232
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.
236  */
237
238 void QSGMaterialShader::compile()
239 {
240     Q_ASSERT_X(!m_program.isLinked(), "QSGSMaterialShader::compile()", "Compile called multiple times!");
241
242     program()->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShader());
243     program()->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShader());
244
245     char const *const *attr = attributeNames();
246 #ifndef QT_NO_DEBUG
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());
256         }
257         if (*attr[i])
258             program()->bindAttributeLocation(attr[i], i);
259     }
260 #else
261     for (int i = 0; attr[i]; ++i) {
262         if (*attr[i])
263             program()->bindAttributeLocation(attr[i], i);
264     }
265 #endif
266
267     if (!program()->link()) {
268         qWarning("QSGMaterialShader: Shader compilation failed:");
269         qWarning() << program()->log();
270     }
271 }
272
273
274
275 /*!
276     \class QSGMaterialShader::RenderState
277     \brief The QSGMaterialShader::RenderState encapsulates the current rendering state
278     during a call to QSGMaterialShader::updateState().
279
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.
282
283     The instance is only valid inside a call to QSGMaterialShader::updateState() and
284     should not be used outisde this function.
285  */
286
287
288
289 /*!
290     \enum QSGMaterialShader::RenderState::DirtyState
291
292     \value DirtyMatrix Used to indicate that the matrix has changed and must be updated.
293
294     \value DirtyOpacity Used to indicate that the opacity has changed and must be updated.
295  */
296
297
298
299 /*!
300     \fn bool QSGMaterialShader::RenderState::isMatrixDirty() const
301
302     Convenience function to check if the dirtyStates() indicates that the matrix
303     needs to be updated.
304  */
305
306
307
308 /*!
309     \fn bool QSGMaterialShader::RenderState::isOpacityDirty() const
310
311     Conveience function to check if the dirtyStates() indicates that the opacity
312     needs to be updated.
313  */
314
315
316
317 /*!
318     \fn QSGMaterialShader::RenderState::DirtyStates QSGMaterialShader::RenderState::dirtyStates() const
319
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
322     rendering state.
323  */
324
325
326
327 /*!
328     Returns the accumulated opacity to be used for rendering
329  */
330
331 float QSGMaterialShader::RenderState::opacity() const
332 {
333     Q_ASSERT(m_data);
334     return static_cast<const QSGRenderer *>(m_data)->currentOpacity();
335 }
336
337 /*!
338     Returns the modelview determinant to be used for rendering
339  */
340
341 float QSGMaterialShader::RenderState::determinant() const
342 {
343     Q_ASSERT(m_data);
344     return static_cast<const QSGRenderer *>(m_data)->determinant();
345 }
346
347 /*!
348     Returns the matrix combined of modelview matrix and project matrix.
349  */
350
351 QMatrix4x4 QSGMaterialShader::RenderState::combinedMatrix() const
352 {
353     Q_ASSERT(m_data);
354     return static_cast<const QSGRenderer *>(m_data)->currentCombinedMatrix();
355 }
356
357
358
359 /*!
360     Returns the model view matrix.
361
362     If the material has the RequiresFullMatrix flag
363     set, this is guaranteed to be the complete transform
364     matrix calculated from the scenegraph.
365
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
369     to identity.
370
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.
375  */
376
377 QMatrix4x4 QSGMaterialShader::RenderState::modelViewMatrix() const
378 {
379     Q_ASSERT(m_data);
380     return static_cast<const QSGRenderer *>(m_data)->currentModelViewMatrix();
381 }
382
383
384
385 /*!
386     Returns the viewport rect of the surface being rendered to.
387  */
388
389 QRect QSGMaterialShader::RenderState::viewportRect() const
390 {
391     Q_ASSERT(m_data);
392     return static_cast<const QSGRenderer *>(m_data)->viewportRect();
393 }
394
395
396
397 /*!
398     Returns the device rect of the surface being rendered to
399  */
400
401 QRect QSGMaterialShader::RenderState::deviceRect() const
402 {
403     Q_ASSERT(m_data);
404     return static_cast<const QSGRenderer *>(m_data)->deviceRect();
405 }
406
407
408
409 /*!
410     Returns the QOpenGLContext that is being used for rendering
411  */
412
413 QOpenGLContext *QSGMaterialShader::RenderState::context() const
414 {
415     return static_cast<const QSGRenderer *>(m_data)->glContext();
416 }
417
418
419 #ifndef QT_NO_DEBUG
420 static int qt_material_count = 0;
421
422 static void qt_print_material_count()
423 {
424     qDebug("Number of leaked materials: %i", qt_material_count);
425     qt_material_count = -1;
426 }
427 #endif
428
429 /*!
430     \class QSGMaterialType
431     \brief The QSGMaterialType class is used as a unique type token in combination with QSGMaterial.
432
433     It serves no purpose outside the QSGMaterial::type() function.
434  */
435
436 /*!
437     \class QSGMaterial
438     \brief The QSGMaterial class encapsulates rendering state for a shader program.
439
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.
447
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.
452
453     A minimal QSGMaterial implementation could look like this:
454     \code
455         class Material : public QSGMaterial
456         {
457         public:
458             QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
459             QSGMaterialShader *createShader() const { return new Shader; }
460         };
461     \endcode
462
463     \warning Instances of QSGMaterial belongs to the Scene Graph rendering thread,
464     and cannot be used from the GUI thread.
465  */
466
467 QSGMaterial::QSGMaterial()
468     : m_flags(0)
469 {
470 #ifndef QT_NO_DEBUG
471     ++qt_material_count;
472     static bool atexit_registered = false;
473     if (!atexit_registered) {
474         atexit(qt_print_material_count);
475         atexit_registered = true;
476     }
477 #endif
478 }
479
480 QSGMaterial::~QSGMaterial()
481 {
482 #ifndef QT_NO_DEBUG
483     --qt_material_count;
484     if (qt_material_count < 0)
485         qDebug("Material destroyed after qt_print_material_count() was called.");
486 #endif
487 }
488
489
490
491 /*!
492     \enum QSGMaterial::Flag
493
494     \value Blending Set this flag to true if the material requires GL_BLEND to be
495     enabled during rendering.
496
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.
499
500     \value RequiresFullMatrix Set this flag to true if the material relies on
501     the full matrix of the geometry nodes for rendering.
502  */
503
504
505
506 /*!
507     Sets the flags \a flags on this material if \a on is true;
508     otherwise clears the attribute.
509 */
510
511 void QSGMaterial::setFlag(Flags flags, bool on)
512 {
513     if (on)
514         m_flags |= flags;
515     else
516         m_flags &= ~flags;
517 }
518
519
520
521 /*!
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
524     before.
525
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().
530
531     The this pointer and \a other is guaranteed to have the same type().
532  */
533
534 int QSGMaterial::compare(const QSGMaterial *other) const
535 {
536     Q_ASSERT(other && type() == other->type());
537     return qint64(this) - qint64(other);
538 }
539
540
541
542 /*!
543     \fn QSGMaterialType QSGMaterial::type() const
544
545     This function is called by the scene graph to return a unique instance
546     per subclass.
547  */
548
549
550
551 /*!
552     \fn QSGMaterialShader *QSGMaterial::createShader() const
553
554     This function returns a new instance of a the QSGMaterialShader
555     implementatation used to render geometry for a specifc implementation
556     of QSGMaterial.
557
558     The function will be called only once for each material type that
559     exists in the scene graph and will be cached internally.
560 */
561
562
563 QT_END_NAMESPACE