1/****************************************************************************
2**
3** Copyright (C) 2017 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 "qshaderprogrambuilder.h"
41#include "qshaderprogrambuilder_p.h"
42#include "qshaderprogram.h"
43#include <Qt3DCore/qpropertyupdatedchange.h>
44#include <Qt3DRender/private/qurlhelper_p.h>
45#include <QDebug>
46#include <QFile>
47#include <QFileInfo>
48#include <QUrl>
49
50/*!
51 \class Qt3DRender::QShaderProgramBuilder
52 \inmodule Qt3DRender
53 \brief Generates a Shader Program content from loaded graphs.
54 \inherits Qt3DCore::QNode
55 \since 5.10
56
57 A shader program builder consists of several different shader graphs
58 used to generate shader code.
59
60 A cache of generated shader code is maintained. Generated shaders are by
61 defaults saved in
62 QStandardPaths::writableLocation(QStandardPaths::TempLocation)). This path
63 can be overridden by setting environment variable QT3D_WRITABLE_CACHE_PATH
64 to a valid writable path.
65
66 The use of the cache can be disabled by setting environment variable
67 QT3D_DISABLE_SHADER_CACHE.
68
69 In most cases, changes made to a graph are detected by Qt 3D and a new
70 cache entry will be generated. One case were this will not happen is when
71 code snippets included by a graphs are changed. To work around that,
72 clearing the cache directory or setting environment variable
73 QT3D_REBUILD_SHADER_CACHE can be used to force shader code to be generated
74 again.
75*/
76
77/*!
78 \qmltype ShaderProgramBuilder
79 \instantiates Qt3DRender::QShaderProgramBuilder
80 \inqmlmodule Qt3D.Render
81 \brief Generates a Shader Program content from loaded graphs.
82 \since 5.10
83
84 A shader program builder consists of several different shader graphs
85 used to generate shader code.
86
87 A cache of generated shader code is maintained. Generated shaders are by
88 defaults saved in
89 QStandardPaths::writableLocation(QStandardPaths::TempLocation)). This path
90 can be overridden by setting environment variable QT3D_WRITABLE_CACHE_PATH
91 to a valid writable path.
92
93 The use of the cache can be disabled by setting environment variable
94 QT3D_DISABLE_SHADER_CACHE.
95
96 In most cases, changes made to a graph are detected by Qt 3D and a new
97 cache entry will be generated. One case were this will not happen is when
98 code snippets included by a graphs are changed. To work around that,
99 clearing the cache directory or setting environment variable
100 QT3D_REBUILD_SHADER_CACHE can be used to force shader code to be generated
101 again.
102*/
103
104QT_BEGIN_NAMESPACE
105
106namespace Qt3DRender {
107
108QShaderProgramBuilderPrivate::QShaderProgramBuilderPrivate()
109 : QNodePrivate(),
110 m_shaderProgram(nullptr)
111{
112}
113
114void QShaderProgramBuilderPrivate::setShaderCode(const QByteArray &code, QShaderProgram::ShaderType type)
115{
116 Q_Q(QShaderProgramBuilder);
117 const bool blocked = q->blockNotifications(block: true);
118
119 switch (type) {
120 case QShaderProgram::Vertex: {
121 m_vertexShaderCode = code;
122 emit q->vertexShaderCodeChanged(vertexShaderCode: m_vertexShaderCode);
123 break;
124 }
125 case QShaderProgram::Fragment:{
126 m_fragmentShaderCode = code;
127 emit q->fragmentShaderCodeChanged(fragmentShaderCode: m_fragmentShaderCode);
128 break;
129 }
130 case QShaderProgram::Geometry: {
131 m_geometryShaderCode = code;
132 emit q->geometryShaderCodeChanged(geometryShaderCode: m_geometryShaderCode);
133 break;
134 }
135 case QShaderProgram::Compute: {
136 m_computeShaderCode = code;
137 emit q->computeShaderCodeChanged(computeShaderCode: m_computeShaderCode);
138 break;
139 }
140 case QShaderProgram::TessellationControl: {
141 m_tessControlShaderCode = code;
142 emit q->tessellationControlShaderCodeChanged(tessellationControlShaderCode: m_tessControlShaderCode);
143 break;
144 }
145 case QShaderProgram::TessellationEvaluation: {
146 m_tessEvalShaderCode = code;
147 emit q->tessellationEvaluationShaderCodeChanged(tessellationEvaluationShaderCode: m_tessEvalShaderCode);
148 break;
149 }
150 }
151
152 q->blockNotifications(block: blocked);
153}
154
155QShaderProgramBuilder::QShaderProgramBuilder(QNode *parent)
156 : QNode(*new QShaderProgramBuilderPrivate, parent)
157{
158}
159
160QShaderProgramBuilder::~QShaderProgramBuilder()
161{
162}
163
164/*! \internal */
165QShaderProgramBuilder::QShaderProgramBuilder(QShaderProgramBuilderPrivate &dd, QNode *parent)
166 : QNode(dd, parent)
167{
168}
169
170// TODO Unused remove in Qt6
171void QShaderProgramBuilder::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &)
172{
173}
174
175/*!
176 \qmlproperty string ShaderProgramBuilder::shaderProgram
177
178 Holds the shader program on which this builder generates code.
179*/
180/*!
181 \property QShaderProgramBuilder::shaderProgram
182
183 Holds the shader program on which this builder generates code.
184*/
185void QShaderProgramBuilder::setShaderProgram(QShaderProgram *program)
186{
187 Q_D(QShaderProgramBuilder);
188 if (program != d->m_shaderProgram) {
189
190 if (d->m_shaderProgram)
191 d->unregisterDestructionHelper(node: d->m_shaderProgram);
192
193 // We need to add it as a child of the current node if it has been declared inline
194 // Or not previously added as a child of the current node so that
195 // 1) The backend gets notified about it's creation
196 // 2) When the current node is destroyed, it gets destroyed as well
197 if (program && !program->parent())
198 program->setParent(this);
199 d->m_shaderProgram = program;
200
201 // Ensures proper bookkeeping
202 if (d->m_shaderProgram)
203 d->registerDestructionHelper(node: d->m_shaderProgram, func: &QShaderProgramBuilder::setShaderProgram, d->m_shaderProgram);
204
205 emit shaderProgramChanged(shaderProgram: program);
206 }
207}
208
209QShaderProgram *QShaderProgramBuilder::shaderProgram() const
210{
211 Q_D(const QShaderProgramBuilder);
212 return d->m_shaderProgram;
213}
214
215/*!
216 \qmlproperty stringlist ShaderProgramBuilder::enabledLayers
217
218 Holds the list of layers this builder will activate on the shader graphs
219 during code generation.
220*/
221/*!
222 \property QShaderProgramBuilder::enabledLayers
223
224 Holds the list of layers this builder will activate on the shader graphs
225 during code generation.
226*/
227void QShaderProgramBuilder::setEnabledLayers(const QStringList &layers)
228{
229 Q_D(QShaderProgramBuilder);
230 if (layers != d->m_enabledLayers) {
231 d->m_enabledLayers = layers;
232 emit enabledLayersChanged(layers);
233 }
234}
235
236QStringList QShaderProgramBuilder::enabledLayers() const
237{
238 Q_D(const QShaderProgramBuilder);
239 return d->m_enabledLayers;
240}
241
242/*!
243 \qmlproperty string ShaderProgram::vertexShaderGraph
244
245 Holds the URL to the vertex shader graph used by this shader program builder.
246*/
247/*!
248 \property QShaderProgramBuilder::vertexShaderGraph
249
250 Holds the URL to the vertex shader graph used by this shader program builder.
251*/
252void QShaderProgramBuilder::setVertexShaderGraph(const QUrl &vertexShaderGraph)
253{
254 Q_D(QShaderProgramBuilder);
255 if (vertexShaderGraph != d->m_vertexShaderGraph) {
256 d->m_vertexShaderGraph = vertexShaderGraph;
257 emit vertexShaderGraphChanged(vertexShaderGraph);
258 }
259}
260
261QUrl QShaderProgramBuilder::vertexShaderGraph() const
262{
263 Q_D(const QShaderProgramBuilder);
264 return d->m_vertexShaderGraph;
265}
266
267/*!
268 \qmlproperty string ShaderProgram::tessellationControlShaderGraph
269
270 Holds the URL to the tesselation control shader graph used by this shader program builder.
271*/
272/*!
273 \property QShaderProgramBuilder::tessellationControlShaderGraph
274
275 Holds the URL to the tesselation control shader graph used by this shader program builder.
276*/
277void QShaderProgramBuilder::setTessellationControlShaderGraph(const QUrl &tessellationControlShaderGraph)
278{
279 Q_D(QShaderProgramBuilder);
280 if (tessellationControlShaderGraph != d->m_tessControlShaderGraph) {
281 d->m_tessControlShaderGraph = tessellationControlShaderGraph;
282 emit tessellationControlShaderGraphChanged(tessellationControlShaderGraph);
283 }
284}
285
286QUrl QShaderProgramBuilder::tessellationControlShaderGraph() const
287{
288 Q_D(const QShaderProgramBuilder);
289 return d->m_tessControlShaderGraph;
290}
291
292/*!
293 \qmlproperty string ShaderProgram::tessellationEvaluationShaderGraph
294
295 Holds the URL to the tesselation evaluation shader graph used by this shader program builder.
296*/
297/*!
298 \property QShaderProgramBuilder::tessellationEvaluationShaderGraph
299
300 Holds the URL to the tesselation evaluation shader graph used by this shader program builder.
301*/
302void QShaderProgramBuilder::setTessellationEvaluationShaderGraph(const QUrl &tessellationEvaluationShaderGraph)
303{
304 Q_D(QShaderProgramBuilder);
305 if (tessellationEvaluationShaderGraph != d->m_tessEvalShaderGraph) {
306 d->m_tessEvalShaderGraph = tessellationEvaluationShaderGraph;
307 emit tessellationEvaluationShaderGraphChanged(tessellationEvaluationShaderGraph);
308 }
309}
310
311QUrl QShaderProgramBuilder::tessellationEvaluationShaderGraph() const
312{
313 Q_D(const QShaderProgramBuilder);
314 return d->m_tessEvalShaderGraph;
315}
316
317/*!
318 \qmlproperty string ShaderProgram::geometryShaderGraph
319
320 Holds the URL to the geometry shader graph used by this shader program builder.
321*/
322/*!
323 \property QShaderProgramBuilder::geometryShaderGraph
324
325 Holds the URL to the geometry shader graph used by this shader program builder.
326*/
327void QShaderProgramBuilder::setGeometryShaderGraph(const QUrl &geometryShaderGraph)
328{
329 Q_D(QShaderProgramBuilder);
330 if (geometryShaderGraph != d->m_geometryShaderGraph) {
331 d->m_geometryShaderGraph = geometryShaderGraph;
332 emit geometryShaderGraphChanged(geometryShaderGraph);
333 }
334}
335
336QUrl QShaderProgramBuilder::geometryShaderGraph() const
337{
338 Q_D(const QShaderProgramBuilder);
339 return d->m_geometryShaderGraph;
340}
341
342/*!
343 \qmlproperty string ShaderProgram::fragmentShaderGraph
344
345 Holds the URL to the fragment shader graph used by this shader program builder.
346*/
347/*!
348 \property QShaderProgramBuilder::fragmentShaderGraph
349
350 Holds the URL to the fragment shader graph used by this shader program builder.
351*/
352void QShaderProgramBuilder::setFragmentShaderGraph(const QUrl &fragmentShaderGraph)
353{
354 Q_D(QShaderProgramBuilder);
355 if (fragmentShaderGraph != d->m_fragmentShaderGraph) {
356 d->m_fragmentShaderGraph = fragmentShaderGraph;
357 emit fragmentShaderGraphChanged(fragmentShaderGraph);
358 }
359}
360
361QUrl QShaderProgramBuilder::fragmentShaderGraph() const
362{
363 Q_D(const QShaderProgramBuilder);
364 return d->m_fragmentShaderGraph;
365}
366
367/*!
368 \qmlproperty string ShaderProgram::computeShaderGraph
369
370 Holds the URL to the compute shader graph used by this shader program builder.
371*/
372/*!
373 \property QShaderProgramBuilder::computeShaderGraph
374
375 Holds the URL to the compute shader graph used by this shader program builder.
376*/
377void QShaderProgramBuilder::setComputeShaderGraph(const QUrl &computeShaderGraph)
378{
379 Q_D(QShaderProgramBuilder);
380 if (computeShaderGraph != d->m_computeShaderGraph) {
381 d->m_computeShaderGraph = computeShaderGraph;
382 emit computeShaderGraphChanged(computeShaderGraph);
383 }
384}
385
386QUrl QShaderProgramBuilder::computeShaderGraph() const
387{
388 Q_D(const QShaderProgramBuilder);
389 return d->m_computeShaderGraph;
390}
391
392/*!
393 \qmlproperty string ShaderProgramBuilder::vertexShaderCode
394
395 Holds the generated vertex shader code
396 \since 2.13
397*/
398/*!
399 \property QShaderProgramBuilder::vertexShaderCode
400
401 Holds the generate vertex shader code.
402 \since 5.13
403*/
404QByteArray QShaderProgramBuilder::vertexShaderCode() const
405{
406 Q_D(const QShaderProgramBuilder);
407 return d->m_vertexShaderCode;
408}
409
410/*!
411 \qmlproperty string ShaderProgramBuilder::tessellationControlShaderCode
412
413 Holds the generated tessellation control shader code
414 \since 2.13
415*/
416/*!
417 \property QShaderProgramBuilder::tessellationControlShaderCode
418
419 Holds the generate tessellation control shader code.
420 \since 5.13
421*/
422QByteArray QShaderProgramBuilder::tessellationControlShaderCode() const
423{
424 Q_D(const QShaderProgramBuilder);
425 return d->m_tessControlShaderCode;
426}
427
428/*!
429 \qmlproperty string ShaderProgramBuilder::tessellationEvaluationShaderCode
430
431 Holds the generated tessellation evaluation shader code
432 \since 2.13
433*/
434/*!
435 \property QShaderProgramBuilder::tessellationEvaluationShaderCode
436
437 Holds the generate tessellation evaluation shader code.
438 \since 5.13
439*/
440QByteArray QShaderProgramBuilder::tessellationEvaluationShaderCode() const
441{
442 Q_D(const QShaderProgramBuilder);
443 return d->m_tessEvalShaderCode;
444}
445
446/*!
447 \qmlproperty string ShaderProgramBuilder::geometryShaderCode
448
449 Holds the generated geometry shader code
450 \since 2.13
451*/
452/*!
453 \property QShaderProgramBuilder::geometryShaderCode
454
455 Holds the generate geometry shader code.
456 \since 5.13
457*/
458QByteArray QShaderProgramBuilder::geometryShaderCode() const
459{
460 Q_D(const QShaderProgramBuilder);
461 return d->m_geometryShaderCode;
462}
463
464/*!
465 \qmlproperty string ShaderProgramBuilder::fragmentShaderCode
466
467 Holds the generated fragment shader code
468 \since 2.13
469*/
470/*!
471 \property QShaderProgramBuilder::fragmentShaderCode
472
473 Holds the generate fragment shader code.
474 \since 5.13
475*/
476QByteArray QShaderProgramBuilder::fragmentShaderCode() const
477{
478 Q_D(const QShaderProgramBuilder);
479 return d->m_fragmentShaderCode;
480}
481
482/*!
483 \qmlproperty string ShaderProgramBuilder::computeShaderCode
484
485 Holds the generated compute shader code
486 \since 2.13
487*/
488/*!
489 \property QShaderProgramBuilder::computeShaderCode
490
491 Holds the generate compute shader code.
492 \since 5.13
493*/
494QByteArray QShaderProgramBuilder::computeShaderCode() const
495{
496 Q_D(const QShaderProgramBuilder);
497 return d->m_computeShaderCode;
498}
499
500Qt3DCore::QNodeCreatedChangeBasePtr QShaderProgramBuilder::createNodeCreationChange() const
501{
502 auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QShaderProgramBuilderData>::create(arguments: this);
503 auto &data = creationChange->data;
504 Q_D(const QShaderProgramBuilder);
505 data.shaderProgramId = d->m_shaderProgram ? d->m_shaderProgram->id() : Qt3DCore::QNodeId();
506 data.enabledLayers = d->m_enabledLayers;
507 data.vertexShaderGraph = d->m_vertexShaderGraph;
508 data.tessellationControlShaderGraph = d->m_tessControlShaderGraph;
509 data.tessellationEvaluationShaderGraph = d->m_tessEvalShaderGraph;
510 data.geometryShaderGraph = d->m_geometryShaderGraph;
511 data.fragmentShaderGraph = d->m_fragmentShaderGraph;
512 data.computeShaderGraph = d->m_computeShaderGraph;
513 return creationChange;
514}
515
516} // of namespace Qt3DRender
517
518QT_END_NAMESPACE
519

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