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
20QT_BEGIN_NAMESPACE
21
22namespace Qt3DRender {
23
24namespace Debug {
25
26namespace {
27
28template<typename Type>
29QJsonObject typeToJsonObj(const Type &)
30{
31 return QJsonObject();
32}
33
34template<typename Type>
35QJsonValue typeToJsonValue(const Type &t)
36{
37 Q_UNUSED(t);
38 return QJsonValue();
39}
40
41template<>
42QJsonValue 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
54template<>
55QJsonValue 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
65template<>
66QJsonValue 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
77template<>
78QJsonValue typeToJsonValue<Qt3DCore::QNodeId>(const Qt3DCore::QNodeId &v)
79{
80 QJsonValue value(qint64(v.id()));
81 return value;
82}
83
84template<>
85QJsonValue 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
97template<>
98QJsonValue 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
110template<>
111QJsonValue 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
130template<typename Handle, typename Manager>
131QJsonObject 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
142QJsonObject 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
196CommandExecuter::CommandExecuter(Render::OpenGL::Renderer *renderer)
197 : m_renderer(renderer)
198{
199}
200
201// Render thread
202void 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
270QVariant 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
288QT_END_NAMESPACE
289

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