blob: 5ed0c970d6e7be4583d4a8eb44568f7ee6c85e06 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
** 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 <Qt3DRender/private/renderer_p.h>
#include <Qt3DCore/private/qabstractaspect_p.h>
#include <Qt3DCore/qbackendnode.h>
#include <Qt3DRender/private/graphicscontext_p.h>
#include <Qt3DRender/private/renderview_p.h>
#include <Qt3DRender/private/rendercommand_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
#include <Qt3DRender/private/stringtoint_p.h>
#include <Qt3DRender/private/submissioncontext_p.h>
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonArray>
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<>
QJsonObject typeToJsonObj<QRectF>(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<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<>
QJsonObject typeToJsonObj<QSize>(const QSize &s)
{
QJsonObject obj;
obj.insert(QLatin1String("width"), s.width());
obj.insert(QLatin1String("height"), s.height());
return obj;
}
template<>
QJsonValue typeToJsonValue<QSize>(const QSize &s)
{
QJsonArray value;
value.push_back(s.width());
value.push_back(s.height());
return value;
}
template<>
QJsonObject typeToJsonObj<QVector3D>(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<QVector3D>(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<Qt3DCore::QNodeId>(const Qt3DCore::QNodeId &v)
{
QJsonObject obj;
obj.insert(QLatin1String("id"), qint64(v.id()));
return obj;
}
template<>
QJsonValue typeToJsonValue<Qt3DCore::QNodeId>(const Qt3DCore::QNodeId &v)
{
QJsonValue value(qint64(v.id()));
return value;
}
template<>
QJsonObject typeToJsonObj<QVector4D>(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<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<>
QJsonObject typeToJsonObj<QMatrix4x4>(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<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::ShaderParameterPack &pack)
{
QJsonObject obj;
const Render::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 QVector<Render::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 QVector<Render::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 QVector<Render::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::Renderer *renderer)
: m_renderer(renderer)
{
}
// Render thread
void CommandExecuter::performAsynchronousCommandExecution(const QVector<Render::RenderView *> &views)
{
QMutexLocker lock(&m_pendingCommandsMutex);
const QVector<Qt3DCore::Debug::AsynchronousCommandReply *> 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::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;
for (const Render::RenderCommand &c : v->commands()) {
QJsonObject commandObj;
Render::NodeManagers *nodeManagers = m_renderer->nodeManagers();
commandObj.insert(QLatin1String("shader"), backendNodeToJSon(c.m_shader, nodeManagers->shaderManager()));
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