1/****************************************************************************
2**
3** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "commandexecuter_p.h"
38
39#include <Qt3DCore/private/qabstractaspect_p.h>
40#include <Qt3DCore/qbackendnode.h>
41#include <Qt3DRender/private/nodemanagers_p.h>
42#include <Qt3DRender/private/geometryrenderermanager_p.h>
43#include <Qt3DRender/private/stringtoint_p.h>
44#include <QJsonObject>
45#include <QJsonDocument>
46#include <QJsonArray>
47#include <graphicscontext_p.h>
48#include <renderview_p.h>
49#include <rendercommand_p.h>
50#include <renderer_p.h>
51#include <submissioncontext_p.h>
52
53QT_BEGIN_NAMESPACE
54
55namespace Qt3DRender {
56
57namespace Debug {
58
59namespace {
60
61template<typename Type>
62QJsonObject typeToJsonObj(const Type &)
63{
64 return QJsonObject();
65}
66
67template<typename Type>
68QJsonValue typeToJsonValue(const Type &t)
69{
70 Q_UNUSED(t);
71 return QJsonValue();
72}
73
74template<>
75QJsonObject typeToJsonObj<QRectF>(const QRectF &rect)
76{
77 QJsonObject obj;
78
79 obj.insert(key: QLatin1String("x"), value: rect.x());
80 obj.insert(key: QLatin1String("y"), value: rect.y());
81 obj.insert(key: QLatin1String("width"), value: rect.width());
82 obj.insert(key: QLatin1String("height"), value: rect.height());
83
84 return obj;
85}
86
87template<>
88QJsonValue typeToJsonValue<QRectF>(const QRectF &rect)
89{
90 QJsonArray value;
91
92 value.push_back(t: rect.x());
93 value.push_back(t: rect.y());
94 value.push_back(t: rect.width());
95 value.push_back(t: rect.height());
96
97 return value;
98}
99
100template<>
101QJsonObject typeToJsonObj<QSize>(const QSize &s)
102{
103 QJsonObject obj;
104
105 obj.insert(key: QLatin1String("width"), value: s.width());
106 obj.insert(key: QLatin1String("height"), value: s.height());
107
108 return obj;
109}
110
111template<>
112QJsonValue typeToJsonValue<QSize>(const QSize &s)
113{
114 QJsonArray value;
115
116 value.push_back(t: s.width());
117 value.push_back(t: s.height());
118
119 return value;
120}
121
122template<>
123QJsonObject typeToJsonObj<QVector3D>(const QVector3D &v)
124{
125 QJsonObject obj;
126
127 obj.insert(key: QLatin1String("x"), value: v.x());
128 obj.insert(key: QLatin1String("y"), value: v.y());
129 obj.insert(key: QLatin1String("z"), value: v.z());
130
131 return obj;
132}
133
134template<>
135QJsonValue typeToJsonValue<QVector3D>(const QVector3D &v)
136{
137 QJsonArray value;
138
139 value.push_back(t: v.x());
140 value.push_back(t: v.y());
141 value.push_back(t: v.z());
142
143 return value;
144}
145
146template<>
147QJsonObject typeToJsonObj<Qt3DCore::QNodeId>(const Qt3DCore::QNodeId &v)
148{
149 QJsonObject obj;
150 obj.insert(key: QLatin1String("id"), value: qint64(v.id()));
151 return obj;
152}
153
154template<>
155QJsonValue typeToJsonValue<Qt3DCore::QNodeId>(const Qt3DCore::QNodeId &v)
156{
157 QJsonValue value(qint64(v.id()));
158 return value;
159}
160
161template<>
162QJsonObject typeToJsonObj<QVector4D>(const QVector4D &v)
163{
164 QJsonObject obj;
165
166 obj.insert(key: QLatin1String("x"), value: v.x());
167 obj.insert(key: QLatin1String("y"), value: v.y());
168 obj.insert(key: QLatin1String("z"), value: v.z());
169 obj.insert(key: QLatin1String("w"), value: v.w());
170
171 return obj;
172}
173
174template<>
175QJsonValue typeToJsonValue<QVector4D>(const QVector4D &v)
176{
177 QJsonArray value;
178
179 value.push_back(t: v.x());
180 value.push_back(t: v.y());
181 value.push_back(t: v.z());
182 value.push_back(t: v.w());
183
184 return value;
185}
186
187template<>
188QJsonObject typeToJsonObj<QMatrix4x4>(const QMatrix4x4 &v)
189{
190 QJsonObject obj;
191
192 obj.insert(key: QLatin1String("row 0"), value: typeToJsonObj(v: v.row(index: 0)));
193 obj.insert(key: QLatin1String("row 1"), value: typeToJsonObj(v: v.row(index: 0)));
194 obj.insert(key: QLatin1String("row 2"), value: typeToJsonObj(v: v.row(index: 0)));
195 obj.insert(key: QLatin1String("row 3"), value: typeToJsonObj(v: v.row(index: 0)));
196
197 return obj;
198}
199
200template<>
201QJsonValue typeToJsonValue<QMatrix4x4>(const QMatrix4x4 &v)
202{
203 QJsonArray value;
204
205 value.push_back(t: typeToJsonValue(v: v.row(index: 0)));
206 value.push_back(t: typeToJsonValue(v: v.row(index: 1)));
207 value.push_back(t: typeToJsonValue(v: v.row(index: 2)));
208 value.push_back(t: typeToJsonValue(v: v.row(index: 3)));
209
210 return value;
211}
212
213template<>
214QJsonValue typeToJsonValue<QVariant>(const QVariant &v)
215{
216 const int nodeTypeId = qMetaTypeId<Qt3DCore::QNodeId>();
217
218 if (v.userType() == nodeTypeId)
219 return typeToJsonValue(v: v.value<Qt3DCore::QNodeId>());
220
221 switch (v.userType()) {
222 case QMetaType::QVector3D:
223 return typeToJsonValue(v: v.value<QVector3D>());
224 case QMetaType::QVector4D:
225 return typeToJsonValue(v: v.value<QVector4D>());
226 case QMetaType::QMatrix4x4:
227 return typeToJsonValue(v: v.value<QMatrix4x4>());
228 default:
229 return QJsonValue::fromVariant(variant: v);
230 }
231}
232
233template<typename Handle, typename Manager>
234QJsonObject backendNodeToJSon(Handle handle, Manager *manager)
235{
236 Qt3DCore::QBackendNode *node = manager->data(handle);
237 QJsonObject obj;
238 Qt3DCore::QNodeId id;
239 if (node != nullptr)
240 id = node->peerId();
241 obj.insert(key: QLatin1String("id"), value: qint64(id.id()));
242 return obj;
243}
244
245QJsonObject parameterPackToJson(const Render::OpenGL::ShaderParameterPack &pack)
246{
247 QJsonObject obj;
248
249 const Render::OpenGL::PackUniformHash &uniforms = pack.uniforms();
250 QJsonArray uniformsArray;
251 for (int i = 0, m = uniforms.keys.size(); i < m; ++i) {
252 QJsonObject uniformObj;
253 uniformObj.insert(key: QLatin1String("name"), value: Render::StringToInt::lookupString(idx: uniforms.keys.at(n: i)));
254 const Render::UniformValue::ValueType type = uniforms.values.at(n: i).valueType();
255 uniformObj.insert(key: QLatin1String("type"),
256 value: type == Render::UniformValue::ScalarValue
257 ? QLatin1String("value")
258 : QLatin1String("texture"));
259 uniformsArray.push_back(t: uniformObj);
260 }
261 obj.insert(key: QLatin1String("uniforms"), value: uniformsArray);
262
263 QJsonArray texturesArray;
264 const std::vector<Render::OpenGL::ShaderParameterPack::NamedResource> &textures = pack.textures();
265 for (const auto & texture : textures) {
266 QJsonObject textureObj;
267 textureObj.insert(key: QLatin1String("name"), value: Render::StringToInt::lookupString(idx: texture.glslNameId));
268 textureObj.insert(key: QLatin1String("id"), value: qint64(texture.nodeId.id()));
269 texturesArray.push_back(t: textureObj);
270 }
271 obj.insert(key: QLatin1String("textures"), value: texturesArray);
272
273 const std::vector<Render::OpenGL::BlockToUBO> &ubos = pack.uniformBuffers();
274 QJsonArray ubosArray;
275 for (const auto &ubo : ubos) {
276 QJsonObject uboObj;
277 uboObj.insert(key: QLatin1String("index"), value: ubo.m_blockIndex);
278 uboObj.insert(key: QLatin1String("bufferId"), value: qint64(ubo.m_bufferID.id()));
279 ubosArray.push_back(t: uboObj);
280
281 }
282 obj.insert(key: QLatin1String("ubos"), value: ubosArray);
283
284 const std::vector<Render::OpenGL::BlockToSSBO> &ssbos = pack.shaderStorageBuffers();
285 QJsonArray ssbosArray;
286 for (const auto &ssbo : ssbos) {
287 QJsonObject ssboObj;
288 ssboObj.insert(key: QLatin1String("index"), value: ssbo.m_blockIndex);
289 ssboObj.insert(key: QLatin1String("bufferId"), value: qint64(ssbo.m_bufferID.id()));
290 ssbosArray.push_back(t: ssboObj);
291 }
292 obj.insert(key: QLatin1String("ssbos"), value: ssbosArray);
293
294 return obj;
295}
296
297} // anonymous
298
299CommandExecuter::CommandExecuter(Render::OpenGL::Renderer *renderer)
300 : m_renderer(renderer)
301{
302}
303
304// Render thread
305void CommandExecuter::performAsynchronousCommandExecution(const QVector<Render::OpenGL::RenderView *> &views)
306{
307 QMutexLocker lock(&m_pendingCommandsMutex);
308 const QVector<Qt3DCore::Debug::AsynchronousCommandReply *> shellCommands = std::move(m_pendingCommands);
309 lock.unlock();
310
311 for (auto *reply : shellCommands) {
312 if (reply->commandName() == QLatin1String("glinfo")) {
313 QJsonObject replyObj;
314 const GraphicsApiFilterData *contextInfo = m_renderer->submissionContext()->contextInfo();
315 if (contextInfo != nullptr) {
316 replyObj.insert(key: QLatin1String("api"),
317 value: contextInfo->m_api == QGraphicsApiFilter::OpenGL
318 ? QLatin1String("OpenGL")
319 : QLatin1String("OpenGLES"));
320 const QString versionString =
321 QString::number(contextInfo->m_major)
322 + QStringLiteral(".")
323 + QString::number(contextInfo->m_minor);
324 replyObj.insert(key: QLatin1String("version"), value: versionString);
325 replyObj.insert(key: QLatin1String("profile"),
326 value: contextInfo->m_profile == QGraphicsApiFilter::CoreProfile
327 ? QLatin1String("Core")
328 : contextInfo->m_profile == QGraphicsApiFilter::CompatibilityProfile
329 ? QLatin1String("Compatibility")
330 : QLatin1String("None"));
331 }
332 reply->setData(QJsonDocument(replyObj).toJson());
333 } else if (reply->commandName() == QLatin1String("rendercommands")) {
334 QJsonObject replyObj;
335
336 QJsonArray viewArray;
337 for (Render::OpenGL::RenderView *v : views) {
338 QJsonObject viewObj;
339 viewObj.insert(key: QLatin1String("viewport"), value: typeToJsonValue(rect: v->viewport()));
340 viewObj.insert(key: QLatin1String("surfaceSize"), value: typeToJsonValue(s: v->surfaceSize()));
341 viewObj.insert(key: QLatin1String("devicePixelRatio"), value: v->devicePixelRatio());
342 viewObj.insert(key: QLatin1String("noDraw"), value: v->noDraw());
343 viewObj.insert(key: QLatin1String("frustumCulling"), value: v->frustumCulling());
344 viewObj.insert(key: QLatin1String("compute"), value: v->isCompute());
345 viewObj.insert(key: QLatin1String("clearDepthValue"), value: v->clearDepthValue());
346 viewObj.insert(key: QLatin1String("clearStencilValue"), value: v->clearStencilValue());
347
348 QJsonArray renderCommandsArray;
349 v->forEachCommand(func: [&] (Render::OpenGL::RenderCommand &c) {
350 QJsonObject commandObj;
351 Render::NodeManagers *nodeManagers = m_renderer->nodeManagers();
352 commandObj.insert(key: QLatin1String("shader"), value: typeToJsonValue(v: QVariant::fromValue(value: c.m_shaderId)));
353 commandObj.insert(key: QLatin1String("vao"), value: double(c.m_vao.handle()));
354 commandObj.insert(key: QLatin1String("instanceCount"), value: c.m_instanceCount);
355 commandObj.insert(key: QLatin1String("geometry"), value: backendNodeToJSon(handle: c.m_geometry, manager: nodeManagers->geometryManager()));
356 commandObj.insert(key: QLatin1String("geometryRenderer"), value: backendNodeToJSon(handle: c.m_geometryRenderer, manager: nodeManagers->geometryRendererManager()));
357 commandObj.insert(key: QLatin1String("shaderParameterPack"), value: parameterPackToJson(pack: c.m_parameterPack));
358
359 renderCommandsArray.push_back(t: commandObj);
360 });
361 viewObj.insert(key: QLatin1String("commands"), value: renderCommandsArray);
362 viewArray.push_back(t: viewObj);
363 }
364
365 replyObj.insert(key: QLatin1String("renderViews"), value: viewArray);
366 reply->setData(QJsonDocument(replyObj).toJson());
367 }
368 reply->setFinished(true);
369 }
370}
371
372// Main thread
373QVariant CommandExecuter::executeCommand(const QStringList &args)
374{
375 // Note: The replies will be deleted by the AspectCommandDebugger
376 if (args.length() > 0 &&
377 (args.first() == QLatin1String("glinfo") ||
378 args.first() == QLatin1String("rendercommands"))) {
379 auto reply = new Qt3DCore::Debug::AsynchronousCommandReply(args.first());
380 QMutexLocker lock(&m_pendingCommandsMutex);
381 m_pendingCommands.push_back(t: reply);
382 return QVariant::fromValue(value: reply);
383 }
384 return QVariant();
385}
386
387} // Debug
388
389} // Qt3DRenderer
390
391QT_END_NAMESPACE
392

source code of qt3d/src/plugins/renderers/opengl/renderer/commandexecuter.cpp