1 | // Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com> |
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 "commandexecuter_p.h" |
5 | |
6 | #include <Qt3DCore/private/qabstractaspect_p.h> |
7 | #include <Qt3DCore/qbackendnode.h> |
8 | #include <Qt3DRender/private/nodemanagers_p.h> |
9 | #include <Qt3DRender/private/geometryrenderermanager_p.h> |
10 | #include <Qt3DRender/private/stringtoint_p.h> |
11 | #include <QJsonObject> |
12 | #include <QJsonDocument> |
13 | #include <QJsonArray> |
14 | #include <graphicscontext_p.h> |
15 | #include <renderview_p.h> |
16 | #include <rendercommand_p.h> |
17 | #include <renderer_p.h> |
18 | #include <submissioncontext_p.h> |
19 | |
20 | QT_BEGIN_NAMESPACE |
21 | |
22 | namespace Qt3DRender { |
23 | |
24 | namespace Debug { |
25 | |
26 | namespace { |
27 | |
28 | template<typename Type> |
29 | QJsonObject typeToJsonObj(const Type &) |
30 | { |
31 | return QJsonObject(); |
32 | } |
33 | |
34 | template<typename Type> |
35 | QJsonValue typeToJsonValue(const Type &t) |
36 | { |
37 | Q_UNUSED(t); |
38 | return QJsonValue(); |
39 | } |
40 | |
41 | template<> |
42 | QJsonValue typeToJsonValue<QRectF>(const QRectF &rect) |
43 | { |
44 | QJsonArray value; |
45 | |
46 | value.push_back(t: rect.x()); |
47 | value.push_back(t: rect.y()); |
48 | value.push_back(t: rect.width()); |
49 | value.push_back(t: rect.height()); |
50 | |
51 | return value; |
52 | } |
53 | |
54 | template<> |
55 | QJsonValue typeToJsonValue<QSize>(const QSize &s) |
56 | { |
57 | QJsonArray value; |
58 | |
59 | value.push_back(t: s.width()); |
60 | value.push_back(t: s.height()); |
61 | |
62 | return value; |
63 | } |
64 | |
65 | template<> |
66 | QJsonValue typeToJsonValue<QVector3D>(const QVector3D &v) |
67 | { |
68 | QJsonArray value; |
69 | |
70 | value.push_back(t: v.x()); |
71 | value.push_back(t: v.y()); |
72 | value.push_back(t: v.z()); |
73 | |
74 | return value; |
75 | } |
76 | |
77 | template<> |
78 | QJsonValue typeToJsonValue<Qt3DCore::QNodeId>(const Qt3DCore::QNodeId &v) |
79 | { |
80 | QJsonValue value(qint64(v.id())); |
81 | return value; |
82 | } |
83 | |
84 | template<> |
85 | QJsonValue typeToJsonValue<QVector4D>(const QVector4D &v) |
86 | { |
87 | QJsonArray value; |
88 | |
89 | value.push_back(t: v.x()); |
90 | value.push_back(t: v.y()); |
91 | value.push_back(t: v.z()); |
92 | value.push_back(t: v.w()); |
93 | |
94 | return value; |
95 | } |
96 | |
97 | template<> |
98 | QJsonValue typeToJsonValue<QMatrix4x4>(const QMatrix4x4 &v) |
99 | { |
100 | QJsonArray value; |
101 | |
102 | value.push_back(t: typeToJsonValue(v: v.row(index: 0))); |
103 | value.push_back(t: typeToJsonValue(v: v.row(index: 1))); |
104 | value.push_back(t: typeToJsonValue(v: v.row(index: 2))); |
105 | value.push_back(t: typeToJsonValue(v: v.row(index: 3))); |
106 | |
107 | return value; |
108 | } |
109 | |
110 | template<> |
111 | QJsonValue typeToJsonValue<QVariant>(const QVariant &v) |
112 | { |
113 | const int nodeTypeId = qMetaTypeId<Qt3DCore::QNodeId>(); |
114 | |
115 | if (v.userType() == nodeTypeId) |
116 | return typeToJsonValue(v: v.value<Qt3DCore::QNodeId>()); |
117 | |
118 | switch (v.userType()) { |
119 | case QMetaType::QVector3D: |
120 | return typeToJsonValue(v: v.value<QVector3D>()); |
121 | case QMetaType::QVector4D: |
122 | return typeToJsonValue(v: v.value<QVector4D>()); |
123 | case QMetaType::QMatrix4x4: |
124 | return typeToJsonValue(v: v.value<QMatrix4x4>()); |
125 | default: |
126 | return QJsonValue::fromVariant(variant: v); |
127 | } |
128 | } |
129 | |
130 | template<typename Handle, typename Manager> |
131 | QJsonObject backendNodeToJSon(Handle handle, Manager *manager) |
132 | { |
133 | Qt3DCore::QBackendNode *node = manager->data(handle); |
134 | QJsonObject obj; |
135 | Qt3DCore::QNodeId id; |
136 | if (node != nullptr) |
137 | id = node->peerId(); |
138 | obj.insert(key: QLatin1String("id" ), value: qint64(id.id())); |
139 | return obj; |
140 | } |
141 | |
142 | QJsonObject parameterPackToJson(const Render::OpenGL::ShaderParameterPack &pack) |
143 | { |
144 | QJsonObject obj; |
145 | |
146 | const Render::OpenGL::PackUniformHash &uniforms = pack.uniforms(); |
147 | QJsonArray uniformsArray; |
148 | for (qsizetype i = 0, m = uniforms.keys.size(); i < m; ++i) { |
149 | QJsonObject uniformObj; |
150 | uniformObj.insert(key: QLatin1String("name" ), value: Render::StringToInt::lookupString(idx: uniforms.keys.at(n: i))); |
151 | const Render::UniformValue::ValueType type = uniforms.values.at(n: i).valueType(); |
152 | uniformObj.insert(key: QLatin1String("type" ), |
153 | value: type == Render::UniformValue::ScalarValue |
154 | ? QLatin1String("value" ) |
155 | : QLatin1String("texture" )); |
156 | uniformsArray.push_back(t: uniformObj); |
157 | } |
158 | obj.insert(key: QLatin1String("uniforms" ), value: uniformsArray); |
159 | |
160 | QJsonArray texturesArray; |
161 | const std::vector<Render::OpenGL::ShaderParameterPack::NamedResource> &textures = pack.textures(); |
162 | for (const auto & texture : textures) { |
163 | QJsonObject textureObj; |
164 | textureObj.insert(key: QLatin1String("name" ), value: Render::StringToInt::lookupString(idx: texture.glslNameId)); |
165 | textureObj.insert(key: QLatin1String("id" ), value: qint64(texture.nodeId.id())); |
166 | texturesArray.push_back(t: textureObj); |
167 | } |
168 | obj.insert(key: QLatin1String("textures" ), value: texturesArray); |
169 | |
170 | const std::vector<Render::OpenGL::BlockToUBO> &ubos = pack.uniformBuffers(); |
171 | QJsonArray ubosArray; |
172 | for (const auto &ubo : ubos) { |
173 | QJsonObject uboObj; |
174 | uboObj.insert(key: QLatin1String("index" ), value: ubo.m_blockIndex); |
175 | uboObj.insert(key: QLatin1String("bufferId" ), value: qint64(ubo.m_bufferID.id())); |
176 | ubosArray.push_back(t: uboObj); |
177 | |
178 | } |
179 | obj.insert(key: QLatin1String("ubos" ), value: ubosArray); |
180 | |
181 | const std::vector<Render::OpenGL::BlockToSSBO> &ssbos = pack.shaderStorageBuffers(); |
182 | QJsonArray ssbosArray; |
183 | for (const auto &ssbo : ssbos) { |
184 | QJsonObject ssboObj; |
185 | ssboObj.insert(key: QLatin1String("index" ), value: ssbo.m_blockIndex); |
186 | ssboObj.insert(key: QLatin1String("bufferId" ), value: qint64(ssbo.m_bufferID.id())); |
187 | ssbosArray.push_back(t: ssboObj); |
188 | } |
189 | obj.insert(key: QLatin1String("ssbos" ), value: ssbosArray); |
190 | |
191 | return obj; |
192 | } |
193 | |
194 | } // anonymous |
195 | |
196 | CommandExecuter::CommandExecuter(Render::OpenGL::Renderer *renderer) |
197 | : m_renderer(renderer) |
198 | { |
199 | } |
200 | |
201 | // Render thread |
202 | void CommandExecuter::performAsynchronousCommandExecution(const std::vector<Render::OpenGL::RenderView *> &views) |
203 | { |
204 | QMutexLocker lock(&m_pendingCommandsMutex); |
205 | const QList<Qt3DCore::Debug::AsynchronousCommandReply *> shellCommands = Qt3DCore::moveAndClear(data&: m_pendingCommands); |
206 | lock.unlock(); |
207 | |
208 | for (auto *reply : shellCommands) { |
209 | if (reply->commandName() == QLatin1String("glinfo" )) { |
210 | QJsonObject replyObj; |
211 | const GraphicsApiFilterData *contextInfo = m_renderer->submissionContext()->contextInfo(); |
212 | if (contextInfo != nullptr) { |
213 | replyObj.insert(key: QLatin1String("api" ), |
214 | value: contextInfo->m_api == QGraphicsApiFilter::OpenGL |
215 | ? QLatin1String("OpenGL" ) |
216 | : QLatin1String("OpenGLES" )); |
217 | const QString versionString = |
218 | QString::number(contextInfo->m_major) |
219 | + QStringLiteral("." ) |
220 | + QString::number(contextInfo->m_minor); |
221 | replyObj.insert(key: QLatin1String("version" ), value: versionString); |
222 | replyObj.insert(key: QLatin1String("profile" ), |
223 | value: contextInfo->m_profile == QGraphicsApiFilter::CoreProfile |
224 | ? QLatin1String("Core" ) |
225 | : contextInfo->m_profile == QGraphicsApiFilter::CompatibilityProfile |
226 | ? QLatin1String("Compatibility" ) |
227 | : QLatin1String("None" )); |
228 | } |
229 | reply->setData(QJsonDocument(replyObj).toJson()); |
230 | } else if (reply->commandName() == QLatin1String("rendercommands" )) { |
231 | QJsonObject replyObj; |
232 | |
233 | QJsonArray viewArray; |
234 | for (Render::OpenGL::RenderView *v : views) { |
235 | QJsonObject viewObj; |
236 | viewObj.insert(key: QLatin1String("viewport" ), value: typeToJsonValue(rect: v->viewport())); |
237 | viewObj.insert(key: QLatin1String("surfaceSize" ), value: typeToJsonValue(s: v->surfaceSize())); |
238 | viewObj.insert(key: QLatin1String("devicePixelRatio" ), value: v->devicePixelRatio()); |
239 | viewObj.insert(key: QLatin1String("noDraw" ), value: v->noDraw()); |
240 | viewObj.insert(key: QLatin1String("frustumCulling" ), value: v->frustumCulling()); |
241 | viewObj.insert(key: QLatin1String("compute" ), value: v->isCompute()); |
242 | viewObj.insert(key: QLatin1String("clearDepthValue" ), value: v->clearDepthValue()); |
243 | viewObj.insert(key: QLatin1String("clearStencilValue" ), value: v->clearStencilValue()); |
244 | |
245 | QJsonArray renderCommandsArray; |
246 | v->forEachCommand(func: [&] (Render::OpenGL::RenderCommand &c) { |
247 | QJsonObject commandObj; |
248 | Render::NodeManagers *nodeManagers = m_renderer->nodeManagers(); |
249 | commandObj.insert(key: QLatin1String("shader" ), value: typeToJsonValue(v: QVariant::fromValue(value: c.m_shaderId))); |
250 | commandObj.insert(key: QLatin1String("vao" ), value: double(c.m_vao.handle())); |
251 | commandObj.insert(key: QLatin1String("instanceCount" ), value: c.m_instanceCount); |
252 | commandObj.insert(key: QLatin1String("geometry" ), value: backendNodeToJSon(handle: c.m_geometry, manager: nodeManagers->geometryManager())); |
253 | commandObj.insert(key: QLatin1String("geometryRenderer" ), value: backendNodeToJSon(handle: c.m_geometryRenderer, manager: nodeManagers->geometryRendererManager())); |
254 | commandObj.insert(key: QLatin1String("shaderParameterPack" ), value: parameterPackToJson(pack: c.m_parameterPack)); |
255 | |
256 | renderCommandsArray.push_back(t: commandObj); |
257 | }); |
258 | viewObj.insert(key: QLatin1String("commands" ), value: renderCommandsArray); |
259 | viewArray.push_back(t: viewObj); |
260 | } |
261 | |
262 | replyObj.insert(key: QLatin1String("renderViews" ), value: viewArray); |
263 | reply->setData(QJsonDocument(replyObj).toJson()); |
264 | } |
265 | reply->setFinished(true); |
266 | } |
267 | } |
268 | |
269 | // Main thread |
270 | QVariant CommandExecuter::executeCommand(const QStringList &args) |
271 | { |
272 | // Note: The replies will be deleted by the AspectCommandDebugger |
273 | if (args.size() > 0 && |
274 | (args.first() == QLatin1String("glinfo" ) || |
275 | args.first() == QLatin1String("rendercommands" ))) { |
276 | auto reply = new Qt3DCore::Debug::AsynchronousCommandReply(args.first()); |
277 | QMutexLocker lock(&m_pendingCommandsMutex); |
278 | m_pendingCommands.push_back(t: reply); |
279 | return QVariant::fromValue(value: reply); |
280 | } |
281 | return QVariant(); |
282 | } |
283 | |
284 | } // Debug |
285 | |
286 | } // Qt3DRenderer |
287 | |
288 | QT_END_NAMESPACE |
289 | |