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