Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qssgrendershadermetadata.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5
6#include <QPair>
7#include <QJsonDocument>
8#include <QJsonArray>
9#include <QJsonObject>
10#include <QJsonValue>
11
12#include <QtDebug>
13
14// Example snippet based on viewProperties.glsllib
15// The comment in the ifdefed block is necessary to keep weird shader compilers (Vivante) happy.
16
17// #ifdef QQ3D_SHADER_META
18// /*{
19// "uniforms": [ { "type": "mat44", "name": "qt_viewProjectionMatrix" },
20// { "type": "mat4", "name": "qt_viewMatrix" },
21// { "type": "vec2", "name": "qt_cameraProperties" },
22// { "type": "vec3", "name": "qt_cameraPosition", "condition": "!SSAO_CUSTOM_MATERIAL_GLSLLIB" }
23// ]
24// }*/
25// #endif // QQ3D_SHADER_META
26
28
29const char *shaderMetaStart() { return "#ifdef QQ3D_SHADER_META"; }
30const char *shaderMetaEnd() { return "#endif"; }
31
33{
34 if (condition.isEmpty())
36
37 if (condition.at(0) == QChar::fromLatin1('!'))
38 return Uniform::Negated;
39
40 return Uniform::Regular;
41}
42
44{
45 if (stage == QLatin1String("vertex")) {
47 } else if (stage == QLatin1String("fragment"))
49 else {
50 qWarning("Unknown stage in shader metadata: %s, assuming vertex", qPrintable(stage));
52 }
53}
54
56{
58 if (data.isEmpty())
59 return result;
60
61 int jsonStart = 0, jsonEnd = 0;
62 for ( ; ; ) {
63 jsonStart = data.indexOf(shaderMetaStart(), jsonEnd);
64 if (jsonStart)
65 jsonEnd = data.indexOf(shaderMetaEnd(), jsonStart);
66
67 if (jsonEnd) // adjust start position
68 jsonStart += int(strlen(shaderMetaStart()));
69
70 if (jsonStart <= 0 || jsonEnd <= 0)
71 break;
72
73 const int size = jsonEnd - jsonStart;
74 // /*{"inputs":[]}*/ => 17
75 if (size < 17) {
76 qWarning("Shader metadata section found, but content to small to be valid!");
77 break;
78 }
79
80 QByteArray jsonData = data.mid(jsonStart, size).trimmed();
81 if (!jsonData.startsWith(QByteArrayLiteral("/*{"))) {
82 qWarning("Missing /*{ prefix");
83 break;
84 }
85 if (!jsonData.endsWith(QByteArrayLiteral("}*/"))) {
86 qWarning("Missing }*/ suffix");
87 break;
88 }
89 jsonData = jsonData.mid(2, jsonData.size() - 4);
90
92 const auto doc = QJsonDocument::fromJson(jsonData, &error);
93 if (error.error != QJsonParseError::NoError) {
94 qWarning() << "Shader metadata parse error at offset: " << error.offset;
95 break;
96 }
97
98 static const auto toUniform = [](const QJsonObject &uObj) {
99 Uniform uniform;
100 auto it = uObj.constBegin();
101 const auto end = uObj.constEnd();
102 if (it != end) {
103 it = uObj.constFind(QLatin1String("type"));
104 uniform.type = (it != end) ? it->toString().toLatin1() : QByteArray();
105 it = uObj.constFind(QLatin1String("name"));
106 uniform.name = (it != end) ? it->toString().toLatin1() : QByteArray();
107
108 it = uObj.constFind(QLatin1String("condition"));
109 const QString conditionString = (it != end) ? it->toString() : QString();
110 uniform.condition = Uniform::conditionFromString(conditionString);
111 if (uniform.condition == Uniform::Negated)
112 uniform.conditionName = conditionString.mid(1).toLatin1();
113 else if (uniform.condition == Uniform::Regular)
114 uniform.conditionName = conditionString.toLatin1();
115 }
116 return uniform;
117 };
118
119 static const auto toInputOutput = [](const QJsonObject &uObj) {
120 InputOutput inOutVar;
121 auto it = uObj.constBegin();
122 const auto end = uObj.constEnd();
123 if (it != end) {
124 it = uObj.constFind(QLatin1String("type"));
125 inOutVar.type = (it != end) ? it->toString().toLatin1() : QByteArray();
126 it = uObj.constFind(QLatin1String("name"));
127 inOutVar.name = (it != end) ? it->toString().toLatin1() : QByteArray();
128 it = uObj.constFind(QLatin1String("stage"));
129 inOutVar.stage = InputOutput::stageFromString((it != end) ? it->toString() : QString());
130 }
131 return inOutVar;
132 };
133
134 const QJsonObject obj = doc.object();
135 auto it = obj.constBegin();
136 const auto end = obj.constEnd();
137 if (it != end) {
138 // Uniforms
139 it = obj.constFind(QLatin1String("uniforms"));
140 if (it != obj.constEnd()) {
141 // Check if it's an array or a single object
142 if (it->type() == QJsonValue::Array) {
143 const auto uniformArray = it->toArray();
144 for (const auto valueRef : uniformArray) {
145 if (!valueRef.isObject())
146 continue;
147
148 const QJsonObject obj = valueRef.toObject();
149 const auto uniform = toUniform(obj);
150 if (!uniform.type.isEmpty() && !uniform.name.isEmpty()) {
151 result.uniforms.push_back(uniform);
152 } else {
153 qWarning("Invalid uniform, skipping");
154 }
155 }
156 } else if (it->type() == QJsonValue::Object) {
157 const auto uniform = toUniform(it->toObject());
158 if (!uniform.type.isEmpty() && !uniform.name.isEmpty())
159 result.uniforms.push_back(uniform);
160 else
161 qWarning("Invalid uniform, skipping");
162 }
163 }
164
165 // Inputs
166 it = obj.constFind(QLatin1String("inputs"));
167 if (it != end) {
168 if (it->type() == QJsonValue::Array) {
169 for (const auto valueRef : it->toArray()) {
170 if (!valueRef.isObject())
171 continue;
172 const auto inOutVar = toInputOutput(valueRef.toObject());
173 if (!inOutVar.type.isEmpty() && !inOutVar.name.isEmpty())
174 result.inputs.push_back(inOutVar);
175 else
176 qWarning("Invalid input variable, skipping");
177 }
178 } else if (it->type() == QJsonValue::Object) {
179 const QJsonObject obj = it->toObject();
180 const auto inOutVar = toInputOutput(obj);
181 if (!inOutVar.type.isEmpty() && !inOutVar.name.isEmpty()) {
182 result.inputs.push_back(inOutVar);
183 } else {
184 qWarning("Invalid input variable, skipping");
185 }
186 }
187 }
188
189 // Outputs
190 it = obj.constFind(QLatin1String("outputs"));
191 if (it != end) {
192 if (it->type() == QJsonValue::Array) {
193 for (const auto valueRef : it->toArray()) {
194 if (!valueRef.isObject())
195 continue;
196 const auto inOutVar = toInputOutput(valueRef.toObject());
197 if (!inOutVar.type.isEmpty() && !inOutVar.name.isEmpty())
198 result.outputs.push_back(inOutVar);
199 else
200 qWarning("Invalid output variable, skipping");
201 }
202 } else if (it->type() == QJsonValue::Object) {
203 const QJsonObject inputJObj = it->toObject();
204 const auto inOutVar = toInputOutput(inputJObj);
205 if (!inOutVar.type.isEmpty() && !inOutVar.name.isEmpty()) {
206 result.outputs.push_back(inOutVar);
207 } else {
208 qWarning("Invalid output variable, skipping");
209 }
210 }
211 }
212 }
213 }
214
215 return result;
216}
217
218} // namespace
\inmodule QtCore
Definition qbytearray.h:57
QByteArray trimmed() const &
Definition qbytearray.h:198
bool endsWith(char c) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qbytearray.h:174
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
bool startsWith(QByteArrayView bv) const
Definition qbytearray.h:170
QByteArray mid(qsizetype index, qsizetype len=-1) const
Returns a byte array containing len bytes from this byte array, starting at position pos.
static constexpr QChar fromLatin1(char c) noexcept
Converts the Latin-1 character c to its equivalent QChar.
Definition qchar.h:461
static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error=nullptr)
Parses json as a UTF-8 encoded JSON document, and creates a QJsonDocument from it.
\inmodule QtCore\reentrant
Definition qjsonobject.h:20
const_iterator constBegin() const noexcept
Definition qset.h:139
const_iterator constEnd() const noexcept
Definition qset.h:143
const_iterator constFind(const T &value) const
Definition qset.h:161
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QByteArray toLatin1() const &
Definition qstring.h:559
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
QSet< QString >::iterator it
ShaderMetaData getShaderMetaData(const QByteArray &data)
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
DBusConnection const char DBusError * error
#define qWarning
Definition qlogging.h:162
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum condition
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLhandleARB obj
[2]
GLuint64EXT * result
[6]
#define qPrintable(string)
Definition qstring.h:1391
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
\inmodule QtCore\reentrant
static QSSGShaderGeneratorStage stageFromString(const QString &stage)
static Condition conditionFromString(const QString &condition)