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 | |
104 | QT_BEGIN_NAMESPACE |
105 | |
106 | namespace Qt3DRender { |
107 | |
108 | QShaderProgramBuilderPrivate::QShaderProgramBuilderPrivate() |
109 | : QNodePrivate(), |
110 | m_shaderProgram(nullptr) |
111 | { |
112 | } |
113 | |
114 | void 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 | |
155 | QShaderProgramBuilder::QShaderProgramBuilder(QNode *parent) |
156 | : QNode(*new QShaderProgramBuilderPrivate, parent) |
157 | { |
158 | } |
159 | |
160 | QShaderProgramBuilder::~QShaderProgramBuilder() |
161 | { |
162 | } |
163 | |
164 | /*! \internal */ |
165 | QShaderProgramBuilder::QShaderProgramBuilder(QShaderProgramBuilderPrivate &dd, QNode *parent) |
166 | : QNode(dd, parent) |
167 | { |
168 | } |
169 | |
170 | // TODO Unused remove in Qt6 |
171 | void 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 | */ |
185 | void 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 | |
209 | QShaderProgram *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 | */ |
227 | void 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 | |
236 | QStringList 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 | */ |
252 | void 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 | |
261 | QUrl 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 | */ |
277 | void 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 | |
286 | QUrl 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 | */ |
302 | void 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 | |
311 | QUrl 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 | */ |
327 | void 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 | |
336 | QUrl 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 | */ |
352 | void 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 | |
361 | QUrl 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 | */ |
377 | void 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 | |
386 | QUrl 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 | */ |
404 | QByteArray 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 | */ |
422 | QByteArray 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 | */ |
440 | QByteArray 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 | */ |
458 | QByteArray 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 | */ |
476 | QByteArray 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 | */ |
494 | QByteArray QShaderProgramBuilder::computeShaderCode() const |
495 | { |
496 | Q_D(const QShaderProgramBuilder); |
497 | return d->m_computeShaderCode; |
498 | } |
499 | |
500 | Qt3DCore::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 | |
518 | QT_END_NAMESPACE |
519 | |