1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2019 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQuick module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qsgmaterial.h" |
41 | #include "qsgrenderer_p.h" |
42 | #include "qsgmaterialshader_p.h" |
43 | #if QT_CONFIG(opengl) |
44 | # include <private/qsgshadersourcebuilder_p.h> |
45 | # include <private/qsgdefaultcontext_p.h> |
46 | # include <private/qsgdefaultrendercontext_p.h> |
47 | # include <QtGui/QOpenGLFunctions> |
48 | # include <QtGui/QOpenGLContext> |
49 | #endif |
50 | |
51 | QT_BEGIN_NAMESPACE |
52 | |
53 | #if QT_CONFIG(opengl) |
54 | const char *QSGMaterialShaderPrivate::loadShaderSource(QOpenGLShader::ShaderType type) const |
55 | { |
56 | const QStringList files = m_sourceFiles[type]; |
57 | QSGShaderSourceBuilder builder; |
58 | for (const QString &file : files) |
59 | builder.appendSourceFile(fileName: file); |
60 | m_sources[type] = builder.source(); |
61 | return m_sources[type].constData(); |
62 | } |
63 | #endif |
64 | |
65 | /*! |
66 | \class QSGMaterialShader |
67 | \brief The QSGMaterialShader class represents an OpenGL shader program |
68 | in the renderer. |
69 | \inmodule QtQuick |
70 | \ingroup qtquick-scenegraph-materials |
71 | |
72 | The QSGMaterialShader API is relatively low-level. A more convenient API, |
73 | which provides almost all the same features, is available through |
74 | QSGSimpleMaterialShader. |
75 | |
76 | \warning This class is only functional when running with the legacy OpenGL |
77 | renderer of the Qt Quick scenegraph. |
78 | |
79 | The QSGMaterial and QSGMaterialShader form a tight relationship. For one |
80 | scene graph (including nested graphs), there is one unique QSGMaterialShader |
81 | instance which encapsulates the QOpenGLShaderProgram the scene graph uses |
82 | to render that material, such as a shader to flat coloring of geometry. |
83 | Each QSGGeometryNode can have a unique QSGMaterial containing the |
84 | how the shader should be configured when drawing that node, such as |
85 | the actual color used to render the geometry. |
86 | |
87 | An instance of QSGMaterialShader is never created explicitly by the user, |
88 | it will be created on demand by the scene graph through |
89 | QSGMaterial::createShader(). The scene graph will make sure that there |
90 | is only one instance of each shader implementation through a scene graph. |
91 | |
92 | The source code returned from vertexShader() is used to control what the |
93 | material does with the vertiex data that comes in from the geometry. |
94 | The source code returned from the fragmentShader() is used to control |
95 | what how the material should fill each individual pixel in the geometry. |
96 | The vertex and fragment source code is queried once during initialization, |
97 | changing what is returned from these functions later will not have |
98 | any effect. |
99 | |
100 | The activate() function is called by the scene graph when a shader is |
101 | is starting to be used. The deactivate function is called by the scene |
102 | graph when the shader is no longer going to be used. While active, |
103 | the scene graph may make one or more calls to updateState() which |
104 | will update the state of the shader for each individual geometry to |
105 | render. |
106 | |
107 | The attributeNames() returns the name of the attributes used in the |
108 | vertexShader(). These are used in the default implementation of |
109 | activate() and deactivate() to decide whice vertex registers are enabled. |
110 | |
111 | The initialize() function is called during program creation to allow |
112 | subclasses to prepare for use, such as resolve uniform names in the |
113 | vertexShader() and fragmentShader(). |
114 | |
115 | A minimal example: |
116 | \code |
117 | class Shader : public QSGMaterialShader |
118 | { |
119 | public: |
120 | const char *vertexShader() const { |
121 | return |
122 | "attribute highp vec4 vertex; \n" |
123 | "uniform highp mat4 matrix; \n" |
124 | "void main() { \n" |
125 | " gl_Position = matrix * vertex; \n" |
126 | "}"; |
127 | } |
128 | |
129 | const char *fragmentShader() const { |
130 | return |
131 | "uniform lowp float opacity; \n" |
132 | "void main() { \n" |
133 | " gl_FragColor = vec4(1, 0, 0, 1) * opacity; \n" |
134 | "}"; |
135 | } |
136 | |
137 | char const *const *attributeNames() const |
138 | { |
139 | static char const *const names[] = { "vertex", 0 }; |
140 | return names; |
141 | } |
142 | |
143 | void initialize() |
144 | { |
145 | QSGMaterialShader::initialize(); |
146 | m_id_matrix = program()->uniformLocation("matrix"); |
147 | m_id_opacity = program()->uniformLocation("opacity"); |
148 | } |
149 | |
150 | void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) |
151 | { |
152 | Q_ASSERT(program()->isLinked()); |
153 | if (state.isMatrixDirty()) |
154 | program()->setUniformValue(m_id_matrix, state.combinedMatrix()); |
155 | if (state.isOpacityDirty()) |
156 | program()->setUniformValue(m_id_opacity, state.opacity()); |
157 | } |
158 | |
159 | private: |
160 | int m_id_matrix; |
161 | int m_id_opacity; |
162 | }; |
163 | \endcode |
164 | |
165 | \note All classes with QSG prefix should be used solely on the scene graph's |
166 | rendering thread. See \l {Scene Graph and Rendering} for more information. |
167 | |
168 | */ |
169 | |
170 | |
171 | |
172 | /*! |
173 | Creates a new QSGMaterialShader. |
174 | */ |
175 | QSGMaterialShader::QSGMaterialShader() |
176 | : d_ptr(new QSGMaterialShaderPrivate) |
177 | { |
178 | } |
179 | |
180 | /*! |
181 | \internal |
182 | */ |
183 | QSGMaterialShader::QSGMaterialShader(QSGMaterialShaderPrivate &dd) |
184 | : d_ptr(&dd) |
185 | { |
186 | } |
187 | |
188 | /*! |
189 | \internal |
190 | */ |
191 | QSGMaterialShader::~QSGMaterialShader() |
192 | { |
193 | } |
194 | |
195 | /*! |
196 | \fn char const *const *QSGMaterialShader::attributeNames() const |
197 | |
198 | Returns a zero-terminated array describing the names of the |
199 | attributes used in the vertex shader. |
200 | |
201 | This function is called when the shader is compiled to specify |
202 | which attributes exist. The order of the attribute names |
203 | defines the attribute register position in the vertex shader. |
204 | */ |
205 | |
206 | #if QT_CONFIG(opengl) |
207 | /*! |
208 | \fn const char *QSGMaterialShader::vertexShader() const |
209 | |
210 | Called when the shader is being initialized to get the vertex |
211 | shader source code. |
212 | |
213 | The contents returned from this function should never change. |
214 | */ |
215 | const char *QSGMaterialShader::vertexShader() const |
216 | { |
217 | Q_D(const QSGMaterialShader); |
218 | return d->loadShaderSource(type: QOpenGLShader::Vertex); |
219 | } |
220 | |
221 | |
222 | /*! |
223 | \fn const char *QSGMaterialShader::fragmentShader() const |
224 | |
225 | Called when the shader is being initialized to get the fragment |
226 | shader source code. |
227 | |
228 | The contents returned from this function should never change. |
229 | */ |
230 | const char *QSGMaterialShader::fragmentShader() const |
231 | { |
232 | Q_D(const QSGMaterialShader); |
233 | return d->loadShaderSource(type: QOpenGLShader::Fragment); |
234 | } |
235 | |
236 | |
237 | /*! |
238 | \fn QOpenGLShaderProgram *QSGMaterialShader::program() |
239 | |
240 | Returns the shader program used by this QSGMaterialShader. |
241 | */ |
242 | #endif |
243 | |
244 | /*! |
245 | \fn void QSGMaterialShader::initialize() |
246 | |
247 | Reimplement this function to do one-time initialization when the |
248 | shader program is compiled. The OpenGL shader program is compiled |
249 | and linked, but not bound, when this function is called. |
250 | */ |
251 | |
252 | |
253 | /*! |
254 | This function is called by the scene graph to indicate that geometry is |
255 | about to be rendered using this shader. |
256 | |
257 | State that is global for all uses of the shader, independent of the geometry |
258 | that is being drawn, can be setup in this function. |
259 | */ |
260 | |
261 | void QSGMaterialShader::activate() |
262 | { |
263 | } |
264 | |
265 | |
266 | |
267 | /*! |
268 | This function is called by the scene graph to indicate that geometry will |
269 | no longer to be rendered using this shader. |
270 | */ |
271 | |
272 | void QSGMaterialShader::deactivate() |
273 | { |
274 | } |
275 | |
276 | |
277 | |
278 | /*! |
279 | This function is called by the scene graph before geometry is rendered |
280 | to make sure the shader is in the right state. |
281 | |
282 | The current rendering \a state is passed from the scene graph. If the state |
283 | indicates that any state is dirty, the updateState implementation must |
284 | update accordingly for the geometry to render correctly. |
285 | |
286 | The subclass specific state, such as the color of a flat color material, should |
287 | be extracted from \a newMaterial to update the color uniforms accordingly. |
288 | |
289 | The \a oldMaterial can be used to minimze state changes when updating |
290 | material states. The \a oldMaterial is 0 if this shader was just activated. |
291 | |
292 | \sa activate(), deactivate() |
293 | */ |
294 | |
295 | void QSGMaterialShader::updateState(const RenderState & /* state */, QSGMaterial * /* newMaterial */, QSGMaterial * /* oldMaterial */) |
296 | { |
297 | } |
298 | |
299 | #if QT_CONFIG(opengl) |
300 | /*! |
301 | Sets the GLSL source file for the shader stage \a type to \a sourceFile. The |
302 | default implementation of the vertexShader() and fragmentShader() functions |
303 | will load the source files set by this function. |
304 | |
305 | This function is useful when you have a single source file for a given shader |
306 | stage. If your shader consists of multiple source files then use |
307 | setShaderSourceFiles() |
308 | |
309 | \sa setShaderSourceFiles(), vertexShader(), fragmentShader() |
310 | */ |
311 | void QSGMaterialShader::setShaderSourceFile(QOpenGLShader::ShaderType type, const QString &sourceFile) |
312 | { |
313 | Q_D(QSGMaterialShader); |
314 | d->m_sourceFiles[type] = (QStringList() << sourceFile); |
315 | } |
316 | |
317 | /*! |
318 | Sets the GLSL source files for the shader stage \a type to \a sourceFiles. The |
319 | default implementation of the vertexShader() and fragmentShader() functions |
320 | will load the source files set by this function in the order given. |
321 | |
322 | \sa setShaderSourceFile(), vertexShader(), fragmentShader() |
323 | */ |
324 | void QSGMaterialShader::setShaderSourceFiles(QOpenGLShader::ShaderType type, const QStringList &sourceFiles) |
325 | { |
326 | Q_D(QSGMaterialShader); |
327 | d->m_sourceFiles[type] = sourceFiles; |
328 | } |
329 | |
330 | /*! |
331 | This function is called when the shader is initialized to compile the |
332 | actual QOpenGLShaderProgram. Do not call it explicitly. |
333 | |
334 | The default implementation will extract the vertexShader() and |
335 | fragmentShader() and bind the names returned from attributeNames() |
336 | to consecutive vertex attribute registers starting at 0. |
337 | */ |
338 | |
339 | void QSGMaterialShader::compile() |
340 | { |
341 | Q_ASSERT_X(!m_program.isLinked(), "QSGSMaterialShader::compile()" , "Compile called multiple times!" ); |
342 | |
343 | program()->addCacheableShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertexShader()); |
344 | program()->addCacheableShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragmentShader()); |
345 | |
346 | char const *const *attr = attributeNames(); |
347 | #ifndef QT_NO_DEBUG |
348 | int maxVertexAttribs = 0; |
349 | QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); |
350 | funcs->glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, params: &maxVertexAttribs); |
351 | for (int i = 0; attr[i]; ++i) { |
352 | if (i >= maxVertexAttribs) { |
353 | qFatal(msg: "List of attribute names is either too long or not null-terminated.\n" |
354 | "Maximum number of attributes on this hardware is %i.\n" |
355 | "Vertex shader:\n%s\n" |
356 | "Fragment shader:\n%s\n" , |
357 | maxVertexAttribs, vertexShader(), fragmentShader()); |
358 | } |
359 | if (*attr[i]) |
360 | program()->bindAttributeLocation(name: attr[i], location: i); |
361 | } |
362 | #else |
363 | for (int i = 0; attr[i]; ++i) { |
364 | if (*attr[i]) |
365 | program()->bindAttributeLocation(attr[i], i); |
366 | } |
367 | #endif |
368 | |
369 | if (!program()->link()) { |
370 | qWarning(msg: "QSGMaterialShader: Shader compilation failed:" ); |
371 | qWarning() << program()->log(); |
372 | } |
373 | } |
374 | |
375 | #endif |
376 | |
377 | /*! |
378 | \class QSGMaterialShader::RenderState |
379 | \brief The QSGMaterialShader::RenderState encapsulates the current rendering state |
380 | during a call to QSGMaterialShader::updateState(). |
381 | \inmodule QtQuick |
382 | |
383 | The render state contains a number of accessors that the shader needs to respect |
384 | in order to conform to the current state of the scene graph. |
385 | |
386 | The instance is only valid inside a call to QSGMaterialShader::updateState() and |
387 | should not be used outisde this function. |
388 | */ |
389 | |
390 | |
391 | |
392 | /*! |
393 | \enum QSGMaterialShader::RenderState::DirtyState |
394 | |
395 | \value DirtyMatrix Used to indicate that the matrix has changed and must be updated. |
396 | |
397 | \value DirtyOpacity Used to indicate that the opacity has changed and must be updated. |
398 | |
399 | \value DirtyCachedMaterialData Used to indicate that the cached material data have changed and must be updated. |
400 | |
401 | \value DirtyAll Used to indicate that everything needs to be updated. |
402 | */ |
403 | |
404 | |
405 | |
406 | /*! |
407 | \fn bool QSGMaterialShader::RenderState::isMatrixDirty() const |
408 | |
409 | Returns \c true if the dirtyStates() contain the dirty matrix state, |
410 | otherwise returns \c false. |
411 | */ |
412 | |
413 | |
414 | |
415 | /*! |
416 | \fn bool QSGMaterialShader::RenderState::isOpacityDirty() const |
417 | |
418 | Returns \c true if the dirtyStates() contains the dirty opacity state, |
419 | otherwise returns \c false. |
420 | */ |
421 | |
422 | /*! |
423 | \fn bool QSGMaterialShader::RenderState::isCachedMaterialDataDirty() const |
424 | |
425 | Returns \c true if the dirtyStates() contains the dirty cached material state, |
426 | otherwise returns \c false. |
427 | */ |
428 | |
429 | /*! |
430 | \fn QSGMaterialShader::RenderState::DirtyStates QSGMaterialShader::RenderState::dirtyStates() const |
431 | |
432 | Returns which rendering states that have changed and needs to be updated |
433 | for geometry rendered with this material to conform to the current |
434 | rendering state. |
435 | */ |
436 | |
437 | |
438 | |
439 | /*! |
440 | Returns the accumulated opacity to be used for rendering. |
441 | */ |
442 | |
443 | float QSGMaterialShader::RenderState::opacity() const |
444 | { |
445 | Q_ASSERT(m_data); |
446 | return static_cast<const QSGRenderer *>(m_data)->currentOpacity(); |
447 | } |
448 | |
449 | /*! |
450 | Returns the modelview determinant to be used for rendering. |
451 | */ |
452 | |
453 | float QSGMaterialShader::RenderState::determinant() const |
454 | { |
455 | Q_ASSERT(m_data); |
456 | return static_cast<const QSGRenderer *>(m_data)->determinant(); |
457 | } |
458 | |
459 | /*! |
460 | Returns the matrix combined of modelview matrix and project matrix. |
461 | */ |
462 | |
463 | QMatrix4x4 QSGMaterialShader::RenderState::combinedMatrix() const |
464 | { |
465 | Q_ASSERT(m_data); |
466 | return static_cast<const QSGRenderer *>(m_data)->currentCombinedMatrix(); |
467 | } |
468 | /*! |
469 | Returns the ratio between physical pixels and device-independent pixels |
470 | to be used for rendering. |
471 | */ |
472 | float QSGMaterialShader::RenderState::devicePixelRatio() const |
473 | { |
474 | Q_ASSERT(m_data); |
475 | return static_cast<const QSGRenderer *>(m_data)->devicePixelRatio(); |
476 | } |
477 | |
478 | |
479 | |
480 | /*! |
481 | Returns the model view matrix. |
482 | |
483 | If the material has the RequiresFullMatrix flag |
484 | set, this is guaranteed to be the complete transform |
485 | matrix calculated from the scenegraph. |
486 | |
487 | However, if this flag is not set, the renderer may |
488 | choose to alter this matrix. For example, it may |
489 | pre-transform vertices on the CPU and set this matrix |
490 | to identity. |
491 | |
492 | In a situation such as the above, it is still possible |
493 | to retrieve the actual matrix determinant by setting |
494 | the RequiresDeterminant flag in the material and |
495 | calling the determinant() accessor. |
496 | */ |
497 | |
498 | QMatrix4x4 QSGMaterialShader::RenderState::modelViewMatrix() const |
499 | { |
500 | Q_ASSERT(m_data); |
501 | return static_cast<const QSGRenderer *>(m_data)->currentModelViewMatrix(); |
502 | } |
503 | |
504 | /*! |
505 | Returns the projection matrix. |
506 | */ |
507 | |
508 | QMatrix4x4 QSGMaterialShader::RenderState::projectionMatrix() const |
509 | { |
510 | Q_ASSERT(m_data); |
511 | return static_cast<const QSGRenderer *>(m_data)->currentProjectionMatrix(); |
512 | } |
513 | |
514 | |
515 | |
516 | /*! |
517 | Returns the viewport rect of the surface being rendered to. |
518 | */ |
519 | |
520 | QRect QSGMaterialShader::RenderState::viewportRect() const |
521 | { |
522 | Q_ASSERT(m_data); |
523 | return static_cast<const QSGRenderer *>(m_data)->viewportRect(); |
524 | } |
525 | |
526 | |
527 | |
528 | /*! |
529 | Returns the device rect of the surface being rendered to |
530 | */ |
531 | |
532 | QRect QSGMaterialShader::RenderState::deviceRect() const |
533 | { |
534 | Q_ASSERT(m_data); |
535 | return static_cast<const QSGRenderer *>(m_data)->deviceRect(); |
536 | } |
537 | |
538 | #if QT_CONFIG(opengl) |
539 | |
540 | /*! |
541 | Returns the QOpenGLContext that is being used for rendering |
542 | */ |
543 | |
544 | QOpenGLContext *QSGMaterialShader::RenderState::context() const |
545 | { |
546 | // Only the QSGDefaultRenderContext will have an OpenGL Context to query |
547 | auto openGLRenderContext = static_cast<const QSGDefaultRenderContext *>(static_cast<const QSGRenderer *>(m_data)->context()); |
548 | if (openGLRenderContext != nullptr) |
549 | return openGLRenderContext->openglContext(); |
550 | else |
551 | return nullptr; |
552 | } |
553 | |
554 | #endif |
555 | |
556 | QT_END_NAMESPACE |
557 | |