Remove "All rights reserved" line from license headers.
[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 QtDeclarative 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
339 /*!
340     Returns the matrix combined of modelview matrix and project matrix.
341  */
342
343 QMatrix4x4 QSGMaterialShader::RenderState::combinedMatrix() const
344 {
345     Q_ASSERT(m_data);
346     return static_cast<const QSGRenderer *>(m_data)->currentCombinedMatrix();
347 }
348
349
350
351 /*!
352     Returns the model view matrix.
353  */
354
355 QMatrix4x4 QSGMaterialShader::RenderState::modelViewMatrix() const
356 {
357     Q_ASSERT(m_data);
358     return static_cast<const QSGRenderer *>(m_data)->currentModelViewMatrix();
359 }
360
361
362
363 /*!
364     Returns the viewport rect of the surface being rendered to.
365  */
366
367 QRect QSGMaterialShader::RenderState::viewportRect() const
368 {
369     Q_ASSERT(m_data);
370     return static_cast<const QSGRenderer *>(m_data)->viewportRect();
371 }
372
373
374
375 /*!
376     Returns the device rect of the surface being rendered to
377  */
378
379 QRect QSGMaterialShader::RenderState::deviceRect() const
380 {
381     Q_ASSERT(m_data);
382     return static_cast<const QSGRenderer *>(m_data)->deviceRect();
383 }
384
385
386
387 /*!
388     Returns the QOpenGLContext that is being used for rendering
389  */
390
391 QOpenGLContext *QSGMaterialShader::RenderState::context() const
392 {
393     return static_cast<const QSGRenderer *>(m_data)->glContext();
394 }
395
396
397 #ifndef QT_NO_DEBUG
398 static int qt_material_count = 0;
399
400 static void qt_print_material_count()
401 {
402     qDebug("Number of leaked materials: %i", qt_material_count);
403     qt_material_count = -1;
404 }
405 #endif
406
407 /*!
408     \class QSGMaterialType
409     \brief The QSGMaterialType class is used as a unique type token in combination with QSGMaterial.
410
411     It serves no purpose outside the QSGMaterial::type() function.
412  */
413
414 /*!
415     \class QSGMaterial
416     \brief The QSGMaterial class encapsulates rendering state for a shader program.
417
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.
425
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.
430
431     A minimal QSGMaterial implementation could look like this:
432     \code
433         class Material : public QSGMaterial
434         {
435         public:
436             QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
437             QSGMaterialShader *createShader() const { return new Shader; }
438         };
439     \endcode
440
441     \warning Instances of QSGMaterial belongs to the Scene Graph rendering thread,
442     and cannot be used from the GUI thread.
443  */
444
445 QSGMaterial::QSGMaterial()
446     : m_flags(0)
447 {
448 #ifndef QT_NO_DEBUG
449     ++qt_material_count;
450     static bool atexit_registered = false;
451     if (!atexit_registered) {
452         atexit(qt_print_material_count);
453         atexit_registered = true;
454     }
455 #endif
456 }
457
458 QSGMaterial::~QSGMaterial()
459 {
460 #ifndef QT_NO_DEBUG
461     --qt_material_count;
462     if (qt_material_count < 0)
463         qDebug("Material destroyed after qt_print_material_count() was called.");
464 #endif
465 }
466
467
468
469 /*!
470     \enum QSGMaterial::Flag
471
472     \value Blending Set this flag to true if the material requires GL_BLEND to be
473     enabled during rendering.
474
475     \value RequiresDeterminant Set this flag to true if the material relies on
476     the determinant of the matrix of the geometry nodes for rendering.
477
478     \value RequiresFullMatrix Set this flag to true if the material relies on
479     the full matrix of the geometry nodes for rendering.
480  */
481
482
483
484 /*!
485     Sets the flags \a flags on this material if \a on is true;
486     otherwise clears the attribute.
487 */
488
489 void QSGMaterial::setFlag(Flags flags, bool on)
490 {
491     if (on)
492         m_flags |= flags;
493     else
494         m_flags &= ~flags;
495 }
496
497
498
499 /*!
500     Compares this material to \a other and returns 0 if they are equal; -1 if
501     this material should sort before \a other and 1 if \a other should sort
502     before.
503
504     The scene graph can reorder geometry nodes to minimize state changes.
505     The compare function is called during the sorting process so that
506     the materials can be sorted to minimize state changes in each
507     call to QSGMaterialShader::updateState().
508
509     The this pointer and \a other is guaranteed to have the same type().
510  */
511
512 int QSGMaterial::compare(const QSGMaterial *other) const
513 {
514     Q_ASSERT(other && type() == other->type());
515     return qint64(this) - qint64(other);
516 }
517
518
519
520 /*!
521     \fn QSGMaterialType QSGMaterial::type() const
522
523     This function is called by the scene graph to return a unique instance
524     per subclass.
525  */
526
527
528
529 /*!
530     \fn QSGMaterialShader *QSGMaterial::createShader() const
531
532     This function returns a new instance of a the QSGMaterialShader
533     implementatation used to render geometry for a specifc implementation
534     of QSGMaterial.
535
536     The function will be called only once for each material type that
537     exists in the scene graph and will be cached internally.
538 */
539
540
541 QT_END_NAMESPACE