Revision control

++ // Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++
++ #include "commandexecuter_p.h"
++
++ #include <Qt3DCore/private/qabstractaspect_p.h>
++ #include <Qt3DCore/qbackendnode.h>
++ #include <Qt3DRender/private/nodemanagers_p.h>
++ #include <Qt3DRender/private/geometryrenderermanager_p.h>
++ #include <Qt3DRender/private/stringtoint_p.h>
++ #include <QJsonObject>
++ #include <QJsonDocument>
++ #include <QJsonArray>
++ #include <graphicscontext_p.h>
++ #include <renderview_p.h>
++ #include <rendercommand_p.h>
++ #include <renderer_p.h>
++ #include <submissioncontext_p.h>
++
++ QT_BEGIN_NAMESPACE
++
++ namespace Qt3DRender {
++
++ namespace Debug {
++
++ namespace {
++
++ template<typename Type>
++ QJsonObject typeToJsonObj(const Type &)
++ {
++ return QJsonObject();
++ }
++
++ template<typename Type>
++ QJsonValue typeToJsonValue(const Type &t)
++ {
++ Q_UNUSED(t);
++ return QJsonValue();
++ }
++
++ template<>
++ QJsonValue typeToJsonValue<QRectF>(const QRectF &rect)
++ {
++ QJsonArray value;
++
++ value.push_back(rect.x());
++ value.push_back(rect.y());
++ value.push_back(rect.width());
++ value.push_back(rect.height());
++
++ return value;
++ }
++
++ template<>
++ QJsonValue typeToJsonValue<QSize>(const QSize &s)
++ {
++ QJsonArray value;
++
++ value.push_back(s.width());
++ value.push_back(s.height());
++
++ return value;
++ }
++
++ template<>
++ QJsonValue typeToJsonValue<QVector3D>(const QVector3D &v)
++ {
++ QJsonArray value;
++
++ value.push_back(v.x());
++ value.push_back(v.y());
++ value.push_back(v.z());
++
++ return value;
++ }
++
++ template<>
++ QJsonValue typeToJsonValue<Qt3DCore::QNodeId>(const Qt3DCore::QNodeId &v)
++ {
++ QJsonValue value(qint64(v.id()));
++ return value;
++ }
++
++ template<>
++ QJsonValue typeToJsonValue<QVector4D>(const QVector4D &v)
++ {
++ QJsonArray value;
++
++ value.push_back(v.x());
++ value.push_back(v.y());
++ value.push_back(v.z());
++ value.push_back(v.w());
++
++ return value;
++ }
++
++ template<>
++ QJsonValue typeToJsonValue<QMatrix4x4>(const QMatrix4x4 &v)
++ {
++ QJsonArray value;
++
++ value.push_back(typeToJsonValue(v.row(0)));
++ value.push_back(typeToJsonValue(v.row(1)));
++ value.push_back(typeToJsonValue(v.row(2)));
++ value.push_back(typeToJsonValue(v.row(3)));
++
++ return value;
++ }
++
++ template<>
++ QJsonValue typeToJsonValue<QVariant>(const QVariant &v)
++ {
++ const int nodeTypeId = qMetaTypeId<Qt3DCore::QNodeId>();
++
++ if (v.userType() == nodeTypeId)
++ return typeToJsonValue(v.value<Qt3DCore::QNodeId>());
++
++ switch (v.userType()) {
++ case QMetaType::QVector3D:
++ return typeToJsonValue(v.value<QVector3D>());
++ case QMetaType::QVector4D:
++ return typeToJsonValue(v.value<QVector4D>());
++ case QMetaType::QMatrix4x4:
++ return typeToJsonValue(v.value<QMatrix4x4>());
++ default:
++ return QJsonValue::fromVariant(v);
++ }
++ }
++
++ template<typename Handle, typename Manager>
++ QJsonObject backendNodeToJSon(Handle handle, Manager *manager)
++ {
++ Qt3DCore::QBackendNode *node = manager->data(handle);
++ QJsonObject obj;
++ Qt3DCore::QNodeId id;
++ if (node != nullptr)
++ id = node->peerId();
++ obj.insert(QLatin1String("id"), qint64(id.id()));
++ return obj;
++ }
++
++ QJsonObject parameterPackToJson(const Render::OpenGL::ShaderParameterPack &pack)
++ {
++ QJsonObject obj;
++
++ const Render::OpenGL::PackUniformHash &uniforms = pack.uniforms();
++ QJsonArray uniformsArray;
++ for (qsizetype i = 0, m = uniforms.keys.size(); i < m; ++i) {
++ QJsonObject uniformObj;
++ uniformObj.insert(QLatin1String("name"), Render::StringToInt::lookupString(uniforms.keys.at(i)));
++ const Render::UniformValue::ValueType type = uniforms.values.at(i).valueType();
++ uniformObj.insert(QLatin1String("type"),
++ type == Render::UniformValue::ScalarValue
++ ? QLatin1String("value")
++ : QLatin1String("texture"));
++ uniformsArray.push_back(uniformObj);
++ }
++ obj.insert(QLatin1String("uniforms"), uniformsArray);
++
++ QJsonArray texturesArray;
++ const std::vector<Render::OpenGL::ShaderParameterPack::NamedResource> &textures = pack.textures();
++ for (const auto & texture : textures) {
++ QJsonObject textureObj;
++ textureObj.insert(QLatin1String("name"), Render::StringToInt::lookupString(texture.glslNameId));
++ textureObj.insert(QLatin1String("id"), qint64(texture.nodeId.id()));
++ texturesArray.push_back(textureObj);
++ }
++ obj.insert(QLatin1String("textures"), texturesArray);
++
++ const std::vector<Render::OpenGL::BlockToUBO> &ubos = pack.uniformBuffers();
++ QJsonArray ubosArray;
++ for (const auto &ubo : ubos) {
++ QJsonObject uboObj;
++ uboObj.insert(QLatin1String("index"), ubo.m_blockIndex);
++ uboObj.insert(QLatin1String("bufferId"), qint64(ubo.m_bufferID.id()));
++ ubosArray.push_back(uboObj);
++
++ }
++ obj.insert(QLatin1String("ubos"), ubosArray);
++
++ const std::vector<Render::OpenGL::BlockToSSBO> &ssbos = pack.shaderStorageBuffers();
++ QJsonArray ssbosArray;
++ for (const auto &ssbo : ssbos) {
++ QJsonObject ssboObj;
++ ssboObj.insert(QLatin1String("index"), ssbo.m_blockIndex);
++ ssboObj.insert(QLatin1String("bufferId"), qint64(ssbo.m_bufferID.id()));
++ ssbosArray.push_back(ssboObj);
++ }
++ obj.insert(QLatin1String("ssbos"), ssbosArray);
++
++ return obj;
++ }
++
++ } // anonymous
++
++ CommandExecuter::CommandExecuter(Render::OpenGL::Renderer *renderer)
++ : m_renderer(renderer)
++ {
++ }
++
++ // Render thread
++ void CommandExecuter::performAsynchronousCommandExecution(const std::vector<Render::OpenGL::RenderView *> &views)
++ {
++ QMutexLocker lock(&m_pendingCommandsMutex);
++ const QList<Qt3DCore::Debug::AsynchronousCommandReply *> shellCommands = Qt3DCore::moveAndClear(m_pendingCommands);
++ lock.unlock();
++
++ for (auto *reply : shellCommands) {
++ if (reply->commandName() == QLatin1String("glinfo")) {
++ QJsonObject replyObj;
++ const GraphicsApiFilterData *contextInfo = m_renderer->submissionContext()->contextInfo();
++ if (contextInfo != nullptr) {
++ replyObj.insert(QLatin1String("api"),
++ contextInfo->m_api == QGraphicsApiFilter::OpenGL
++ ? QLatin1String("OpenGL")
++ : QLatin1String("OpenGLES"));
++ const QString versionString =
++ QString::number(contextInfo->m_major)
++ + QStringLiteral(".")
++ + QString::number(contextInfo->m_minor);
++ replyObj.insert(QLatin1String("version"), versionString);
++ replyObj.insert(QLatin1String("profile"),
++ contextInfo->m_profile == QGraphicsApiFilter::CoreProfile
++ ? QLatin1String("Core")
++ : contextInfo->m_profile == QGraphicsApiFilter::CompatibilityProfile
++ ? QLatin1String("Compatibility")
++ : QLatin1String("None"));
++ }
++ reply->setData(QJsonDocument(replyObj).toJson());
++ } else if (reply->commandName() == QLatin1String("rendercommands")) {
++ QJsonObject replyObj;
++
++ QJsonArray viewArray;
++ for (Render::OpenGL::RenderView *v : views) {
++ QJsonObject viewObj;
++ viewObj.insert(QLatin1String("viewport"), typeToJsonValue(v->viewport()));
++ viewObj.insert(QLatin1String("surfaceSize"), typeToJsonValue(v->surfaceSize()));
++ viewObj.insert(QLatin1String("devicePixelRatio"), v->devicePixelRatio());
++ viewObj.insert(QLatin1String("noDraw"), v->noDraw());
++ viewObj.insert(QLatin1String("frustumCulling"), v->frustumCulling());
++ viewObj.insert(QLatin1String("compute"), v->isCompute());
++ viewObj.insert(QLatin1String("clearDepthValue"), v->clearDepthValue());
++ viewObj.insert(QLatin1String("clearStencilValue"), v->clearStencilValue());
++
++ QJsonArray renderCommandsArray;
++ v->forEachCommand([&] (Render::OpenGL::RenderCommand &c) {
++ QJsonObject commandObj;
++ Render::NodeManagers *nodeManagers = m_renderer->nodeManagers();
++ commandObj.insert(QLatin1String("shader"), typeToJsonValue(QVariant::fromValue(c.m_shaderId)));
++ commandObj.insert(QLatin1String("vao"), double(c.m_vao.handle()));
++ commandObj.insert(QLatin1String("instanceCount"), c.m_instanceCount);
++ commandObj.insert(QLatin1String("geometry"), backendNodeToJSon(c.m_geometry, nodeManagers->geometryManager()));
++ commandObj.insert(QLatin1String("geometryRenderer"), backendNodeToJSon(c.m_geometryRenderer, nodeManagers->geometryRendererManager()));
++ commandObj.insert(QLatin1String("shaderParameterPack"), parameterPackToJson(c.m_parameterPack));
++
++ renderCommandsArray.push_back(commandObj);
++ });
++ viewObj.insert(QLatin1String("commands"), renderCommandsArray);
++ viewArray.push_back(viewObj);
++ }
++
++ replyObj.insert(QLatin1String("renderViews"), viewArray);
++ reply->setData(QJsonDocument(replyObj).toJson());
++ }
++ reply->setFinished(true);
++ }
++ }
++
++ // Main thread
++ QVariant CommandExecuter::executeCommand(const QStringList &args)
++ {
++ // Note: The replies will be deleted by the AspectCommandDebugger
++ if (args.size() > 0 &&
++ (args.first() == QLatin1String("glinfo") ||
++ args.first() == QLatin1String("rendercommands"))) {
++ auto reply = new Qt3DCore::Debug::AsynchronousCommandReply(args.first());
++ QMutexLocker lock(&m_pendingCommandsMutex);
++ m_pendingCommands.push_back(reply);
++ return QVariant::fromValue(reply);
++ }
++ return QVariant();
++ }
++
++ } // Debug
++
++ } // Qt3DRenderer
++
++ QT_END_NAMESPACE