1/****************************************************************************
2**
3** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D 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 "qshaderprogram.h"
41#include "qshaderprogram_p.h"
42#include <Qt3DCore/qpropertyupdatedchange.h>
43#include <Qt3DRender/private/qurlhelper_p.h>
44#include <QDebug>
45#include <QFile>
46#include <QFileInfo>
47#include <QUrl>
48
49/*!
50 \class Qt3DRender::QShaderProgram
51 \inmodule Qt3DRender
52 \brief Encapsulates a Shader Program.
53 \inherits Qt3DCore::QNode
54 \since 5.5
55
56 A shader program consists of several different shaders, such as vertex and fragment shaders.
57
58 Qt3D will automatically populate a set of default uniforms if they are
59 encountered during the shader instrospection phase.
60
61 \table
62 \header
63 \li {1, 1} Default Uniform
64 \li {2, 1} Associated Qt3D Parameter name
65 \li {3, 1} GLSL declaration
66
67 \row
68 \li {1, 1} ModelMatrix
69 \li {2, 1} modelMatrix
70 \li {3, 1} uniform mat4 modelMatrix;
71
72 \row
73 \li {1, 1} ViewMatrix
74 \li {2, 1} viewMatrix
75 \li {3, 1} uniform mat4 viewMatrix;
76
77 \row
78 \li {1, 1} ProjectionMatrix
79 \li {2, 1} projectionMatrix
80 \li {3, 1} uniform mat4 projectionMatrix;
81
82 \row
83 \li {1, 1} ModelViewMatrix
84 \li {2, 1} modelView
85 \li {3, 1} uniform mat4 modelView;
86
87 \row
88 \li {1, 1} ViewProjectionMatrix
89 \li {2, 1} viewProjectionMatrix
90 \li {3, 1} uniform mat4 viewProjectionMatrix;
91
92 \row
93 \li {1, 1} ModelViewProjectionMatrix
94 \li {2, 1} modelViewProjection \br mvp
95 \li {3, 1} uniform mat4 modelViewProjection; \br uniform mat4 mvp;
96
97 \row
98 \li {1, 1} InverseModelMatrix
99 \li {2, 1} inverseModelMatrix
100 \li {3, 1} uniform mat4 inverseModelMatrix;
101
102 \row
103 \li {1, 1} InverseViewMatrix
104 \li {2, 1} inverseViewMatrix
105 \li {3, 1} uniform mat4 inverseViewMatrix;
106
107 \row
108 \li {1, 1} InverseProjectionMatrix
109 \li {2, 1} inverseProjectionMatrix
110 \li {3, 1} uniform mat4 inverseProjectionMatrix;
111
112 \row
113 \li {1, 1} InverseModelViewMatrix
114 \li {2, 1} inverseModelView
115 \li {3, 1} uniform mat4 inverseModelView;
116
117 \row
118 \li {1, 1} InverseViewProjectionMatrix
119 \li {2, 1} inverseViewProjectionMatrix
120 \li {3, 1} uniform mat4 inverseViewProjectionMatrix;
121
122 \row
123 \li {1, 1} InverseModelViewProjectionMatrix
124 \li {2, 1} inverseModelViewProjection
125 \li {3, 1} uniform mat4 inverseModelViewProjection;
126
127 \row
128 \li {1, 1} ModelNormalMatrix
129 \li {2, 1} modelNormalMatrix
130 \li {3, 1} uniform mat3 modelNormalMatrix;
131
132 \row
133 \li {1, 1} ModelViewNormalMatrix
134 \li {2, 1} modelViewNormal
135 \li {3, 1} uniform mat3 modelViewNormal;
136
137 \row
138 \li {1, 1} ViewportMatrix
139 \li {2, 1} viewportMatrix
140 \li {3, 1} uniform mat4 viewportMatrix;
141
142 \row
143 \li {1, 1} InverseViewportMatrix
144 \li {2, 1} inverseViewportMatrix
145 \li {3, 1} uniform mat4 inverseViewportMatrix;
146
147 \row
148 \li {1, 1} AspectRatio \br (surface width / surface height)
149 \li {2, 1} aspectRatio
150 \li {3, 1} uniform float aspectRatio;
151
152 \row
153 \li {1, 1} Exposure
154 \li {2, 1} exposure
155 \li {3, 1} uniform float exposure;
156
157 \row
158 \li {1, 1} Gamma
159 \li {2, 1} gamma
160 \li {3, 1} uniform float gamma;
161
162 \row
163 \li {1, 1} Time \br (in nano seconds)
164 \li {2, 1} time
165 \li {3, 1} uniform float time;
166
167 \row
168 \li {1, 1} EyePosition
169 \li {2, 1} eyePosition
170 \li {3, 1} uniform vec3 eyePosition;
171
172 \row
173 \li {1, 1} SkinningPalette
174 \li {2, 1} skinningPalette[0]
175 \li {3, 1} const int maxJoints = 100; \br uniform mat4 skinningPalette[maxJoints];
176
177 \endtable
178*/
179
180/*!
181 \qmltype ShaderProgram
182 \instantiates Qt3DRender::QShaderProgram
183 \inqmlmodule Qt3D.Render
184 \brief Encapsulates a Shader Program.
185 \since 5.5
186
187 ShaderProgram class encapsulates a shader program. A shader program consists of several
188 different shaders, such as vertex and fragment shaders.
189
190 Qt3D will automatically populate a set of default uniforms if they are
191 encountered during the shader instrospection phase.
192
193 \table
194 \header
195 \li {1, 1} Default Uniform
196 \li {2, 1} Associated Qt3D Parameter name
197 \li {3, 1} GLSL declaration
198
199 \row
200 \li {1, 1} ModelMatrix
201 \li {2, 1} modelMatrix
202 \li {3, 1} uniform mat4 modelMatrix;
203
204 \row
205 \li {1, 1} ViewMatrix
206 \li {2, 1} viewMatrix
207 \li {3, 1} uniform mat4 viewMatrix;
208
209 \row
210 \li {1, 1} ProjectionMatrix
211 \li {2, 1} projectionMatrix
212 \li {3, 1} uniform mat4 projectionMatrix;
213
214 \row
215 \li {1, 1} ModelViewMatrix
216 \li {2, 1} modelView
217 \li {3, 1} uniform mat4 modelView;
218
219 \row
220 \li {1, 1} ViewProjectionMatrix
221 \li {2, 1} viewProjectionMatrix
222 \li {3, 1} uniform mat4 viewProjectionMatrix;
223
224 \row
225 \li {1, 1} ModelViewProjectionMatrix
226 \li {2, 1} modelViewProjection \br mvp
227 \li {3, 1} uniform mat4 modelViewProjection; \br uniform mat4 mvp;
228
229 \row
230 \li {1, 1} InverseModelMatrix
231 \li {2, 1} inverseModelMatrix
232 \li {3, 1} uniform mat4 inverseModelMatrix;
233
234 \row
235 \li {1, 1} InverseViewMatrix
236 \li {2, 1} inverseViewMatrix
237 \li {3, 1} uniform mat4 inverseViewMatrix;
238
239 \row
240 \li {1, 1} InverseProjectionMatrix
241 \li {2, 1} inverseProjectionMatrix
242 \li {3, 1} uniform mat4 inverseProjectionMatrix;
243
244 \row
245 \li {1, 1} InverseModelViewMatrix
246 \li {2, 1} inverseModelView
247 \li {3, 1} uniform mat4 inverseModelView;
248
249 \row
250 \li {1, 1} InverseViewProjectionMatrix
251 \li {2, 1} inverseViewProjectionMatrix
252 \li {3, 1} uniform mat4 inverseViewProjectionMatrix;
253
254 \row
255 \li {1, 1} InverseModelViewProjectionMatrix
256 \li {2, 1} inverseModelViewProjection
257 \li {3, 1} uniform mat4 inverseModelViewProjection;
258
259 \row
260 \li {1, 1} ModelNormalMatrix
261 \li {2, 1} modelNormalMatrix
262 \li {3, 1} uniform mat3 modelNormalMatrix;
263
264 \row
265 \li {1, 1} ModelViewNormalMatrix
266 \li {2, 1} modelViewNormal
267 \li {3, 1} uniform mat3 modelViewNormal;
268
269 \row
270 \li {1, 1} ViewportMatrix
271 \li {2, 1} viewportMatrix
272 \li {3, 1} uniform mat4 viewportMatrix;
273
274 \row
275 \li {1, 1} InverseViewportMatrix
276 \li {2, 1} inverseViewportMatrix
277 \li {3, 1} uniform mat4 inverseViewportMatrix;
278
279 \row
280 \li {1, 1} AspectRatio \br (surface width / surface height)
281 \li {2, 1} aspectRatio
282 \li {3, 1} uniform float aspectRatio;
283
284 \row
285 \li {1, 1} Exposure
286 \li {2, 1} exposure
287 \li {3, 1} uniform float exposure;
288
289 \row
290 \li {1, 1} Gamma
291 \li {2, 1} gamma
292 \li {3, 1} uniform float gamma;
293
294 \row
295 \li {1, 1} Time \br (in nano seconds)
296 \li {2, 1} time
297 \li {3, 1} uniform float time;
298
299 \row
300 \li {1, 1} EyePosition
301 \li {2, 1} eyePosition
302 \li {3, 1} uniform vec3 eyePosition;
303
304 \row
305 \li {1, 1} SkinningPalette
306 \li {2, 1} skinningPalette[0]
307 \li {3, 1} const int maxJoints = 100; \br uniform mat4 skinningPalette[maxJoints];
308
309 \endtable
310*/
311
312/*!
313 \enum QShaderProgram::ShaderType
314
315 This enum identifies the type of shader used.
316
317 \value Vertex Vertex shader
318 \value Fragment Fragment shader
319 \value TessellationControl Tesselation control shader
320 \value TessellationEvaluation Tesselation evaluation shader
321 \value Geometry Geometry shader
322 \value Compute Compute shader
323*/
324
325/*!
326 \enum QShaderProgram::Status
327
328 This enum identifies the status of shader used.
329
330 \value NotReady The shader hasn't been compiled and linked yet
331 \value Ready The shader was successfully compiled
332 \value Error An error occurred while compiling the shader
333*/
334
335QT_BEGIN_NAMESPACE
336
337namespace Qt3DRender {
338
339QShaderProgramPrivate::QShaderProgramPrivate()
340 : QNodePrivate()
341 , m_status(QShaderProgram::NotReady)
342{
343}
344
345void QShaderProgramPrivate::setLog(const QString &log)
346{
347 Q_Q(QShaderProgram);
348 if (log != m_log) {
349 m_log = log;
350 const bool blocked = q->blockNotifications(true);
351 emit q->logChanged(m_log);
352 q->blockNotifications(blocked);
353 }
354}
355
356void QShaderProgramPrivate::setStatus(QShaderProgram::Status status)
357{
358 Q_Q(QShaderProgram);
359 if (status != m_status) {
360 m_status = status;
361 const bool blocked = q->blockNotifications(true);
362 emit q->statusChanged(m_status);
363 q->blockNotifications(blocked);
364 }
365}
366
367QShaderProgram::QShaderProgram(QNode *parent)
368 : QNode(*new QShaderProgramPrivate, parent)
369{
370}
371
372QShaderProgram::~QShaderProgram()
373{
374}
375
376/*! \internal */
377QShaderProgram::QShaderProgram(QShaderProgramPrivate &dd, QNode *parent)
378 : QNode(dd, parent)
379{
380}
381
382/*!
383 Posts a scene change with parameter \a change.
384*/
385void QShaderProgram::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
386{
387 Q_D(QShaderProgram);
388 if (change->type() == Qt3DCore::PropertyUpdated) {
389 const Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
390 if (e->propertyName() == QByteArrayLiteral("log"))
391 d->setLog(e->value().toString());
392 else if (e->propertyName() == QByteArrayLiteral("status"))
393 d->setStatus(static_cast<QShaderProgram::Status>(e->value().toInt()));
394 }
395}
396
397/*!
398 \qmlproperty string ShaderProgram::vertexShaderCode
399
400 Holds the vertex shader code used by this shader program.
401*/
402/*!
403 \property QShaderProgram::vertexShaderCode
404
405 Holds the vertex shader code used by this shader program.
406*/
407void QShaderProgram::setVertexShaderCode(const QByteArray &vertexShaderCode)
408{
409 Q_D(QShaderProgram);
410 if (vertexShaderCode != d->m_vertexShaderCode) {
411 d->m_vertexShaderCode = vertexShaderCode;
412 emit vertexShaderCodeChanged(vertexShaderCode);
413 }
414}
415
416QByteArray QShaderProgram::vertexShaderCode() const
417{
418 Q_D(const QShaderProgram);
419 return d->m_vertexShaderCode;
420}
421
422/*!
423 \qmlproperty string ShaderProgram::tessellationControlShaderCode
424
425 Holds the tesselation control shader code used by this shader program.
426*/
427/*!
428 \property QShaderProgram::tessellationControlShaderCode
429
430 Holds the tesselation control shader code used by this shader program.
431*/
432void QShaderProgram::setTessellationControlShaderCode(const QByteArray &tessellationControlShaderCode)
433{
434 Q_D(QShaderProgram);
435 if (tessellationControlShaderCode != d->m_tessControlShaderCode) {
436 d->m_tessControlShaderCode = tessellationControlShaderCode;
437 emit tessellationControlShaderCodeChanged(tessellationControlShaderCode);
438 }
439}
440
441QByteArray QShaderProgram::tessellationControlShaderCode() const
442{
443 Q_D(const QShaderProgram);
444 return d->m_tessControlShaderCode;
445}
446
447/*!
448 \qmlproperty string ShaderProgram::tessellationEvaluationShaderCode
449
450 Holds the tesselation evaluation shader code used by this shader program.
451*/
452/*!
453 \property QShaderProgram::tessellationEvaluationShaderCode
454
455 Holds the tesselation evaluation shader code used by this shader program.
456*/
457void QShaderProgram::setTessellationEvaluationShaderCode(const QByteArray &tessellationEvaluationShaderCode)
458{
459 Q_D(QShaderProgram);
460 if (tessellationEvaluationShaderCode != d->m_tessEvalShaderCode) {
461 d->m_tessEvalShaderCode = tessellationEvaluationShaderCode;
462 emit tessellationEvaluationShaderCodeChanged(tessellationEvaluationShaderCode);
463 }
464}
465
466QByteArray QShaderProgram::tessellationEvaluationShaderCode() const
467{
468 Q_D(const QShaderProgram);
469 return d->m_tessEvalShaderCode;
470}
471
472/*!
473 \qmlproperty string ShaderProgram::geometryShaderCode
474
475 Holds the geometry shader code used by this shader program.
476*/
477/*!
478 \property QShaderProgram::geometryShaderCode
479
480 Holds the geometry shader code used by this shader program.
481*/
482void QShaderProgram::setGeometryShaderCode(const QByteArray &geometryShaderCode)
483{
484 Q_D(QShaderProgram);
485 if (geometryShaderCode != d->m_geometryShaderCode) {
486 d->m_geometryShaderCode = geometryShaderCode;
487 emit geometryShaderCodeChanged(geometryShaderCode);
488 }
489}
490
491QByteArray QShaderProgram::geometryShaderCode() const
492{
493 Q_D(const QShaderProgram);
494 return d->m_geometryShaderCode;
495}
496
497/*!
498 \qmlproperty string ShaderProgram::fragmentShaderCode
499
500 Holds the fragment shader code used by this shader program.
501*/
502/*!
503 \property QShaderProgram::fragmentShaderCode
504
505 Holds the fragment shader code used by this shader program.
506*/
507void QShaderProgram::setFragmentShaderCode(const QByteArray &fragmentShaderCode)
508{
509 Q_D(QShaderProgram);
510 if (fragmentShaderCode != d->m_fragmentShaderCode) {
511 d->m_fragmentShaderCode = fragmentShaderCode;
512 emit fragmentShaderCodeChanged(fragmentShaderCode);
513 }
514}
515
516QByteArray QShaderProgram::fragmentShaderCode() const
517{
518 Q_D(const QShaderProgram);
519 return d->m_fragmentShaderCode;
520}
521
522/*!
523 \qmlproperty string ShaderProgram::computeShaderCode
524
525 Holds the compute shader code used by this shader program.
526*/
527/*!
528 \property QShaderProgram::computeShaderCode
529
530 Holds the compute shader code used by this shader program.
531*/
532void QShaderProgram::setComputeShaderCode(const QByteArray &computeShaderCode)
533{
534 Q_D(QShaderProgram);
535 if (computeShaderCode != d->m_computeShaderCode) {
536 d->m_computeShaderCode = computeShaderCode;
537 emit computeShaderCodeChanged(computeShaderCode);
538 }
539}
540
541QByteArray QShaderProgram::computeShaderCode() const
542{
543 Q_D(const QShaderProgram);
544 return d->m_computeShaderCode;
545}
546
547
548/*!
549 Sets the shader code for \a type of shader to the \a shaderCode.
550*/
551void QShaderProgram::setShaderCode(ShaderType type, const QByteArray &shaderCode)
552{
553 switch (type) {
554 case Vertex:
555 setVertexShaderCode(shaderCode);
556 break;
557 case TessellationControl:
558 setTessellationControlShaderCode(shaderCode);
559 break;
560 case TessellationEvaluation:
561 setTessellationEvaluationShaderCode(shaderCode);
562 break;
563 case Geometry:
564 setGeometryShaderCode(shaderCode);
565 break;
566 case Fragment:
567 setFragmentShaderCode(shaderCode);
568 break;
569 case Compute:
570 setComputeShaderCode(shaderCode);
571 break;
572 default:
573 Q_UNREACHABLE();
574 }
575}
576
577/*!
578 Returns the shader code for \a type.
579*/
580QByteArray QShaderProgram::shaderCode(ShaderType type) const
581{
582 Q_D(const QShaderProgram);
583 switch (type) {
584 case Vertex:
585 return d->m_vertexShaderCode;
586 case TessellationControl:
587 return d->m_tessControlShaderCode;
588 case TessellationEvaluation:
589 return d->m_tessEvalShaderCode;
590 case Geometry:
591 return d->m_geometryShaderCode;
592 case Fragment:
593 return d->m_fragmentShaderCode;
594 case Compute:
595 return d->m_computeShaderCode;
596 default:
597 Q_UNREACHABLE();
598 }
599}
600
601/*!
602 \qmlproperty string ShaderProgram::log
603
604 Holds the log of the current shader program. This is useful to diagnose a
605 compilation failure of the shader program.
606*/
607/*!
608 \property QShaderProgram::log
609
610 Holds the log of the current shader program. This is useful to diagnose a
611 compilation failure of the shader program.
612*/
613QString QShaderProgram::log() const
614{
615 Q_D(const QShaderProgram);
616 return d->m_log;
617}
618
619/*!
620 \qmlproperty string ShaderProgram::status
621
622 Holds the status of the current shader program.
623*/
624/*!
625 \property QShaderProgram::status
626
627 Holds the status of the current shader program.
628*/
629/*!
630 Returns the status of the current shader program.
631*/
632QShaderProgram::Status QShaderProgram::status() const
633{
634 Q_D(const QShaderProgram);
635 return d->m_status;
636}
637
638QByteArray QShaderProgramPrivate::deincludify(const QString &filePath)
639{
640 QFile f(filePath);
641 if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
642 qWarning() << "Could not read shader source file:" << f.fileName();
643 return QByteArray();
644 }
645
646 QByteArray contents = f.readAll();
647 return deincludify(contents, filePath);
648}
649
650QByteArray QShaderProgramPrivate::deincludify(const QByteArray &contents, const QString &filePath)
651{
652 QByteArrayList lines = contents.split('\n');
653 const QByteArray includeDirective = QByteArrayLiteral("#pragma include");
654 for (int i = 0; i < lines.count(); ++i) {
655 const auto line = lines[i].simplified();
656 if (line.startsWith(includeDirective)) {
657 const QString includePartialPath = QString::fromUtf8(line.mid(includeDirective.count() + 1));
658
659 QString includePath = QFileInfo(includePartialPath).isAbsolute() ? includePartialPath
660 : QFileInfo(filePath).absolutePath() + QLatin1Char('/') + includePartialPath;
661 if (qEnvironmentVariableIsSet("QT3D_GLSL100_WORKAROUND")) {
662 QString candidate = includePath + QLatin1String("100");
663 if (QFile::exists(candidate))
664 includePath = candidate;
665 }
666 lines.removeAt(i);
667 QByteArray includedContents = deincludify(includePath);
668 lines.insert(i, includedContents);
669 QString lineDirective = QString(QStringLiteral("#line %1")).arg(i + 2);
670 lines.insert(i + 1, lineDirective.toUtf8());
671 }
672 }
673
674 return lines.join('\n');
675}
676
677/*!
678 \qmlmethod string ShaderProgram::loadSource(url sourceUrl)
679
680 Returns the shader code loaded from \a sourceUrl.
681*/
682/*!
683 Returns the shader code loaded from \a sourceUrl.
684*/
685QByteArray QShaderProgram::loadSource(const QUrl &sourceUrl)
686{
687 // TO DO: Handle remote path
688 return QShaderProgramPrivate::deincludify(Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(sourceUrl));
689}
690
691Qt3DCore::QNodeCreatedChangeBasePtr QShaderProgram::createNodeCreationChange() const
692{
693 auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QShaderProgramData>::create(this);
694 auto &data = creationChange->data;
695 Q_D(const QShaderProgram);
696 data.vertexShaderCode = d->m_vertexShaderCode;
697 data.tessellationControlShaderCode = d->m_tessControlShaderCode;
698 data.tessellationEvaluationShaderCode = d->m_tessEvalShaderCode;
699 data.geometryShaderCode = d->m_geometryShaderCode;
700 data.fragmentShaderCode = d->m_fragmentShaderCode;
701 data.computeShaderCode = d->m_computeShaderCode;
702 return creationChange;
703}
704
705} // of namespace Qt3DRender
706
707QT_END_NAMESPACE
708