1// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qshaderprogram.h"
5#include "qshaderprogram_p.h"
6#include <Qt3DCore/private/qurlhelper_p.h>
7#include <QDebug>
8#include <QFile>
9#include <QFileInfo>
10#include <QUrl>
11#include <QRegularExpression>
12
13/*!
14 \class Qt3DRender::QShaderProgram
15 \inmodule Qt3DRender
16 \brief Encapsulates a Shader Program.
17 \inherits Qt3DCore::QNode
18 \since 5.5
19
20 A shader program consists of several different shaders, such as vertex and fragment shaders.
21
22 Qt3D will automatically populate a set of default uniforms if they are
23 encountered during the shader instrospection phase.
24
25 \table
26 \header
27 \li Default Uniform
28 \li Associated Qt3D Parameter name
29 \li GLSL declaration
30
31 \row
32 \li ModelMatrix
33 \li modelMatrix
34 \li uniform mat4 modelMatrix;
35
36 \row
37 \li ViewMatrix
38 \li viewMatrix
39 \li uniform mat4 viewMatrix;
40
41 \row
42 \li ProjectionMatrix
43 \li projectionMatrix
44 \li uniform mat4 projectionMatrix;
45
46 \row
47 \li ModelViewMatrix
48 \li modelView
49 \li uniform mat4 modelView;
50
51 \row
52 \li ViewProjectionMatrix
53 \li viewProjectionMatrix
54 \li uniform mat4 viewProjectionMatrix;
55
56 \row
57 \li ModelViewProjectionMatrix
58 \li modelViewProjection \br mvp
59 \li uniform mat4 modelViewProjection; \br uniform mat4 mvp;
60
61 \row
62 \li InverseModelMatrix
63 \li inverseModelMatrix
64 \li uniform mat4 inverseModelMatrix;
65
66 \row
67 \li InverseViewMatrix
68 \li inverseViewMatrix
69 \li uniform mat4 inverseViewMatrix;
70
71 \row
72 \li InverseProjectionMatrix
73 \li inverseProjectionMatrix
74 \li uniform mat4 inverseProjectionMatrix;
75
76 \row
77 \li InverseModelViewMatrix
78 \li inverseModelView
79 \li uniform mat4 inverseModelView;
80
81 \row
82 \li InverseViewProjectionMatrix
83 \li inverseViewProjectionMatrix
84 \li uniform mat4 inverseViewProjectionMatrix;
85
86 \row
87 \li InverseModelViewProjectionMatrix
88 \li inverseModelViewProjection
89 \li uniform mat4 inverseModelViewProjection;
90
91 \row
92 \li ModelNormalMatrix
93 \li modelNormalMatrix
94 \li uniform mat3 modelNormalMatrix;
95
96 \row
97 \li ModelViewNormalMatrix
98 \li modelViewNormal
99 \li uniform mat3 modelViewNormal;
100
101 \row
102 \li ViewportMatrix
103 \li viewportMatrix
104 \li uniform mat4 viewportMatrix;
105
106 \row
107 \li InverseViewportMatrix
108 \li inverseViewportMatrix
109 \li uniform mat4 inverseViewportMatrix;
110
111 \row
112 \li AspectRatio \br (surface width / surface height)
113 \li aspectRatio
114 \li uniform float aspectRatio;
115
116 \row
117 \li Exposure
118 \li exposure
119 \li uniform float exposure;
120
121 \row
122 \li Gamma
123 \li gamma
124 \li uniform float gamma;
125
126 \row
127 \li Time \br (in nano seconds)
128 \li time
129 \li uniform float time;
130
131 \row
132 \li EyePosition
133 \li eyePosition
134 \li uniform vec3 eyePosition;
135
136 \row
137 \li SkinningPalette
138 \li skinningPalette[0]
139 \li const int maxJoints = 100; \br uniform mat4 skinningPalette[maxJoints];
140
141 \endtable
142
143 \section1 RHI Support
144
145 When writing GLSL 450 shader code to use with Qt 3D's RHI backend,
146 the default uniforms will be provided as 2 uniform buffer objects.
147
148 The binding locations for these is set to bindings 0 for RenderView
149 uniforms and 1 for Command uniforms.
150
151 \badcode
152 #version 450 core
153
154 layout(location = 0) in vec3 vertexPosition;
155
156 layout(std140, binding = 0) uniform qt3d_render_view_uniforms {
157 mat4 viewMatrix;
158 mat4 projectionMatrix;
159 mat4 uncorrectedProjectionMatrix;
160 mat4 clipCorrectionMatrix;
161 mat4 viewProjectionMatrix;
162 mat4 inverseViewMatrix;
163 mat4 inverseProjectionMatrix;
164 mat4 inverseViewProjectionMatrix;
165 mat4 viewportMatrix;
166 mat4 inverseViewportMatrix;
167 vec4 textureTransformMatrix;
168 vec3 eyePosition;
169 float aspectRatio;
170 float gamma;
171 float exposure;
172 float time;
173 float yUpInNDC;
174 float yUpInFBO;
175 };
176
177 layout(std140, binding = 1) uniform qt3d_command_uniforms {
178 mat4 modelMatrix;
179 mat4 inverseModelMatrix;
180 mat4 modelViewMatrix;
181 mat3 modelNormalMatrix;
182 mat4 inverseModelViewMatrix;
183 mat4 modelViewProjection;
184 mat4 inverseModelViewProjectionMatrix;
185 };
186
187 void main()
188 {
189 gl_Position = (projectionMatrix * viewMatrix * modelMatrix * vertexPosition);
190 }
191 \endcode
192
193 For user defined uniform buffer object, use binding starting at 2 or auto
194 to let Qt 3D work out the binding automatically. Make sure to remain
195 consistent between the different shader stages.
196
197
198 \badcode
199 #version 450 core
200
201 layout(std140, binding = auto) uniform my_uniforms {
202 vec4 myColor;
203 };
204
205 layout(location=0) out vec4 fragColor;
206
207 void main()
208 {
209 fragColor = myColor;
210 }
211 \endcode
212
213 There is no change involved when it comes to feeding values to uniforms.
214
215 For the above example, setting myColor could be done with:
216
217 \badcode
218 QParameter *parameter = new QParameter();
219 parameter->setName("myColor");
220 parameter->setValue(QVariant::fromValue(QColor(Qt::blue)));
221 \endcode
222
223 Textures still have to be defined as standalone uniforms.
224
225 \badcode
226 #version 450 core
227
228 layout(binding=0) uniform sampler2D source;
229
230 layout(location=0) out vec4 fragColor;
231
232 void main()
233 {
234 fragColor = texture(source, vec2(0.5, 0.5));
235 }
236 \endcode
237*/
238
239/*!
240 \qmltype ShaderProgram
241 \instantiates Qt3DRender::QShaderProgram
242 \inqmlmodule Qt3D.Render
243 \brief Encapsulates a Shader Program.
244 \since 5.5
245
246 ShaderProgram class encapsulates a shader program. A shader program consists of several
247 different shaders, such as vertex and fragment shaders.
248
249 Qt3D will automatically populate a set of default uniforms if they are
250 encountered during the shader instrospection phase.
251
252 \table
253 \header
254 \li {1, 1} Default Uniform
255 \li {2, 1} Associated Qt3D Parameter name
256 \li {3, 1} GLSL declaration
257
258 \row
259 \li {1, 1} ModelMatrix
260 \li {2, 1} modelMatrix
261 \li {3, 1} uniform mat4 modelMatrix;
262
263 \row
264 \li {1, 1} ViewMatrix
265 \li {2, 1} viewMatrix
266 \li {3, 1} uniform mat4 viewMatrix;
267
268 \row
269 \li {1, 1} ProjectionMatrix
270 \li {2, 1} projectionMatrix
271 \li {3, 1} uniform mat4 projectionMatrix;
272
273 \row
274 \li {1, 1} ModelViewMatrix
275 \li {2, 1} modelView
276 \li {3, 1} uniform mat4 modelView;
277
278 \row
279 \li {1, 1} ViewProjectionMatrix
280 \li {2, 1} viewProjectionMatrix
281 \li {3, 1} uniform mat4 viewProjectionMatrix;
282
283 \row
284 \li {1, 1} ModelViewProjectionMatrix
285 \li {2, 1} modelViewProjection \br mvp
286 \li {3, 1} uniform mat4 modelViewProjection; \br uniform mat4 mvp;
287
288 \row
289 \li {1, 1} InverseModelMatrix
290 \li {2, 1} inverseModelMatrix
291 \li {3, 1} uniform mat4 inverseModelMatrix;
292
293 \row
294 \li {1, 1} InverseViewMatrix
295 \li {2, 1} inverseViewMatrix
296 \li {3, 1} uniform mat4 inverseViewMatrix;
297
298 \row
299 \li {1, 1} InverseProjectionMatrix
300 \li {2, 1} inverseProjectionMatrix
301 \li {3, 1} uniform mat4 inverseProjectionMatrix;
302
303 \row
304 \li {1, 1} InverseModelViewMatrix
305 \li {2, 1} inverseModelView
306 \li {3, 1} uniform mat4 inverseModelView;
307
308 \row
309 \li {1, 1} InverseViewProjectionMatrix
310 \li {2, 1} inverseViewProjectionMatrix
311 \li {3, 1} uniform mat4 inverseViewProjectionMatrix;
312
313 \row
314 \li {1, 1} InverseModelViewProjectionMatrix
315 \li {2, 1} inverseModelViewProjection
316 \li {3, 1} uniform mat4 inverseModelViewProjection;
317
318 \row
319 \li {1, 1} ModelNormalMatrix
320 \li {2, 1} modelNormalMatrix
321 \li {3, 1} uniform mat3 modelNormalMatrix;
322
323 \row
324 \li {1, 1} ModelViewNormalMatrix
325 \li {2, 1} modelViewNormal
326 \li {3, 1} uniform mat3 modelViewNormal;
327
328 \row
329 \li {1, 1} ViewportMatrix
330 \li {2, 1} viewportMatrix
331 \li {3, 1} uniform mat4 viewportMatrix;
332
333 \row
334 \li {1, 1} InverseViewportMatrix
335 \li {2, 1} inverseViewportMatrix
336 \li {3, 1} uniform mat4 inverseViewportMatrix;
337
338 \row
339 \li {1, 1} AspectRatio \br (surface width / surface height)
340 \li {2, 1} aspectRatio
341 \li {3, 1} uniform float aspectRatio;
342
343 \row
344 \li {1, 1} Exposure
345 \li {2, 1} exposure
346 \li {3, 1} uniform float exposure;
347
348 \row
349 \li {1, 1} Gamma
350 \li {2, 1} gamma
351 \li {3, 1} uniform float gamma;
352
353 \row
354 \li {1, 1} Time \br (in nano seconds)
355 \li {2, 1} time
356 \li {3, 1} uniform float time;
357
358 \row
359 \li {1, 1} EyePosition
360 \li {2, 1} eyePosition
361 \li {3, 1} uniform vec3 eyePosition;
362
363 \row
364 \li {1, 1} SkinningPalette
365 \li {2, 1} skinningPalette[0]
366 \li {3, 1} const int maxJoints = 100; \br uniform mat4 skinningPalette[maxJoints];
367
368 \endtable
369
370 \section1 RHI Support
371
372 When writing GLSL 450 shader code to use with Qt 3D's RHI backend,
373 the default uniforms will be provided as 2 uniform buffer objects.
374
375 The binding locations for these is set to bindings 0 for RenderView
376 uniforms and 1 for Command uniforms.
377
378 \badcode
379 #version 450 core
380
381 layout(location = 0) in vec3 vertexPosition;
382
383 layout(std140, binding = 0) uniform qt3d_render_view_uniforms {
384 mat4 viewMatrix;
385 mat4 projectionMatrix;
386 mat4 uncorrectedProjectionMatrix;
387 mat4 clipCorrectionMatrix;
388 mat4 viewProjectionMatrix;
389 mat4 inverseViewMatrix;
390 mat4 inverseProjectionMatrix;
391 mat4 inverseViewProjectionMatrix;
392 mat4 viewportMatrix;
393 mat4 inverseViewportMatrix;
394 vec4 textureTransformMatrix;
395 vec3 eyePosition;
396 float aspectRatio;
397 float gamma;
398 float exposure;
399 float time;
400 float yUpInNDC;
401 float yUpInFBO;
402 };
403
404 layout(std140, binding = 1) uniform qt3d_command_uniforms {
405 mat4 modelMatrix;
406 mat4 inverseModelMatrix;
407 mat4 modelViewMatrix;
408 mat3 modelNormalMatrix;
409 mat4 inverseModelViewMatrix;
410 mat4 modelViewProjection;
411 mat4 inverseModelViewProjectionMatrix;
412 };
413
414 void main()
415 {
416 gl_Position = (projectionMatrix * viewMatrix * modelMatrix * vertexPosition);
417 }
418 \endcode
419
420 For user defined uniform buffer object, use binding starting at 2 or auto
421 to let Qt 3D work out the binding automatically. Make sure to remain
422 consistent between the different shader stages.
423
424
425 \badcode
426 #version 450 core
427
428 layout(std140, binding = auto) uniform my_uniforms {
429 vec4 myColor;
430 };
431
432 layout(location=0) out vec4 fragColor;
433
434 void main()
435 {
436 fragColor = myColor;
437 }
438 \endcode
439
440 There is no change involved when it comes to feeding values to uniforms.
441
442 For the above example, setting myColor could be done with:
443
444 \badcode
445 Parameter { name: "myColor"; value: "blue" }
446 \endcode
447
448 Textures still have to be defined as standalone uniforms.
449
450 \badcode
451 #version 450 core
452
453 layout(binding=0) uniform sampler2D source;
454
455 layout(location=0) out vec4 fragColor;
456
457 void main()
458 {
459 fragColor = texture(source, vec2(0.5, 0.5));
460 }
461 \endcode
462*/
463
464/*!
465 \enum QShaderProgram::ShaderType
466
467 This enum identifies the type of shader used.
468
469 \value Vertex Vertex shader
470 \value Fragment Fragment shader
471 \value TessellationControl Tesselation control shader
472 \value TessellationEvaluation Tesselation evaluation shader
473 \value Geometry Geometry shader
474 \value Compute Compute shader
475*/
476
477/*!
478 \enum QShaderProgram::Status
479
480 This enum identifies the status of shader used.
481
482 \value NotReady The shader hasn't been compiled and linked yet
483 \value Ready The shader was successfully compiled
484 \value Error An error occurred while compiling the shader
485*/
486
487/*!
488 \enum QShaderProgram::Format
489
490 This enum identifies the format of the shader code used.
491
492 \value GLSL OpenGL
493 \value SPIRV Vulkan, OpenGL 5
494
495 \since 5.15
496*/
497
498QT_BEGIN_NAMESPACE
499
500namespace Qt3DRender {
501
502QShaderProgramPrivate::QShaderProgramPrivate()
503 : QNodePrivate()
504 , m_status(QShaderProgram::NotReady)
505 , m_format(QShaderProgram::GLSL)
506{
507}
508
509void QShaderProgramPrivate::setLog(const QString &log)
510{
511 Q_Q(QShaderProgram);
512 if (log != m_log) {
513 m_log = log;
514 const bool blocked = q->blockNotifications(block: true);
515 emit q->logChanged(log: m_log);
516 q->blockNotifications(block: blocked);
517 }
518}
519
520void QShaderProgramPrivate::setStatus(QShaderProgram::Status status)
521{
522 Q_Q(QShaderProgram);
523 if (status != m_status) {
524 m_status = status;
525 const bool blocked = q->blockNotifications(block: true);
526 emit q->statusChanged(status: m_status);
527 q->blockNotifications(block: blocked);
528 }
529}
530
531QShaderProgram::QShaderProgram(QNode *parent)
532 : QNode(*new QShaderProgramPrivate, parent)
533{
534}
535
536QShaderProgram::~QShaderProgram()
537{
538}
539
540/*! \internal */
541QShaderProgram::QShaderProgram(QShaderProgramPrivate &dd, QNode *parent)
542 : QNode(dd, parent)
543{
544}
545
546/*!
547 \qmlproperty string ShaderProgram::vertexShaderCode
548
549 Holds the vertex shader code used by this shader program.
550*/
551/*!
552 \property QShaderProgram::vertexShaderCode
553
554 Holds the vertex shader code used by this shader program.
555*/
556void QShaderProgram::setVertexShaderCode(const QByteArray &vertexShaderCode)
557{
558 Q_D(QShaderProgram);
559 if (vertexShaderCode != d->m_vertexShaderCode) {
560 d->m_vertexShaderCode = vertexShaderCode;
561 emit vertexShaderCodeChanged(vertexShaderCode);
562 }
563}
564
565QByteArray QShaderProgram::vertexShaderCode() const
566{
567 Q_D(const QShaderProgram);
568 return d->m_vertexShaderCode;
569}
570
571/*!
572 \qmlproperty string ShaderProgram::tessellationControlShaderCode
573
574 Holds the tesselation control shader code used by this shader program.
575*/
576/*!
577 \property QShaderProgram::tessellationControlShaderCode
578
579 Holds the tesselation control shader code used by this shader program.
580*/
581void QShaderProgram::setTessellationControlShaderCode(const QByteArray &tessellationControlShaderCode)
582{
583 Q_D(QShaderProgram);
584 if (tessellationControlShaderCode != d->m_tessControlShaderCode) {
585 d->m_tessControlShaderCode = tessellationControlShaderCode;
586 emit tessellationControlShaderCodeChanged(tessellationControlShaderCode);
587 }
588}
589
590QByteArray QShaderProgram::tessellationControlShaderCode() const
591{
592 Q_D(const QShaderProgram);
593 return d->m_tessControlShaderCode;
594}
595
596/*!
597 \qmlproperty string ShaderProgram::tessellationEvaluationShaderCode
598
599 Holds the tesselation evaluation shader code used by this shader program.
600*/
601/*!
602 \property QShaderProgram::tessellationEvaluationShaderCode
603
604 Holds the tesselation evaluation shader code used by this shader program.
605*/
606void QShaderProgram::setTessellationEvaluationShaderCode(const QByteArray &tessellationEvaluationShaderCode)
607{
608 Q_D(QShaderProgram);
609 if (tessellationEvaluationShaderCode != d->m_tessEvalShaderCode) {
610 d->m_tessEvalShaderCode = tessellationEvaluationShaderCode;
611 emit tessellationEvaluationShaderCodeChanged(tessellationEvaluationShaderCode);
612 }
613}
614
615QByteArray QShaderProgram::tessellationEvaluationShaderCode() const
616{
617 Q_D(const QShaderProgram);
618 return d->m_tessEvalShaderCode;
619}
620
621/*!
622 \qmlproperty string ShaderProgram::geometryShaderCode
623
624 Holds the geometry shader code used by this shader program.
625*/
626/*!
627 \property QShaderProgram::geometryShaderCode
628
629 Holds the geometry shader code used by this shader program.
630*/
631void QShaderProgram::setGeometryShaderCode(const QByteArray &geometryShaderCode)
632{
633 Q_D(QShaderProgram);
634 if (geometryShaderCode != d->m_geometryShaderCode) {
635 d->m_geometryShaderCode = geometryShaderCode;
636 emit geometryShaderCodeChanged(geometryShaderCode);
637 }
638}
639
640QByteArray QShaderProgram::geometryShaderCode() const
641{
642 Q_D(const QShaderProgram);
643 return d->m_geometryShaderCode;
644}
645
646/*!
647 \qmlproperty string ShaderProgram::fragmentShaderCode
648
649 Holds the fragment shader code used by this shader program.
650*/
651/*!
652 \property QShaderProgram::fragmentShaderCode
653
654 Holds the fragment shader code used by this shader program.
655*/
656void QShaderProgram::setFragmentShaderCode(const QByteArray &fragmentShaderCode)
657{
658 Q_D(QShaderProgram);
659 if (fragmentShaderCode != d->m_fragmentShaderCode) {
660 d->m_fragmentShaderCode = fragmentShaderCode;
661 emit fragmentShaderCodeChanged(fragmentShaderCode);
662 }
663}
664
665QByteArray QShaderProgram::fragmentShaderCode() const
666{
667 Q_D(const QShaderProgram);
668 return d->m_fragmentShaderCode;
669}
670
671/*!
672 \qmlproperty string ShaderProgram::computeShaderCode
673
674 Holds the compute shader code used by this shader program.
675*/
676/*!
677 \property QShaderProgram::computeShaderCode
678
679 Holds the compute shader code used by this shader program.
680*/
681void QShaderProgram::setComputeShaderCode(const QByteArray &computeShaderCode)
682{
683 Q_D(QShaderProgram);
684 if (computeShaderCode != d->m_computeShaderCode) {
685 d->m_computeShaderCode = computeShaderCode;
686 emit computeShaderCodeChanged(computeShaderCode);
687 }
688}
689
690QByteArray QShaderProgram::computeShaderCode() const
691{
692 Q_D(const QShaderProgram);
693 return d->m_computeShaderCode;
694}
695
696
697/*!
698 Sets the shader code for \a type of shader to the \a shaderCode.
699*/
700void QShaderProgram::setShaderCode(ShaderType type, const QByteArray &shaderCode)
701{
702 switch (type) {
703 case Vertex:
704 setVertexShaderCode(shaderCode);
705 break;
706 case TessellationControl:
707 setTessellationControlShaderCode(shaderCode);
708 break;
709 case TessellationEvaluation:
710 setTessellationEvaluationShaderCode(shaderCode);
711 break;
712 case Geometry:
713 setGeometryShaderCode(shaderCode);
714 break;
715 case Fragment:
716 setFragmentShaderCode(shaderCode);
717 break;
718 case Compute:
719 setComputeShaderCode(shaderCode);
720 break;
721 default:
722 Q_UNREACHABLE();
723 }
724}
725
726/*!
727 Returns the shader code for \a type.
728*/
729QByteArray QShaderProgram::shaderCode(ShaderType type) const
730{
731 Q_D(const QShaderProgram);
732 switch (type) {
733 case Vertex:
734 return d->m_vertexShaderCode;
735 case TessellationControl:
736 return d->m_tessControlShaderCode;
737 case TessellationEvaluation:
738 return d->m_tessEvalShaderCode;
739 case Geometry:
740 return d->m_geometryShaderCode;
741 case Fragment:
742 return d->m_fragmentShaderCode;
743 case Compute:
744 return d->m_computeShaderCode;
745 default:
746 Q_UNREACHABLE();
747 }
748}
749
750/*!
751 \qmlproperty string ShaderProgram::log
752
753 Holds the log of the current shader program. This is useful to diagnose a
754 compilation failure of the shader program.
755*/
756/*!
757 \property QShaderProgram::log
758
759 Holds the log of the current shader program. This is useful to diagnose a
760 compilation failure of the shader program.
761*/
762QString QShaderProgram::log() const
763{
764 Q_D(const QShaderProgram);
765 return d->m_log;
766}
767
768/*!
769 \qmlproperty enumeration ShaderProgram::status
770
771 Holds the status of the current shader program.
772*/
773/*!
774 \property QShaderProgram::status
775
776 Holds the status of the current shader program.
777*/
778/*!
779 Returns the status of the current shader program.
780*/
781QShaderProgram::Status QShaderProgram::status() const
782{
783 Q_D(const QShaderProgram);
784 return d->m_status;
785}
786
787void QShaderProgram::setFormat(QShaderProgram::Format format)
788{
789 Q_D(QShaderProgram);
790 if (format != d->m_format) {
791 d->m_format = format;
792 emit formatChanged(format);
793 }
794}
795
796/*!
797 \qmlproperty enumeration ShaderProgram::format
798 \since 5.15
799
800 Holds the format of the code provided on the ShaderProgram.
801 The default is ShaderProgram.GLSL
802*/
803/*!
804 \property QShaderProgram::format
805 \since 5.15
806
807 Holds the format of the code provided on the ShaderProgram.
808 The default is ShaderProgram.GLSL
809*/
810QShaderProgram::Format QShaderProgram::format() const
811{
812 Q_D(const QShaderProgram);
813 return d->m_format;
814}
815
816QByteArray QShaderProgramPrivate::deincludify(const QString &filePath)
817{
818 QFile f(filePath);
819 if (!f.open(flags: QIODevice::ReadOnly | QIODevice::Text)) {
820 qWarning() << "Could not read shader source file:" << f.fileName();
821 return QByteArray();
822 }
823
824 QByteArray contents = f.readAll();
825 return deincludify(contents, filePath);
826}
827
828QByteArray QShaderProgramPrivate::resolveAutoBindingIndices(const QByteArray &content,
829 int &currentBinding,
830 int &currentInputLocation,
831 int &currentOutputLocation)
832{
833 QString shaderCode = QString::fromUtf8(ba: content);
834
835 // This lambda will replace all occurrences of a string (e.g. "binding = auto") by another,
836 // with the incremented int passed as argument (e.g. "binding = 1", "binding = 2" ...)
837 const auto replaceAndIncrement = [&](const QRegularExpression &regexp,
838 int &variable,
839 const QString &replacement) noexcept {
840 qsizetype matchStart = 0;
841 do {
842 matchStart = shaderCode.indexOf(re: regexp, from: matchStart);
843 if (matchStart != -1) {
844 const auto match = regexp.matchView(subjectView: QStringView{shaderCode}.mid(pos: matchStart));
845 const auto length = match.capturedLength(nth: 0);
846 shaderCode.replace(i: matchStart, len: length, after: replacement.arg(a: variable++));
847 }
848 } while (matchStart != -1);
849 };
850
851 // 1. Handle uniforms
852 {
853 thread_local const QRegularExpression bindings(
854 QStringLiteral("binding\\s*=\\s*auto"));
855
856 replaceAndIncrement(bindings, currentBinding, QStringLiteral("binding = %1"));
857 }
858
859 // 2. Handle inputs
860 {
861 thread_local const QRegularExpression inLocations(
862 QStringLiteral("location\\s*=\\s*auto\\s*\\)\\s*in\\s+"));
863
864 replaceAndIncrement(inLocations, currentInputLocation,
865 QStringLiteral("location = %1) in "));
866 }
867
868 // 3. Handle outputs
869 {
870 thread_local const QRegularExpression outLocations(
871 QStringLiteral("location\\s*=\\s*auto\\s*\\)\\s*out\\s+"));
872
873 replaceAndIncrement(outLocations, currentOutputLocation,
874 QStringLiteral("location = %1) out "));
875 }
876
877 return shaderCode.toUtf8();
878}
879
880QByteArray QShaderProgramPrivate::resolveAutoBindingIndices(const QByteArray &content)
881{
882 int currentBinding = 2; // Qt3D default uniforms are 0 and 1
883 int currentInputLocation = 0;
884 int currentOutputLocation = 0;
885
886 return QShaderProgramPrivate::resolveAutoBindingIndices(content,
887 currentBinding,
888 currentInputLocation,
889 currentOutputLocation);
890}
891
892QByteArray QShaderProgramPrivate::deincludify(const QByteArray &contents, const QString &filePath)
893{
894 QByteArrayList lines = contents.split(sep: '\n');
895 const QByteArray includeDirective = QByteArrayLiteral("#pragma include");
896 for (int i = 0; i < lines.size(); ++i) {
897 const auto line = lines[i].simplified();
898 if (line.startsWith(bv: includeDirective)) {
899 const QString includePartialPath = QString::fromUtf8(ba: line.mid(index: includeDirective.size() + 1));
900
901 QString includePath = QFileInfo(includePartialPath).isAbsolute() ? includePartialPath
902 : QFileInfo(filePath).absolutePath() + QLatin1Char('/') + includePartialPath;
903 if (qEnvironmentVariableIsSet(varName: "QT3D_GLSL100_WORKAROUND")) {
904 QString candidate = includePath + QLatin1String("100");
905 if (QFile::exists(fileName: candidate))
906 includePath = candidate;
907 }
908 lines.removeAt(i);
909 QByteArray includedContents = deincludify(filePath: includePath);
910 lines.insert(i, t: includedContents);
911 QString lineDirective = QString(QStringLiteral("#line %1")).arg(a: i + 2);
912 lines.insert(i: i + 1, t: lineDirective.toUtf8());
913 }
914 }
915
916 return lines.join(sep: '\n');
917}
918
919/*!
920 \qmlmethod string ShaderProgram::loadSource(url sourceUrl)
921
922 Returns the shader code loaded from \a sourceUrl.
923*/
924/*!
925 Returns the shader code loaded from \a sourceUrl.
926*/
927QByteArray QShaderProgram::loadSource(const QUrl &sourceUrl)
928{
929 // TO DO: Handle remote path
930 const QByteArray deincluded = QShaderProgramPrivate::deincludify(filePath: Qt3DCore::QUrlHelper::urlToLocalFileOrQrc(url: sourceUrl));
931 return QShaderProgramPrivate::resolveAutoBindingIndices(content: deincluded);
932}
933
934} // of namespace Qt3DRender
935
936QT_END_NAMESPACE
937
938#include "moc_qshaderprogram.cpp"
939

source code of qt3d/src/render/materialsystem/qshaderprogram.cpp