/**************************************************************************** ** ** Copyright (C) 2016 Paul Lemire ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt3D module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPLv3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or later as published by the Free ** Software Foundation and appearing in the file LICENSE.GPL included in ** the packaging of this file. Please review the following information to ** ensure the GNU General Public License version 2.0 requirements will be ** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "commandexecuter_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE namespace Qt3DRender { namespace Debug { namespace { template QJsonObject typeToJsonObj(const Type &) { return QJsonObject(); } template QJsonValue typeToJsonValue(const Type &t) { Q_UNUSED(t); return QJsonValue(); } template<> QJsonObject typeToJsonObj(const QRectF &rect) { QJsonObject obj; obj.insert(QLatin1String("x"), rect.x()); obj.insert(QLatin1String("y"), rect.y()); obj.insert(QLatin1String("width"), rect.width()); obj.insert(QLatin1String("height"), rect.height()); return obj; } template<> QJsonValue typeToJsonValue(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<> QJsonObject typeToJsonObj(const QSize &s) { QJsonObject obj; obj.insert(QLatin1String("width"), s.width()); obj.insert(QLatin1String("height"), s.height()); return obj; } template<> QJsonValue typeToJsonValue(const QSize &s) { QJsonArray value; value.push_back(s.width()); value.push_back(s.height()); return value; } template<> QJsonObject typeToJsonObj(const QVector3D &v) { QJsonObject obj; obj.insert(QLatin1String("x"), v.x()); obj.insert(QLatin1String("y"), v.y()); obj.insert(QLatin1String("z"), v.z()); return obj; } template<> QJsonValue typeToJsonValue(const QVector3D &v) { QJsonArray value; value.push_back(v.x()); value.push_back(v.y()); value.push_back(v.z()); return value; } template<> QJsonObject typeToJsonObj(const Qt3DCore::QNodeId &v) { QJsonObject obj; obj.insert(QLatin1String("id"), qint64(v.id())); return obj; } template<> QJsonValue typeToJsonValue(const Qt3DCore::QNodeId &v) { QJsonValue value(qint64(v.id())); return value; } template<> QJsonObject typeToJsonObj(const QVector4D &v) { QJsonObject obj; obj.insert(QLatin1String("x"), v.x()); obj.insert(QLatin1String("y"), v.y()); obj.insert(QLatin1String("z"), v.z()); obj.insert(QLatin1String("w"), v.w()); return obj; } template<> QJsonValue typeToJsonValue(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<> QJsonObject typeToJsonObj(const QMatrix4x4 &v) { QJsonObject obj; obj.insert(QLatin1String("row 0"), typeToJsonObj(v.row(0))); obj.insert(QLatin1String("row 1"), typeToJsonObj(v.row(0))); obj.insert(QLatin1String("row 2"), typeToJsonObj(v.row(0))); obj.insert(QLatin1String("row 3"), typeToJsonObj(v.row(0))); return obj; } template<> QJsonValue typeToJsonValue(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(const QVariant &v) { const int nodeTypeId = qMetaTypeId(); if (v.userType() == nodeTypeId) return typeToJsonValue(v.value()); switch (v.userType()) { case QMetaType::QVector3D: return typeToJsonValue(v.value()); case QMetaType::QVector4D: return typeToJsonValue(v.value()); case QMetaType::QMatrix4x4: return typeToJsonValue(v.value()); default: return QJsonValue::fromVariant(v); } } template 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 (int 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 &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 &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 &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 QVector &views) { QMutexLocker lock(&m_pendingCommandsMutex); const QVector shellCommands = std::move(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.length() > 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