Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
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 it = uObj.constFind(QLatin1String("multiview_dependent"));
108 uniform.multiview = (it != end) ? it->toBool() : false;
109
110 it = uObj.constFind(QLatin1String("condition"));
111 const QString conditionString = (it != end) ? it->toString() : QString();
112 uniform.condition = Uniform::conditionFromString(conditionString);
113 if (uniform.condition == Uniform::Negated)
114 uniform.conditionName = conditionString.mid(1).toLatin1();
115 else if (uniform.condition == Uniform::Regular)
116 uniform.conditionName = conditionString.toLatin1();
117 }
118 return uniform;
119 };
120
121 static const auto toInputOutput = [](const QJsonObject &uObj) {
122 InputOutput inOutVar;
123 auto it = uObj.constBegin();
124 const auto end = uObj.constEnd();
125 if (it != end) {
126 it = uObj.constFind(QLatin1String("type"));
127 inOutVar.type = (it != end) ? it->toString().toLatin1() : QByteArray();
128 it = uObj.constFind(QLatin1String("name"));
129 inOutVar.name = (it != end) ? it->toString().toLatin1() : QByteArray();
130 it = uObj.constFind(QLatin1String("stage"));
131 inOutVar.stage = InputOutput::stageFromString((it != end) ? it->toString() : QString());
132 it = uObj.constFind(QLatin1String("flat"));
133 inOutVar.flat = (it != end) ? it->toBool() : false;
134 }
135 return inOutVar;
136 };
137
138 const QJsonObject obj = doc.object();
139 auto it = obj.constBegin();
140 const auto end = obj.constEnd();
141 if (it != end) {
142 // Uniforms
143 it = obj.constFind(QLatin1String("uniforms"));
144 if (it != obj.constEnd()) {
145 // Check if it's an array or a single object
146 if (it->type() == QJsonValue::Array) {
147 const auto uniformArray = it->toArray();
148 for (const auto valueRef : uniformArray) {
149 if (!valueRef.isObject())
150 continue;
151
152 const QJsonObject obj = valueRef.toObject();
153 const auto uniform = toUniform(obj);
154 if (!uniform.type.isEmpty() && !uniform.name.isEmpty()) {
155 result.uniforms.push_back(uniform);
156 } else {
157 qWarning("Invalid uniform, skipping");
158 }
159 }
160 } else if (it->type() == QJsonValue::Object) {
161 const auto uniform = toUniform(it->toObject());
162 if (!uniform.type.isEmpty() && !uniform.name.isEmpty())
163 result.uniforms.push_back(uniform);
164 else
165 qWarning("Invalid uniform, skipping");
166 }
167 }
168
169 // Inputs
170 it = obj.constFind(QLatin1String("inputs"));
171 if (it != end) {
172 if (it->type() == QJsonValue::Array) {
173 for (const auto valueRef : it->toArray()) {
174 if (!valueRef.isObject())
175 continue;
176 const auto inOutVar = toInputOutput(valueRef.toObject());
177 if (!inOutVar.type.isEmpty() && !inOutVar.name.isEmpty())
178 result.inputs.push_back(inOutVar);
179 else
180 qWarning("Invalid input variable, skipping");
181 }
182 } else if (it->type() == QJsonValue::Object) {
183 const QJsonObject obj = it->toObject();
184 const auto inOutVar = toInputOutput(obj);
185 if (!inOutVar.type.isEmpty() && !inOutVar.name.isEmpty()) {
186 result.inputs.push_back(inOutVar);
187 } else {
188 qWarning("Invalid input variable, skipping");
189 }
190 }
191 }
192
193 // Outputs
194 it = obj.constFind(QLatin1String("outputs"));
195 if (it != end) {
196 if (it->type() == QJsonValue::Array) {
197 for (const auto valueRef : it->toArray()) {
198 if (!valueRef.isObject())
199 continue;
200 const auto inOutVar = toInputOutput(valueRef.toObject());
201 if (!inOutVar.type.isEmpty() && !inOutVar.name.isEmpty())
202 result.outputs.push_back(inOutVar);
203 else
204 qWarning("Invalid output variable, skipping");
205 }
206 } else if (it->type() == QJsonValue::Object) {
207 const QJsonObject inputJObj = it->toObject();
208 const auto inOutVar = toInputOutput(inputJObj);
209 if (!inOutVar.type.isEmpty() && !inOutVar.name.isEmpty()) {
210 result.outputs.push_back(inOutVar);
211 } else {
212 qWarning("Invalid output variable, skipping");
213 }
214 }
215 }
216 }
217 }
218
219 return result;
220}
221
222} // namespace
\inmodule QtCore
Definition qbytearray.h:57
QByteArray trimmed() const &
Definition qbytearray.h:262
QByteArray mid(qsizetype index, qsizetype len=-1) const &
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:129
QSet< QString >::iterator it
ShaderMetaData getShaderMetaData(const QByteArray &data)
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
DBusConnection const char DBusError * error
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
#define qWarning
Definition qlogging.h:166
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:1531
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
\inmodule QtCore\reentrant
static QSSGShaderGeneratorStage stageFromString(const QString &stage)
static Condition conditionFromString(const QString &condition)