| 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(std::vector<QByteArray> shaderCode) |
| 570 | { |
| 571 | m_shaderCode = std::move(shaderCode); |
| 572 | } |
| 573 | |
| 574 | void RHIShader::setFragOutputs(QHash<QString, int> fragOutputs) |
| 575 | { |
| 576 | { |
| 577 | QMutexLocker lock(&m_mutex); |
| 578 | m_fragOutputs = std::move(fragOutputs); |
| 579 | } |
| 580 | // updateDNA(); |
| 581 | } |
| 582 | |
| 583 | const QHash<QString, int> &RHIShader::fragOutputs() const |
| 584 | { |
| 585 | QMutexLocker lock(&m_mutex); |
| 586 | return m_fragOutputs; |
| 587 | } |
| 588 | |
| 589 | void RHIShader::initializeAttributes(std::vector<ShaderAttribute> attributesDescription) |
| 590 | { |
| 591 | m_attributes = std::move(attributesDescription); |
| 592 | m_attributesNames.resize(new_size: m_attributes.size()); |
| 593 | m_attributeNamesIds.resize(new_size: m_attributes.size()); |
| 594 | for (size_t i = 0, m = m_attributes.size(); i < m; i++) { |
| 595 | m_attributesNames[i] = m_attributes[i].m_name; |
| 596 | m_attributes[i].m_nameId = StringToInt::lookupId(str: m_attributesNames[i]); |
| 597 | m_attributeNamesIds[i] = m_attributes[i].m_nameId; |
| 598 | qCDebug(Shaders) << "Active Attribute " << m_attributes[i].m_name; |
| 599 | } |
| 600 | } |
| 601 | |
| 602 | void RHIShader::initializeSamplers(std::vector<ShaderAttribute> samplersDescription) |
| 603 | { |
| 604 | m_samplers = std::move(samplersDescription); |
| 605 | m_samplerNames.resize(new_size: m_samplers.size()); |
| 606 | m_samplerIds.resize(new_size: m_samplers.size()); |
| 607 | for (size_t i = 0, m = m_samplers.size(); i < m; i++) { |
| 608 | m_samplerNames[i] = m_samplers[i].m_name; |
| 609 | m_samplers[i].m_nameId = StringToInt::lookupId(str: m_samplerNames[i]); |
| 610 | m_samplerIds[i] = m_samplers[i].m_nameId; |
| 611 | qCDebug(Shaders) << "Active sampler " << m_samplers[i].m_name; |
| 612 | } |
| 613 | } |
| 614 | |
| 615 | void RHIShader::initializeImages(std::vector<ShaderAttribute> imagesDescription) |
| 616 | { |
| 617 | m_images = std::move(imagesDescription); |
| 618 | m_imageNames.resize(new_size: m_images.size()); |
| 619 | m_imageIds.resize(new_size: m_images.size()); |
| 620 | for (size_t i = 0, m = m_images.size(); i < m; i++) { |
| 621 | m_imageNames[i] = m_images[i].m_name; |
| 622 | m_images[i].m_nameId = StringToInt::lookupId(str: m_imageNames[i]); |
| 623 | m_imageIds[i] = m_images[i].m_nameId; |
| 624 | qCDebug(Shaders) << "Active image " << m_images[i].m_name; |
| 625 | } |
| 626 | } |
| 627 | |
| 628 | void RHIShader::initializeUniformBlocks(std::vector<ShaderUniformBlock> uniformBlockDescription) |
| 629 | { |
| 630 | m_uniformBlocks = std::move(uniformBlockDescription); |
| 631 | m_uniformBlockNames.resize(new_size: m_uniformBlocks.size()); |
| 632 | m_uniformBlockNamesIds.resize(new_size: m_uniformBlocks.size()); |
| 633 | for (size_t i = 0, m = m_uniformBlocks.size(); i < m; ++i) { |
| 634 | m_uniformBlockNames[i] = m_uniformBlocks[i].m_name; |
| 635 | m_uniformBlockNamesIds[i] = StringToInt::lookupId(str: m_uniformBlockNames[i]); |
| 636 | m_uniformBlocks[i].m_nameId = m_uniformBlockNamesIds[i]; |
| 637 | qCDebug(Shaders) << "Initializing Uniform Block {" << m_uniformBlockNames[i] << "}" ; |
| 638 | |
| 639 | // Find all active uniforms for the shader block |
| 640 | std::vector<ShaderUniform>::const_iterator uniformsIt = m_uniforms.cbegin(); |
| 641 | const std::vector<ShaderUniform>::const_iterator uniformsEnd = m_uniforms.cend(); |
| 642 | |
| 643 | std::vector<QString>::const_iterator uniformNamesIt = m_uniformsNames.cbegin(); |
| 644 | const std::vector<QString>::const_iterator uniformNamesEnd = m_uniformsNames.cend(); |
| 645 | |
| 646 | QHash<QString, ShaderUniform> activeUniformsInBlock; |
| 647 | |
| 648 | while (uniformsIt != uniformsEnd && uniformNamesIt != uniformNamesEnd) { |
| 649 | if (uniformsIt->m_blockIndex == m_uniformBlocks[i].m_index) { |
| 650 | QString uniformName = *uniformNamesIt; |
| 651 | if (!m_uniformBlockNames[i].isEmpty() |
| 652 | && !uniformName.startsWith(s: m_uniformBlockNames[i])) |
| 653 | uniformName = m_uniformBlockNames[i] + QLatin1Char('.') + *uniformNamesIt; |
| 654 | activeUniformsInBlock.insert(key: uniformName, value: *uniformsIt); |
| 655 | qCDebug(Shaders) << "Active Uniform Block " << uniformName << " in block " |
| 656 | << m_uniformBlockNames[i] << " at index " |
| 657 | << uniformsIt->m_blockIndex; |
| 658 | } |
| 659 | ++uniformsIt; |
| 660 | ++uniformNamesIt; |
| 661 | } |
| 662 | m_uniformBlockIndexToShaderUniforms.insert(key: m_uniformBlocks[i].m_index, |
| 663 | value: activeUniformsInBlock); |
| 664 | } |
| 665 | } |
| 666 | |
| 667 | void RHIShader::initializeShaderStorageBlocks( |
| 668 | std::vector<ShaderStorageBlock> shaderStorageBlockDescription) |
| 669 | { |
| 670 | m_shaderStorageBlocks = std::move(shaderStorageBlockDescription); |
| 671 | m_shaderStorageBlockNames.resize(new_size: m_shaderStorageBlocks.size()); |
| 672 | m_shaderStorageBlockNamesIds.resize(new_size: m_shaderStorageBlocks.size()); |
| 673 | |
| 674 | for (size_t i = 0, m = m_shaderStorageBlocks.size(); i < m; ++i) { |
| 675 | m_shaderStorageBlockNames[i] = m_shaderStorageBlocks[i].m_name; |
| 676 | m_shaderStorageBlockNamesIds[i] = StringToInt::lookupId(str: m_shaderStorageBlockNames[i]); |
| 677 | m_shaderStorageBlocks[i].m_nameId = m_shaderStorageBlockNamesIds[i]; |
| 678 | qCDebug(Shaders) << "Initializing Shader Storage Block {" << m_shaderStorageBlockNames[i] |
| 679 | << "}" ; |
| 680 | } |
| 681 | } |
| 682 | |
| 683 | } // Rhi |
| 684 | |
| 685 | } // Render |
| 686 | |
| 687 | } // Qt3DRender |
| 688 | |
| 689 | QT_END_NAMESPACE |
| 690 | |