Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qssgrenderuserpass.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5
7#include <QtQuick3DRuntimeRender/private/qssgrendercommands_p.h>
8
9#include <QtCore/qregularexpression.h>
10#include <QtCore/qcryptographichash.h>
11
12#include <ssg/qssgrendercontextcore.h>
13
15
16Q_STATIC_LOGGING_CATEGORY(lcRenderUserPass, "qt.quick3d.runtimerender.renderuserpass")
17
18static const QHash<const char*, const char*> AugmentMacros = {
19 { "BASE_COLOR", "qt_diffuseColor" },
20 { "ROUGHNESS", "qt_roughnessAmount" },
21 { "METALNESS", "qt_metalnessAmount" },
22 { "DIFFUSE_LIGHT", "global_diffuse_light.rgb" },
23 { "SPECULAR_LIGHT", "global_specular_light" },
24 { "EMISSIVE_LIGHT", "global_emission" },
25 { "WORLD_NORMAL", "qt_world_normal" },
26 { "WORLD_TANGENT", "qt_tangent" },
27 { "WORLD_BINORMAL", "qt_binormal" },
28 { "F0", "qt_f0" },
29 { "F90", "qt_f90" }
30};
31
32// NOTE: While this class doesn't have graphics resources itself, it manages commands that do!
33QSSGRenderUserPass::QSSGRenderUserPass()
34 : QSSGRenderGraphObject(Type::RenderPass, FlagT(Flags::HasGraphicsResources))
35{
36
37}
38
39QSSGRenderUserPass::~QSSGRenderUserPass()
40{
41 resetCommands();
42}
43
44bool QSSGRenderUserPass::isDirty(DirtyFlag flag) const
45{
46 return (flags & FlagT(flag)) != 0;
47}
48
49void QSSGRenderUserPass::markDirty(DirtyFlag flag)
50{
51 flags |= FlagT(flag);
52}
53
54void QSSGRenderUserPass::clearDirty(DirtyFlag flag)
55{
56 flags &= ~FlagT(flag);
57}
58
59QByteArray replaceAugmentMacros(const QByteArray &shaderCode)
60{
61 QString modifiedCode = QString::fromUtf8(shaderCode);
62 for (auto it = AugmentMacros.constBegin(); it != AugmentMacros.constEnd(); ++it) {
63 QString pattern = QStringLiteral("\\b%1\\b").arg(QRegularExpression::escape(QString::fromUtf8(it.key())));
64 QRegularExpression regex(pattern);
65 modifiedCode.replace(regex, QString::fromUtf8(it.value()));
66 }
67 return modifiedCode.toUtf8();
68}
69
70void QSSGRenderUserPass::finalizeShaders(const QSSGRenderContextInterface &ctx)
71{
72 Q_UNUSED(ctx);
73
74 if (materialMode != AugmentMaterial)
75 return;
76
77 if (!isDirty(DirtyFlag::ShaderDirty))
78 return;
79
80 clearDirty(DirtyFlag::ShaderDirty);
81
82 const bool hasShaderCode = (shaderAugmentation.hasUserAugmentation());
83
84 if (hasShaderCode) {
85 qCDebug(lcRenderUserPass) << "Finalizing shaders for user pass with augment shader code.";
86
87 // Replace any instances of the AugmentMacros with the appropriate built-in variable names
88 shaderAugmentation.preamble = replaceAugmentMacros(shaderAugmentation.preamble);
89 shaderAugmentation.body = replaceAugmentMacros(shaderAugmentation.body);
90 // Used to build the unique shader cache key. The shader key goes in the generated
91 // shader as a one line comment so it can't be multiline. Generate hash from the
92 // augmented shader preamble and body instead, which gets combined with the material key.
93 const QByteArray fullAugmentation = shaderAugmentation.preamble + shaderAugmentation.body;
94 shaderAugmentation.hash = QCryptographicHash::hash(QByteArrayView(fullAugmentation),
95 QCryptographicHash::Algorithm::Sha1).toHex();
96
97 // Check if body needs certain features
98 shaderAugmentation.needsBaseColor = shaderAugmentation.body.contains(AugmentMacros["BASE_COLOR"]);
99 shaderAugmentation.needsRoughness = shaderAugmentation.body.contains(AugmentMacros["ROUGHNESS"]);
100 shaderAugmentation.needsMetalness = shaderAugmentation.body.contains(AugmentMacros["METALNESS"]);
101 shaderAugmentation.needsDiffuseLight = shaderAugmentation.body.contains(AugmentMacros["DIFFUSE_LIGHT"]);
102 shaderAugmentation.needsSpecularLight = shaderAugmentation.body.contains(AugmentMacros["SPECULAR_LIGHT"]);
103 shaderAugmentation.needsEmissiveLight = shaderAugmentation.body.contains(AugmentMacros["EMISSIVE_LIGHT"]);
104 shaderAugmentation.needsWorldNormal = shaderAugmentation.body.contains(AugmentMacros["WORLD_NORMAL"]);
105 shaderAugmentation.needsWorldTangent = shaderAugmentation.body.contains(AugmentMacros["WORLD_TANGENT"]);
106 shaderAugmentation.needsWorldBinormal = shaderAugmentation.body.contains(AugmentMacros["WORLD_BINORMAL"]);
107 shaderAugmentation.needsF0 = shaderAugmentation.body.contains(AugmentMacros["F0"]);
108 shaderAugmentation.needsF90 = shaderAugmentation.body.contains(AugmentMacros["F90"]);
109
110 m_state = State::Ready;
111
112 } else {
113 m_state = State::Error;
114
115 qWarning() << "No augment shader code provided for user pass.";
116 }
117
118 // Finalize shaders for all commands
119 qCDebug(lcRenderUserPass) << "Finalizing shaders for user pass commands";
120}
121
122void QSSGRenderUserPass::resetCommands()
123{
124 qDeleteAll(commands);
125 commands.clear();
126}
127
128QT_END_NAMESPACE
Combined button and popup list for selecting options.
QByteArray replaceAugmentMacros(const QByteArray &shaderCode)