1 | // Copyright (C) 2020 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 "rhishader_p.h" |
5 | #include <QMutexLocker> |
6 | #include <Qt3DCore/private/vector_helper_p.h> |
7 | #include <Qt3DRender/private/stringtoint_p.h> |
8 | #include <submissioncontext_p.h> |
9 | #include <logging_p.h> |
10 | #include <QRegularExpression> |
11 | |
12 | QT_BEGIN_NAMESPACE |
13 | |
14 | namespace Qt3DRender { |
15 | |
16 | namespace Render { |
17 | |
18 | namespace Rhi { |
19 | |
20 | RHIShader::RHIShader() : m_isLoaded(false) |
21 | { |
22 | m_shaderCode.resize(new_size: static_cast<int>(QShaderProgram::Compute) + 1); |
23 | } |
24 | |
25 | const std::vector<QString> &RHIShader::uniformsNames() const |
26 | { |
27 | return m_uniformsNames; |
28 | } |
29 | |
30 | const std::vector<QString> &RHIShader::attributesNames() const |
31 | { |
32 | return m_attributesNames; |
33 | } |
34 | |
35 | const std::vector<QString> &RHIShader::uniformBlockNames() const |
36 | { |
37 | return m_uniformBlockNames; |
38 | } |
39 | |
40 | const std::vector<QString> &RHIShader::storageBlockNames() const |
41 | { |
42 | return m_shaderStorageBlockNames; |
43 | } |
44 | |
45 | const std::vector<QString> &RHIShader::samplerNames() const |
46 | { |
47 | return m_samplerNames; |
48 | } |
49 | |
50 | const std::vector<QString> &RHIShader::imagesNames() const |
51 | { |
52 | return m_imageNames; |
53 | } |
54 | |
55 | const std::vector<QByteArray> &RHIShader::shaderCode() const |
56 | { |
57 | return m_shaderCode; |
58 | } |
59 | |
60 | namespace { |
61 | |
62 | static constexpr int rhiTypeSize(QShaderDescription::VariableType type) |
63 | { |
64 | switch (type) { |
65 | case QShaderDescription::Unknown: |
66 | return 0; |
67 | |
68 | case QShaderDescription::Float: |
69 | return 1; |
70 | case QShaderDescription::Vec2: |
71 | return 2; |
72 | case QShaderDescription::Vec3: |
73 | return 3; |
74 | case QShaderDescription::Vec4: |
75 | return 4; |
76 | case QShaderDescription::Mat2: |
77 | return 2 * 2; |
78 | case QShaderDescription::Mat2x3: |
79 | return 2 * 3; |
80 | case QShaderDescription::Mat2x4: |
81 | return 2 * 4; |
82 | case QShaderDescription::Mat3: |
83 | return 3 * 3; |
84 | case QShaderDescription::Mat3x2: |
85 | return 3 * 2; |
86 | case QShaderDescription::Mat3x4: |
87 | return 3 * 4; |
88 | case QShaderDescription::Mat4: |
89 | return 4 * 4; |
90 | case QShaderDescription::Mat4x2: |
91 | return 4 * 2; |
92 | case QShaderDescription::Mat4x3: |
93 | return 4 * 3; |
94 | |
95 | case QShaderDescription::Int: |
96 | return 1; |
97 | case QShaderDescription::Int2: |
98 | return 2; |
99 | case QShaderDescription::Int3: |
100 | return 3; |
101 | case QShaderDescription::Int4: |
102 | return 4; |
103 | |
104 | case QShaderDescription::Uint: |
105 | return 1; |
106 | case QShaderDescription::Uint2: |
107 | return 2; |
108 | case QShaderDescription::Uint3: |
109 | return 3; |
110 | case QShaderDescription::Uint4: |
111 | return 4; |
112 | |
113 | case QShaderDescription::Bool: |
114 | return 1; |
115 | case QShaderDescription::Bool2: |
116 | return 2; |
117 | case QShaderDescription::Bool3: |
118 | return 3; |
119 | case QShaderDescription::Bool4: |
120 | return 4; |
121 | |
122 | case QShaderDescription::Double: |
123 | return 1; |
124 | case QShaderDescription::Double2: |
125 | return 2; |
126 | case QShaderDescription::Double3: |
127 | return 3; |
128 | case QShaderDescription::Double4: |
129 | return 4; |
130 | case QShaderDescription::DMat2: |
131 | return 2 * 2; |
132 | case QShaderDescription::DMat2x3: |
133 | return 2 * 3; |
134 | case QShaderDescription::DMat2x4: |
135 | return 2 * 4; |
136 | case QShaderDescription::DMat3: |
137 | return 3 * 3; |
138 | case QShaderDescription::DMat3x2: |
139 | return 3 * 2; |
140 | case QShaderDescription::DMat3x4: |
141 | return 3 * 4; |
142 | case QShaderDescription::DMat4: |
143 | return 4 * 4; |
144 | case QShaderDescription::DMat4x2: |
145 | return 4 * 2; |
146 | case QShaderDescription::DMat4x3: |
147 | return 4 * 3; |
148 | |
149 | case QShaderDescription::Sampler1D: |
150 | return 0; |
151 | case QShaderDescription::Sampler2D: |
152 | return 0; |
153 | case QShaderDescription::Sampler2DMS: |
154 | return 0; |
155 | case QShaderDescription::Sampler3D: |
156 | return 0; |
157 | case QShaderDescription::SamplerCube: |
158 | return 0; |
159 | case QShaderDescription::Sampler1DArray: |
160 | return 0; |
161 | case QShaderDescription::Sampler2DArray: |
162 | return 0; |
163 | case QShaderDescription::Sampler2DMSArray: |
164 | return 0; |
165 | case QShaderDescription::Sampler3DArray: |
166 | return 0; |
167 | case QShaderDescription::SamplerCubeArray: |
168 | return 0; |
169 | case QShaderDescription::SamplerRect: |
170 | return 0; |
171 | case QShaderDescription::SamplerBuffer: |
172 | return 0; |
173 | |
174 | case QShaderDescription::Image1D: |
175 | return 0; |
176 | case QShaderDescription::Image2D: |
177 | return 0; |
178 | case QShaderDescription::Image2DMS: |
179 | return 0; |
180 | case QShaderDescription::Image3D: |
181 | return 0; |
182 | case QShaderDescription::ImageCube: |
183 | return 0; |
184 | case QShaderDescription::Image1DArray: |
185 | return 0; |
186 | case QShaderDescription::Image2DArray: |
187 | return 0; |
188 | case QShaderDescription::Image2DMSArray: |
189 | return 0; |
190 | case QShaderDescription::Image3DArray: |
191 | return 0; |
192 | case QShaderDescription::ImageCubeArray: |
193 | return 0; |
194 | case QShaderDescription::ImageRect: |
195 | return 0; |
196 | case QShaderDescription::ImageBuffer: |
197 | return 0; |
198 | |
199 | case QShaderDescription::Struct: |
200 | return 0; |
201 | default: |
202 | return 0; |
203 | } |
204 | } |
205 | |
206 | template<typename T, typename Pred> |
207 | std::vector<T> stableRemoveDuplicates(std::vector<T> in, Pred predicate) |
208 | { |
209 | std::vector<T> out; |
210 | for (const auto &element : in) { |
211 | if (std::none_of(out.begin(), out.end(), |
212 | [&](T &other) { return predicate(element, other); })) |
213 | out.push_back(element); |
214 | } |
215 | return out; |
216 | } |
217 | |
218 | // Utility function to enumerate an array of dimensions |
219 | // Given dims == [0, 3, 2] and maxs == [4, 4, 4] |
220 | // changes dims into [0, 3, 3] |
221 | // Given dims == [0, 3, 3] and maxs == [4, 4, 4] |
222 | // changes dims into [1, 0, 0] |
223 | bool incrementArray(QVarLengthArray<int> &dims, const QList<int> &maxs) |
224 | { |
225 | const int n = dims.size(); |
226 | int i = n; |
227 | for (; i-- > 0;) { |
228 | if (dims[i] == maxs[i] - 1) { |
229 | if (i == 0) { |
230 | // we're done |
231 | return false; |
232 | } |
233 | continue; |
234 | |
235 | } else { |
236 | dims[i]++; |
237 | for (int j = i + 1; j < n; j++) { |
238 | dims[j] = 0; |
239 | } |
240 | return true; |
241 | } |
242 | } |
243 | return false; |
244 | } |
245 | |
246 | // Call a function with a string such as [0][3][2] |
247 | // for all valable array values, given an array of dimension sizes. |
248 | // Dimensions must all be >= 1 |
249 | template<typename F> |
250 | void forEachArrayAccessor(const QList<int> &maxs, F f) |
251 | { |
252 | if (std::any_of(maxs.begin(), maxs.end(), [](int v) { return v <= 0; })) |
253 | return; |
254 | |
255 | QVarLengthArray<int> dims; |
256 | dims.resize(sz: maxs.size()); |
257 | |
258 | // QVarLengthArray does not initialize ints |
259 | std::fill(first: dims.begin(), last: dims.end(), value: 0); |
260 | |
261 | QString str; |
262 | |
263 | do { |
264 | str.resize(size: 0); |
265 | for (int k : dims) { |
266 | str += QStringLiteral("[%1]" ).arg(a: k); |
267 | } |
268 | f(str); |
269 | } while (incrementArray(dims, maxs)); |
270 | } |
271 | } |
272 | |
273 | void RHIShader::recordAllUniforms(UBO_Member &uboMember, |
274 | QString parentName) |
275 | { |
276 | const QShaderDescription::BlockVariable &member = uboMember.blockVariable; |
277 | const bool isStruct = !member.structMembers.empty(); |
278 | const bool isArray = !member.arrayDims.empty(); |
279 | |
280 | // "foo.bar" |
281 | const QString fullMemberName = parentName + member.name; |
282 | m_unqualifiedUniformNames << fullMemberName; |
283 | |
284 | if (isStruct && !isArray) { |
285 | m_structNames.push_back(x: fullMemberName); |
286 | m_structNamesIds.push_back(x: StringToInt::lookupId(str: fullMemberName)); |
287 | |
288 | for (const QShaderDescription::BlockVariable& bv : member.structMembers) { |
289 | UBO_Member innerMember {.nameId: StringToInt::lookupId(str: fullMemberName), .blockVariable: bv, .structMembers: {}}; |
290 | // recordAllUniforms("baz", "foo.bar.") |
291 | const QString structMemberNamePrefix = fullMemberName + QLatin1Char('.'); |
292 | recordAllUniforms(uboMember&: innerMember, parentName: structMemberNamePrefix); |
293 | uboMember.structMembers.push_back(x: innerMember); |
294 | } |
295 | } else if (!isStruct && isArray) { |
296 | // We iterate through all the [l][n][m] by building [0][0][0] and incrementing |
297 | forEachArrayAccessor(maxs: member.arrayDims, f: [&](const QString &str) { |
298 | // "foo.bar[1][2]" |
299 | const QString unqualifiedMemberName = (fullMemberName + str); |
300 | m_unqualifiedUniformNames << unqualifiedMemberName; |
301 | |
302 | // Record as an individual uniform |
303 | m_uniformsNames.push_back(x: unqualifiedMemberName); |
304 | const int nameId = StringToInt::lookupId(str: unqualifiedMemberName); |
305 | m_uniformsNamesIds.push_back(x: nameId); |
306 | |
307 | // Question : does it make sense to also record foo[0], foo[0][0], etc... |
308 | // if there are e.g. 3 dimensions ? |
309 | }); |
310 | } |
311 | else if (isStruct && isArray) { |
312 | // Record the struct names |
313 | forEachArrayAccessor(maxs: member.arrayDims, f: [&] (const QString& str) { |
314 | m_structNames.push_back(x: fullMemberName + str); |
315 | m_structNamesIds.push_back(x: StringToInt::lookupId(str: m_structNames.back())); |
316 | }); |
317 | |
318 | // Record the array times the struct members => entry[i].struct_member |
319 | forEachArrayAccessor(maxs: member.arrayDims, f: [&] (const QString& str) { |
320 | UBO_Member arrayMember {.nameId: StringToInt::lookupId(str: fullMemberName + str), .blockVariable: {}, .structMembers: {}}; |
321 | // Record all struct member into the array member[i] |
322 | for (const QShaderDescription::BlockVariable& bv : member.structMembers) { |
323 | //recordAllUniforms("baz", "foo.bar[1][2].") |
324 | const QString structMemberNamePrefix = fullMemberName + str + QLatin1Char('.'); |
325 | UBO_Member innerMember {.nameId: StringToInt::lookupId(str: structMemberNamePrefix), .blockVariable: bv, .structMembers: {}}; |
326 | recordAllUniforms(uboMember&: innerMember, parentName: structMemberNamePrefix); |
327 | arrayMember.structMembers.push_back(x: innerMember); |
328 | } |
329 | // When dealing with an array of structs, we treat structMembers as arrayMembers |
330 | uboMember.structMembers.push_back(x: arrayMember); |
331 | }); |
332 | } else { |
333 | // Final member (not array or struct) |
334 | // Replace nameId with final nameId name |
335 | uboMember.nameId = StringToInt::lookupId(str: fullMemberName); |
336 | |
337 | // Record as an individual uniform |
338 | m_uniformsNames.push_back(x: fullMemberName); |
339 | const int nameId = StringToInt::lookupId(str: fullMemberName); |
340 | m_uniformsNamesIds.push_back(x: nameId); |
341 | } |
342 | } |
343 | |
344 | namespace { |
345 | // Function to check whether the array conforms to the regex |
346 | // "_[0-9]+" - except QRegularExpression does not support QByteArray |
347 | bool isGeneratedUBOName(const QByteArray& arr) |
348 | { |
349 | if (arr.size() < 2) |
350 | return false; |
351 | if (!arr.startsWith(c: '_')) |
352 | return false; |
353 | for (qsizetype i = 1, N = arr.size(); i < N; i++) { |
354 | if (arr[i] < '0' || arr[i] > '9') |
355 | return false; |
356 | } |
357 | return true; |
358 | } |
359 | } |
360 | |
361 | void RHIShader::introspect() |
362 | { |
363 | std::vector<QShaderDescription::UniformBlock> rhiUBO; |
364 | std::vector<QShaderDescription::StorageBlock> rhiSSBO; |
365 | |
366 | std::vector<ShaderUniformBlock> uniformBlocks; |
367 | std::vector<ShaderStorageBlock> storageBlocks; |
368 | std::vector<ShaderAttribute> attributes; |
369 | std::vector<ShaderAttribute> samplers; |
370 | std::vector<ShaderAttribute> images; |
371 | |
372 | if (m_stages[QShader::ComputeStage].isValid()) { |
373 | const QShaderDescription &comp = m_stages[QShader::ComputeStage].description(); |
374 | |
375 | Qt3DCore::append(destination&: rhiUBO, source: comp.uniformBlocks()); |
376 | Qt3DCore::append(destination&: rhiSSBO, source: comp.storageBlocks()); |
377 | } |
378 | else |
379 | { |
380 | // Introspect shader vertex input |
381 | if (m_stages[QShader::VertexStage].isValid()) { |
382 | const QShaderDescription &vtx = m_stages[QShader::VertexStage].description(); |
383 | |
384 | for (const QShaderDescription::InOutVariable &input : vtx.inputVariables()) { |
385 | attributes.push_back(x: ShaderAttribute { .m_name: input.name, .m_nameId: StringToInt::lookupId(str: input.name), |
386 | .m_type: input.type, .m_size: rhiTypeSize(type: input.type), |
387 | .m_location: input.location }); |
388 | } |
389 | |
390 | Qt3DCore::append(destination&: rhiUBO, source: vtx.uniformBlocks()); |
391 | Qt3DCore::append(destination&: rhiSSBO, source: vtx.storageBlocks()); |
392 | } |
393 | |
394 | // Introspect shader uniforms |
395 | if (m_stages[QShader::FragmentStage].isValid()) { |
396 | const QShaderDescription &frag = m_stages[QShader::FragmentStage].description(); |
397 | for (const QShaderDescription::InOutVariable &sampler : frag.combinedImageSamplers()) { |
398 | samplers.push_back(x: ShaderAttribute { .m_name: sampler.name, .m_nameId: StringToInt::lookupId(str: sampler.name), |
399 | .m_type: sampler.type, .m_size: rhiTypeSize(type: sampler.type), |
400 | .m_location: sampler.binding }); |
401 | } |
402 | for (const QShaderDescription::InOutVariable &image : frag.storageImages()) { |
403 | images.push_back(x: ShaderAttribute { .m_name: image.name, .m_nameId: StringToInt::lookupId(str: image.name), |
404 | .m_type: image.type, .m_size: rhiTypeSize(type: image.type), |
405 | .m_location: image.binding }); |
406 | } |
407 | |
408 | Qt3DCore::append(destination&: rhiUBO, source: frag.uniformBlocks()); |
409 | Qt3DCore::append(destination&: rhiSSBO, source: frag.storageBlocks()); |
410 | } |
411 | } |
412 | |
413 | rhiUBO = stableRemoveDuplicates(in: rhiUBO, |
414 | predicate: [](const QShaderDescription::UniformBlock &lhs, |
415 | const QShaderDescription::UniformBlock &rhs) { |
416 | return lhs.blockName == rhs.blockName; |
417 | }); |
418 | rhiSSBO = stableRemoveDuplicates(in: rhiSSBO, |
419 | predicate: [](const QShaderDescription::StorageBlock &lhs, |
420 | const QShaderDescription::StorageBlock &rhs) { |
421 | return lhs.blockName == rhs.blockName; |
422 | }); |
423 | |
424 | for (const QShaderDescription::UniformBlock &ubo : rhiUBO) { |
425 | uniformBlocks.push_back(x: ShaderUniformBlock { .m_name: ubo.blockName, |
426 | .m_nameId: StringToInt::lookupId(str: ubo.blockName), .m_index: -1, |
427 | .m_binding: ubo.binding, .m_activeUniformsCount: int(ubo.members.size()), .m_size: ubo.size }); |
428 | const bool addUnqualifiedUniforms = isGeneratedUBOName(arr: ubo.structName); |
429 | |
430 | // Parse Uniform Block members so that we can later on map a Parameter name to an actual |
431 | m_uniformsNames.reserve(n: m_uniformsNames.size() + ubo.members.size()); |
432 | m_uniformsNamesIds.reserve(n: m_uniformsNames.size()); |
433 | |
434 | std::vector<UBO_Member> uboMembers; |
435 | uboMembers.reserve(n: ubo.members.size()); |
436 | |
437 | for (const QShaderDescription::BlockVariable &member : std::as_const(t: ubo.members)) { |
438 | m_uniformsNames.push_back(x: member.name); |
439 | const int nameId = StringToInt::lookupId(str: member.name); |
440 | m_uniformsNamesIds.push_back(x: nameId); |
441 | |
442 | UBO_Member uboMember {.nameId: nameId, .blockVariable: member, .structMembers: {}}; |
443 | if (addUnqualifiedUniforms) |
444 | recordAllUniforms(uboMember, QStringLiteral("" )); |
445 | uboMembers.push_back(x: uboMember); |
446 | } |
447 | |
448 | m_uboBlocks.push_back(x: UBO_Block{ .block: uniformBlocks.back(), .members: uboMembers }); |
449 | } |
450 | |
451 | for (const QShaderDescription::StorageBlock &ssbo : rhiSSBO) { |
452 | storageBlocks.push_back(x: ShaderStorageBlock { .m_name: ssbo.blockName, .m_nameId: -1, .m_index: -1, .m_binding: ssbo.binding, .m_size: 0, .m_activeVariablesCount: 0 }); |
453 | } |
454 | |
455 | initializeAttributes(attributesDescription: attributes); |
456 | initializeUniformBlocks(uniformBlockDescription: uniformBlocks); |
457 | initializeShaderStorageBlocks(shaderStorageBlockDescription: storageBlocks); |
458 | initializeSamplers(samplerDescription: samplers); |
459 | initializeImages(imageDescription: images); |
460 | |
461 | qCDebug(Shaders) << "Block Names" << m_uniformBlockNames; |
462 | qCDebug(Shaders) << "Uniform Names" << m_uniformsNames; |
463 | qCDebug(Shaders) << "SSBO Names" << m_shaderStorageBlockNames; |
464 | qCDebug(Shaders) << "Attribute Names" << m_attributesNames; |
465 | |
466 | } |
467 | |
468 | QHash<QString, ShaderUniform> RHIShader::activeUniformsForUniformBlock(int blockIndex) const |
469 | { |
470 | return m_uniformBlockIndexToShaderUniforms.value(key: blockIndex); |
471 | } |
472 | |
473 | ShaderUniformBlock RHIShader::uniformBlockForBlockIndex(int blockIndex) const noexcept |
474 | { |
475 | for (size_t i = 0, m = m_uniformBlocks.size(); i < m; ++i) { |
476 | if (m_uniformBlocks[i].m_index == blockIndex) { |
477 | return m_uniformBlocks[i]; |
478 | } |
479 | } |
480 | return ShaderUniformBlock(); |
481 | } |
482 | |
483 | ShaderUniformBlock RHIShader::uniformBlockForBlockNameId(int blockNameId) const noexcept |
484 | { |
485 | for (size_t i = 0, m = m_uniformBlocks.size(); i < m; ++i) { |
486 | if (m_uniformBlocks[i].m_nameId == blockNameId) { |
487 | return m_uniformBlocks[i]; |
488 | } |
489 | } |
490 | return ShaderUniformBlock(); |
491 | } |
492 | |
493 | ShaderUniformBlock RHIShader::uniformBlockForBlockName(const QString &blockName) const noexcept |
494 | { |
495 | for (size_t i = 0, m = m_uniformBlocks.size(); i < m; ++i) { |
496 | if (m_uniformBlocks[i].m_name == blockName) { |
497 | return m_uniformBlocks[i]; |
498 | } |
499 | } |
500 | return ShaderUniformBlock(); |
501 | } |
502 | |
503 | ShaderUniformBlock RHIShader::uniformBlockForInstanceName(const QString &instanceName) const noexcept |
504 | { |
505 | return uniformBlockForInstanceNameId(instanceNameId: StringToInt::lookupId(str: instanceName)); |
506 | } |
507 | |
508 | ShaderUniformBlock RHIShader::uniformBlockForInstanceNameId(int instanceNameId) const noexcept |
509 | { |
510 | for (size_t i = 0, m = m_uboBlocks.size(); i < m; ++i) { |
511 | const UBO_Block &b = m_uboBlocks[i]; |
512 | for (const UBO_Member &member : b.members) { |
513 | if (member.nameId == instanceNameId) |
514 | return b.block; |
515 | } |
516 | } |
517 | return ShaderUniformBlock(); |
518 | } |
519 | |
520 | ShaderStorageBlock RHIShader::storageBlockForBlockIndex(int blockIndex) const noexcept |
521 | { |
522 | for (size_t i = 0, m = m_shaderStorageBlockNames.size(); i < m; ++i) { |
523 | if (m_shaderStorageBlocks[i].m_index == blockIndex) |
524 | return m_shaderStorageBlocks[i]; |
525 | } |
526 | return ShaderStorageBlock(); |
527 | } |
528 | |
529 | ShaderStorageBlock RHIShader::storageBlockForBlockNameId(int blockNameId) const noexcept |
530 | { |
531 | for (size_t i = 0, m = m_shaderStorageBlockNames.size(); i < m; ++i) { |
532 | if (m_shaderStorageBlocks[i].m_nameId == blockNameId) |
533 | return m_shaderStorageBlocks[i]; |
534 | } |
535 | return ShaderStorageBlock(); |
536 | } |
537 | |
538 | ShaderStorageBlock RHIShader::storageBlockForBlockName(const QString &blockName) const noexcept |
539 | { |
540 | for (size_t i = 0, m = m_shaderStorageBlockNames.size(); i < m; ++i) { |
541 | if (m_shaderStorageBlocks[i].m_name == blockName) |
542 | return m_shaderStorageBlocks[i]; |
543 | } |
544 | return ShaderStorageBlock(); |
545 | } |
546 | |
547 | RHIShader::ParameterKind RHIShader::categorizeVariable(int nameId) const noexcept |
548 | { |
549 | if (Qt3DCore::contains(destination: m_uniformBlockNamesIds, element: nameId)) |
550 | return ParameterKind::UBO; |
551 | else if (Qt3DCore::contains(destination: m_shaderStorageBlockNamesIds, element: nameId)) |
552 | return ParameterKind::SSBO; |
553 | else if (Qt3DCore::contains(destination: m_structNamesIds, element: nameId)) |
554 | return ParameterKind::Struct; |
555 | return ParameterKind::Uniform; |
556 | } |
557 | |
558 | bool RHIShader::hasUniform(int nameId) const noexcept |
559 | { |
560 | return Qt3DCore::contains(destination: m_uniformsNamesIds, element: nameId); |
561 | } |
562 | |
563 | bool RHIShader::hasActiveVariables() const noexcept |
564 | { |
565 | return !m_attributeNamesIds.empty() || !m_uniformsNamesIds.empty() |
566 | || !m_uniformBlockNamesIds.empty() || !m_shaderStorageBlockNamesIds.empty(); |
567 | } |
568 | |
569 | void RHIShader::setShaderCode(const std::vector<QByteArray> &shaderCode) |
570 | { |
571 | m_shaderCode.clear(); |
572 | Qt3DCore::append(destination&: m_shaderCode, source: shaderCode); |
573 | } |
574 | |
575 | void RHIShader::setFragOutputs(const QHash<QString, int> &fragOutputs) |
576 | { |
577 | { |
578 | QMutexLocker lock(&m_mutex); |
579 | m_fragOutputs = fragOutputs; |
580 | } |
581 | // updateDNA(); |
582 | } |
583 | |
584 | const QHash<QString, int> RHIShader::fragOutputs() const |
585 | { |
586 | QMutexLocker lock(&m_mutex); |
587 | return m_fragOutputs; |
588 | } |
589 | |
590 | void RHIShader::initializeAttributes(const std::vector<ShaderAttribute> &attributesDescription) |
591 | { |
592 | m_attributes = attributesDescription; |
593 | m_attributesNames.resize(new_size: attributesDescription.size()); |
594 | m_attributeNamesIds.resize(new_size: attributesDescription.size()); |
595 | for (size_t i = 0, m = attributesDescription.size(); i < m; i++) { |
596 | m_attributesNames[i] = attributesDescription[i].m_name; |
597 | m_attributes[i].m_nameId = StringToInt::lookupId(str: m_attributesNames[i]); |
598 | m_attributeNamesIds[i] = m_attributes[i].m_nameId; |
599 | qCDebug(Shaders) << "Active Attribute " << attributesDescription[i].m_name; |
600 | } |
601 | } |
602 | |
603 | void RHIShader::initializeSamplers(const std::vector<ShaderAttribute> &samplersDescription) |
604 | { |
605 | m_samplers = samplersDescription; |
606 | m_samplerNames.resize(new_size: samplersDescription.size()); |
607 | m_samplerIds.resize(new_size: samplersDescription.size()); |
608 | for (size_t i = 0, m = samplersDescription.size(); i < m; i++) { |
609 | m_samplerNames[i] = samplersDescription[i].m_name; |
610 | m_samplers[i].m_nameId = StringToInt::lookupId(str: m_samplerNames[i]); |
611 | m_samplerIds[i] = m_samplers[i].m_nameId; |
612 | qCDebug(Shaders) << "Active sampler " << samplersDescription[i].m_name; |
613 | } |
614 | } |
615 | |
616 | void RHIShader::initializeImages(const std::vector<ShaderAttribute> &imagesDescription) |
617 | { |
618 | m_images = imagesDescription; |
619 | m_imageNames.resize(new_size: imagesDescription.size()); |
620 | m_imageIds.resize(new_size: imagesDescription.size()); |
621 | for (size_t i = 0, m = imagesDescription.size(); i < m; i++) { |
622 | m_imageNames[i] = imagesDescription[i].m_name; |
623 | m_images[i].m_nameId = StringToInt::lookupId(str: m_imageNames[i]); |
624 | m_imageIds[i] = m_images[i].m_nameId; |
625 | qCDebug(Shaders) << "Active image " << imagesDescription[i].m_name; |
626 | } |
627 | } |
628 | |
629 | void RHIShader::initializeUniformBlocks(const std::vector<ShaderUniformBlock> &uniformBlockDescription) |
630 | { |
631 | m_uniformBlocks = uniformBlockDescription; |
632 | m_uniformBlockNames.resize(new_size: uniformBlockDescription.size()); |
633 | m_uniformBlockNamesIds.resize(new_size: uniformBlockDescription.size()); |
634 | for (size_t i = 0, m = uniformBlockDescription.size(); i < m; ++i) { |
635 | m_uniformBlockNames[i] = m_uniformBlocks[i].m_name; |
636 | m_uniformBlockNamesIds[i] = StringToInt::lookupId(str: m_uniformBlockNames[i]); |
637 | m_uniformBlocks[i].m_nameId = m_uniformBlockNamesIds[i]; |
638 | qCDebug(Shaders) << "Initializing Uniform Block {" << m_uniformBlockNames[i] << "}" ; |
639 | |
640 | // Find all active uniforms for the shader block |
641 | std::vector<ShaderUniform>::const_iterator uniformsIt = m_uniforms.cbegin(); |
642 | const std::vector<ShaderUniform>::const_iterator uniformsEnd = m_uniforms.cend(); |
643 | |
644 | std::vector<QString>::const_iterator uniformNamesIt = m_uniformsNames.cbegin(); |
645 | const std::vector<QString>::const_iterator uniformNamesEnd = m_uniformsNames.cend(); |
646 | |
647 | QHash<QString, ShaderUniform> activeUniformsInBlock; |
648 | |
649 | while (uniformsIt != uniformsEnd && uniformNamesIt != uniformNamesEnd) { |
650 | if (uniformsIt->m_blockIndex == uniformBlockDescription[i].m_index) { |
651 | QString uniformName = *uniformNamesIt; |
652 | if (!m_uniformBlockNames[i].isEmpty() |
653 | && !uniformName.startsWith(s: m_uniformBlockNames[i])) |
654 | uniformName = m_uniformBlockNames[i] + QLatin1Char('.') + *uniformNamesIt; |
655 | activeUniformsInBlock.insert(key: uniformName, value: *uniformsIt); |
656 | qCDebug(Shaders) << "Active Uniform Block " << uniformName << " in block " |
657 | << m_uniformBlockNames[i] << " at index " |
658 | << uniformsIt->m_blockIndex; |
659 | } |
660 | ++uniformsIt; |
661 | ++uniformNamesIt; |
662 | } |
663 | m_uniformBlockIndexToShaderUniforms.insert(key: uniformBlockDescription[i].m_index, |
664 | value: activeUniformsInBlock); |
665 | } |
666 | } |
667 | |
668 | void RHIShader::initializeShaderStorageBlocks( |
669 | const std::vector<ShaderStorageBlock> &shaderStorageBlockDescription) |
670 | { |
671 | m_shaderStorageBlocks = shaderStorageBlockDescription; |
672 | m_shaderStorageBlockNames.resize(new_size: shaderStorageBlockDescription.size()); |
673 | m_shaderStorageBlockNamesIds.resize(new_size: shaderStorageBlockDescription.size()); |
674 | |
675 | for (size_t i = 0, m = shaderStorageBlockDescription.size(); i < m; ++i) { |
676 | m_shaderStorageBlockNames[i] = m_shaderStorageBlocks[i].m_name; |
677 | m_shaderStorageBlockNamesIds[i] = StringToInt::lookupId(str: m_shaderStorageBlockNames[i]); |
678 | m_shaderStorageBlocks[i].m_nameId = m_shaderStorageBlockNamesIds[i]; |
679 | qCDebug(Shaders) << "Initializing Shader Storage Block {" << m_shaderStorageBlockNames[i] |
680 | << "}" ; |
681 | } |
682 | } |
683 | |
684 | } // Rhi |
685 | |
686 | } // Render |
687 | |
688 | } // Qt3DRender |
689 | |
690 | QT_END_NAMESPACE |
691 | |