65 int jsonStart = 0, jsonEnd = 0;
74 if (jsonStart <= 0 || jsonEnd <= 0)
77 const int size = jsonEnd - jsonStart;
80 qWarning(
"Shader metadata section found, but content to small to be valid!");
84 QByteArray jsonData = data.mid(jsonStart, size).trimmed();
85 if (!jsonData.startsWith(QByteArrayLiteral(
"/*{"))) {
86 qWarning(
"Missing /*{ prefix");
89 if (!jsonData.endsWith(QByteArrayLiteral(
"}*/"))) {
90 qWarning(
"Missing }*/ suffix");
93 jsonData = jsonData.mid(2, jsonData.size() - 4);
95 QJsonParseError error;
96 const auto doc = QJsonDocument::fromJson(jsonData, &error);
97 if (error.error != QJsonParseError::NoError) {
98 qWarning() <<
"Shader metadata parse error at offset: " << error.offset;
102 static const auto toUniform = [](
const QJsonObject &uObj) {
104 auto it = uObj.constBegin();
105 const auto end = uObj.constEnd();
107 it = uObj.constFind(QLatin1String(
"type"));
108 uniform.type = (it != end) ? it->toString().toLatin1() : QByteArray();
109 it = uObj.constFind(QLatin1String(
"name"));
110 uniform.name = (it != end) ? it->toString().toLatin1() : QByteArray();
111 it = uObj.constFind(QLatin1String(
"multiview_dependent"));
112 uniform
.multiview = (it != end) ? it->toBool() :
false;
114 it = uObj.constFind(QLatin1String(
"condition"));
115 const QString conditionString = (it != end) ? it->toString() : QString();
116 uniform
.condition = Uniform::conditionFromString(conditionString);
118 uniform.conditionName = conditionString.mid(1).toLatin1();
120 uniform.conditionName = conditionString.toLatin1();
125 static const auto toImage = [](
const QJsonObject &uObj,
const Uniform &uniform)
128 auto it = uObj.constBegin();
129 const auto end = uObj.constEnd();
131 it = uObj.constFind(QLatin1String(
"imgtype"));
132 img.imageType = (it != end) ? it->toString().toLatin1() : QByteArray();
133 it = uObj.constFind(QLatin1String(
"qualifiers"));
134 QByteArray qualifiers = (it != end) ? it->toString().toLatin1() : QByteArray();
135 if (!qualifiers.isEmpty()) {
136 if (!QSSGBaseTypeHelpers::parseMemoryQualifiers(qualifiers, img.qualifiers))
137 qWarning(
"Invalid qualifiers %s for image %s", qualifiers.constData(), uniform.name.constData());
142 static const auto toBuffer = [](
const QJsonObject &uObj,
const Uniform &uniform)
145 auto it = uObj.constBegin();
146 const auto end = uObj.constEnd();
148 it = uObj.constFind(QLatin1String(
"contentType"));
149 buf.contentType = (it != end) ? it->toString().toLatin1() : QByteArray();
150 it = uObj.constFind(QLatin1String(
"qualifiers"));
151 QByteArray qualifiers = (it != end) ? it->toString().toLatin1() : QByteArray();
152 if (!qualifiers.isEmpty()) {
153 if (!QSSGBaseTypeHelpers::parseMemoryQualifiers(qualifiers, buf.qualifiers))
154 qWarning(
"Invalid qualifiers %s for buffer %s", qualifiers.constData(), uniform.name.constData());
160 static const auto toInputOutput = [](
const QJsonObject &uObj) {
162 auto it = uObj.constBegin();
163 const auto end = uObj.constEnd();
165 it = uObj.constFind(QLatin1String(
"type"));
166 inOutVar.type = (it != end) ? it->toString().toLatin1() : QByteArray();
167 it = uObj.constFind(QLatin1String(
"name"));
168 inOutVar.name = (it != end) ? it->toString().toLatin1() : QByteArray();
169 it = uObj.constFind(QLatin1String(
"stage"));
170 inOutVar.stage = InputOutput::stageFromString((it != end) ? it->toString() : QString());
171 it = uObj.constFind(QLatin1String(
"flat"));
172 inOutVar
.flat = (it != end) ? it->toBool() :
false;
177 const auto addUniformEntry = [&result](
const QJsonObject &uObj) {
178 const auto uniform = toUniform(uObj);
179 if (uniform.type.isEmpty() || uniform.name.isEmpty()) {
180 qWarning(
"Invalid uniform, skipping");
183 if (uObj.constFind(QLatin1String(
"imgtype")) != uObj.constEnd()) {
184 Image img(toImage(uObj, uniform));
185 if (img.imageType.isEmpty()) {
186 qWarning(
"Image type missing for image %s, skipping", img.name.constData());
189 result.images.push_back(img);
190 }
else if (uniform.type ==
"buffer") {
191 Buffer buf(toBuffer(uObj, uniform));
192 if (buf.contentType.isEmpty()) {
193 qWarning(
"Content type missing for buffer %s, skipping", buf.name.constData());
196 result.buffers.push_back(buf);
198 result.uniforms.push_back(uniform);
202 const QJsonObject obj = doc.object();
203 auto it = obj.constBegin();
204 const auto end = obj.constEnd();
207 it = obj.constFind(QLatin1String(
"uniforms"));
208 if (it != obj.constEnd()) {
210 if (it->type() == QJsonValue::Array) {
211 for (
const auto valueRef : it->toArray()) {
212 if (valueRef.isObject())
213 addUniformEntry(valueRef.toObject());
215 }
else if (it->type() == QJsonValue::Object) {
216 addUniformEntry(it->toObject());
221 it = obj.constFind(QLatin1String(
"inputs"));
223 if (it->type() == QJsonValue::Array) {
224 const auto array = it->toArray();
225 for (
const auto &valueRef : array) {
226 if (!valueRef.isObject())
228 const auto inOutVar = toInputOutput(valueRef.toObject());
229 if (!inOutVar.type.isEmpty() && !inOutVar.name.isEmpty())
230 result.inputs.push_back(inOutVar);
232 qWarning(
"Invalid input variable, skipping");
234 }
else if (it->type() == QJsonValue::Object) {
235 const QJsonObject obj = it->toObject();
236 const auto inOutVar = toInputOutput(obj);
237 if (!inOutVar.type.isEmpty() && !inOutVar.name.isEmpty()) {
238 result.inputs.push_back(inOutVar);
240 qWarning(
"Invalid input variable, skipping");
246 it = obj.constFind(QLatin1String(
"outputs"));
248 if (it->type() == QJsonValue::Array) {
249 const auto array = it->toArray();
250 for (
const auto &valueRef : array) {
251 if (!valueRef.isObject())
253 const auto inOutVar = toInputOutput(valueRef.toObject());
254 if (!inOutVar.type.isEmpty() && !inOutVar.name.isEmpty())
255 result.outputs.push_back(inOutVar);
257 qWarning(
"Invalid output variable, skipping");
259 }
else if (it->type() == QJsonValue::Object) {
260 const QJsonObject inputJObj = it->toObject();
261 const auto inOutVar = toInputOutput(inputJObj);
262 if (!inOutVar.type.isEmpty() && !inOutVar.name.isEmpty()) {
263 result.outputs.push_back(inOutVar);
265 qWarning(
"Invalid output variable, skipping");