summaryrefslogtreecommitdiffstats
path: root/src/render/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/render/backend')
-rw-r--r--src/render/backend/abstractrenderer_p.h4
-rw-r--r--src/render/backend/attachmentpack.cpp2
-rw-r--r--src/render/backend/backendnode.cpp16
-rw-r--r--src/render/backend/backendnode_p.h8
-rw-r--r--src/render/backend/bufferutils_p.h115
-rw-r--r--src/render/backend/buffervisitor_p.h212
-rw-r--r--src/render/backend/cameralens.cpp126
-rw-r--r--src/render/backend/cameralens_p.h28
-rw-r--r--src/render/backend/commandexecuter.cpp5
-rw-r--r--src/render/backend/commandexecuter_p.h4
-rw-r--r--src/render/backend/commandthread.cpp129
-rw-r--r--src/render/backend/commandthread_p.h105
-rw-r--r--src/render/backend/entity.cpp32
-rw-r--r--src/render/backend/entity_p.h18
-rw-r--r--src/render/backend/frameprofiler_p.h14
-rw-r--r--src/render/backend/handle_types_p.h2
-rw-r--r--src/render/backend/levelofdetail.cpp29
-rw-r--r--src/render/backend/levelofdetail_p.h8
-rw-r--r--src/render/backend/managers_p.h15
-rw-r--r--src/render/backend/nodemanagers.cpp15
-rw-r--r--src/render/backend/nodemanagers_p.h13
-rw-r--r--src/render/backend/openglvertexarrayobject.cpp63
-rw-r--r--src/render/backend/openglvertexarrayobject_p.h18
-rw-r--r--src/render/backend/platformsurfacefilter.cpp4
-rw-r--r--src/render/backend/platformsurfacefilter_p.h4
-rw-r--r--src/render/backend/render-backend.pri22
-rw-r--r--src/render/backend/renderer.cpp290
-rw-r--r--src/render/backend/renderer_p.h23
-rw-r--r--src/render/backend/renderqueue.cpp6
-rw-r--r--src/render/backend/renderqueue_p.h4
-rw-r--r--src/render/backend/rendertargetoutput.cpp9
-rw-r--r--src/render/backend/rendertargetoutput_p.h3
-rw-r--r--src/render/backend/renderthread_p.h8
-rw-r--r--src/render/backend/renderview.cpp52
-rw-r--r--src/render/backend/renderview_p.h20
-rw-r--r--src/render/backend/renderviewbuilder.cpp29
-rw-r--r--src/render/backend/resourceaccessor.cpp123
-rw-r--r--src/render/backend/resourceaccessor_p.h102
-rw-r--r--src/render/backend/shadervariables_p.h1
-rw-r--r--src/render/backend/triangleboundingvolume.cpp17
-rw-r--r--src/render/backend/triangleboundingvolume_p.h2
-rw-r--r--src/render/backend/trianglesvisitor.cpp129
-rw-r--r--src/render/backend/trianglesvisitor_p.h27
43 files changed, 1604 insertions, 252 deletions
diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h
index 8b17cbf45..2f7545454 100644
--- a/src/render/backend/abstractrenderer_p.h
+++ b/src/render/backend/abstractrenderer_p.h
@@ -56,6 +56,8 @@
#include <Qt3DCore/qnodeid.h>
#include <QtGui/qsurfaceformat.h>
+#include <QtGui/qopenglcontext.h>
+
QT_BEGIN_NAMESPACE
class QSurface;
@@ -137,6 +139,7 @@ public:
virtual QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() = 0;
virtual Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() = 0;
virtual Qt3DCore::QAspectJobPtr syncTextureLoadingJob() = 0;
+ virtual Qt3DCore::QAspectJobPtr expandBoundingVolumeJob() = 0;
virtual void setSceneRoot(Qt3DCore::QBackendNodeFactory *factory, Entity *root) = 0;
@@ -153,6 +156,7 @@ public:
virtual void setOffscreenSurfaceHelper(OffscreenSurfaceHelper *helper) = 0;
virtual QSurfaceFormat format() = 0;
+ virtual QOpenGLContext *shareContext() const = 0;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractRenderer::BackendNodeDirtySet)
diff --git a/src/render/backend/attachmentpack.cpp b/src/render/backend/attachmentpack.cpp
index d2bb5ee9a..6dee7587b 100644
--- a/src/render/backend/attachmentpack.cpp
+++ b/src/render/backend/attachmentpack.cpp
@@ -60,7 +60,7 @@ AttachmentPack::AttachmentPack(const RenderTargetSelector *selector, const Rende
for (Qt3DCore::QNodeId outputId : outputIds) {
const RenderTargetOutput *output = attachmentManager->lookupResource(outputId);
if (output)
- m_attachments.append(output->attachment());
+ m_attachments.append(*output->attachment());
}
// Create actual DrawBuffers list that is used for glDrawBuffers
diff --git a/src/render/backend/backendnode.cpp b/src/render/backend/backendnode.cpp
index 7054db6a4..0dc8da237 100644
--- a/src/render/backend/backendnode.cpp
+++ b/src/render/backend/backendnode.cpp
@@ -37,7 +37,10 @@
**
****************************************************************************/
-#include "backendnode_p.h"
+#include <private/backendnode_p.h>
+#include <private/renderer_p.h>
+#include <private/resourceaccessor_p.h>
+#include <private/nodemanagers_p.h>
QT_BEGIN_NAMESPACE
@@ -61,12 +64,23 @@ void BackendNode::setRenderer(AbstractRenderer *renderer)
m_renderer = renderer;
}
+AbstractRenderer *BackendNode::renderer() const
+{
+ return m_renderer;
+}
+
void BackendNode::markDirty(AbstractRenderer::BackendNodeDirtySet changes)
{
Q_ASSERT(m_renderer);
m_renderer->markDirty(changes, this);
}
+QSharedPointer<RenderBackendResourceAccessor> BackendNode::resourceAccessor()
+{
+ Render::Renderer *r = static_cast<Render::Renderer *>(renderer());
+ return r->nodeManagers()->resourceAccessor();
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/backendnode_p.h b/src/render/backend/backendnode_p.h
index 5688c2412..8db68b11d 100644
--- a/src/render/backend/backendnode_p.h
+++ b/src/render/backend/backendnode_p.h
@@ -54,6 +54,7 @@
#include <Qt3DRender/qt3drender_global.h>
#include <Qt3DCore/qbackendnode.h>
#include <Qt3DRender/private/abstractrenderer_p.h>
+#include <private/qt3drender_global_p.h>
QT_BEGIN_NAMESPACE
@@ -61,13 +62,18 @@ namespace Qt3DRender {
namespace Render {
-class Q_AUTOTEST_EXPORT BackendNode : public Qt3DCore::QBackendNode
+class RenderBackendResourceAccessor;
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT BackendNode : public Qt3DCore::QBackendNode
{
public:
BackendNode(Qt3DCore::QBackendNode::Mode mode = ReadOnly);
~BackendNode();
void setRenderer(AbstractRenderer *renderer);
+ AbstractRenderer *renderer() const;
+
+ QSharedPointer<RenderBackendResourceAccessor> resourceAccessor();
protected:
void markDirty(AbstractRenderer::BackendNodeDirtySet changes);
diff --git a/src/render/backend/bufferutils_p.h b/src/render/backend/bufferutils_p.h
new file mode 100644
index 000000000..2bb35fac6
--- /dev/null
+++ b/src/render/backend/bufferutils_p.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Paul Lemire paul.lemire350@gmail.com
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_BUFFERUTILS_P_H
+#define QT3DRENDER_RENDER_BUFFERUTILS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DRender/QAttribute>
+#include <QByteArray>
+
+QT_BEGIN_NAMESPACE
+
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class GeometryRenderer;
+class NodeManagers;
+class Attribute;
+class Buffer;
+
+struct BufferInfo
+{
+ BufferInfo()
+ : type(QAttribute::VertexBaseType::Float)
+ , dataSize(0)
+ , count(0)
+ , byteStride(0)
+ , byteOffset(0)
+ {}
+
+ QByteArray data;
+ QAttribute::VertexBaseType type;
+ uint dataSize;
+ uint count;
+ uint byteStride;
+ uint byteOffset;
+};
+
+
+namespace BufferTypeInfo {
+
+ template <QAttribute::VertexBaseType> struct EnumToType;
+ template <> struct EnumToType<QAttribute::Byte> { typedef const char type; };
+ template <> struct EnumToType<QAttribute::UnsignedByte> { typedef const uchar type; };
+ template <> struct EnumToType<QAttribute::Short> { typedef const short type; };
+ template <> struct EnumToType<QAttribute::UnsignedShort> { typedef const ushort type; };
+ template <> struct EnumToType<QAttribute::Int> { typedef const int type; };
+ template <> struct EnumToType<QAttribute::UnsignedInt> { typedef const uint type; };
+ template <> struct EnumToType<QAttribute::Float> { typedef const float type; };
+ template <> struct EnumToType<QAttribute::Double> { typedef const double type; };
+
+ template<QAttribute::VertexBaseType v>
+ typename EnumToType<v>::type *castToType(const QByteArray &u, uint byteOffset)
+ {
+ return reinterpret_cast< typename EnumToType<v>::type *>(u.constData() + byteOffset);
+ }
+
+} // namespace BufferTypeInfo
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+
+#endif // QT3DRENDER_RENDER_BUFFERUTILS_P_H
diff --git a/src/render/backend/buffervisitor_p.h b/src/render/backend/buffervisitor_p.h
new file mode 100644
index 000000000..7149e21ae
--- /dev/null
+++ b/src/render/backend/buffervisitor_p.h
@@ -0,0 +1,212 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_BUFFERVISITOR_P_H
+#define QT3DRENDER_RENDER_BUFFERVISITOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/qnodeid.h>
+#include <Qt3DRender/QAttribute>
+#include <Qt3DRender/private/trianglesvisitor_p.h>
+#include <Qt3DRender/private/attribute_p.h>
+#include <Qt3DRender/private/buffer_p.h>
+#include <Qt3DRender/private/bufferutils_p.h>
+#include <Qt3DRender/private/geometryrenderer_p.h>
+#include <Qt3DRender/private/geometry_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+class QEntity;
+}
+
+namespace Qt3DRender {
+namespace Render {
+
+
+template <typename ValueType, QAttribute::VertexBaseType VertexBaseType, uint dataSize>
+class Q_AUTOTEST_EXPORT BufferVisitor
+{
+public:
+ explicit BufferVisitor(NodeManagers *manager)
+ : m_manager(manager)
+ {
+ }
+ virtual ~BufferVisitor() { }
+
+ virtual void visit(uint ndx, ValueType x) {
+ Q_UNUSED(ndx); Q_UNUSED(x);
+ }
+ virtual void visit(uint ndx, ValueType x, ValueType y) {
+ Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y);
+ }
+ virtual void visit(uint ndx, ValueType x, ValueType y, ValueType z) {
+ Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(z);
+ }
+ virtual void visit(uint ndx, ValueType x, ValueType y, ValueType z, ValueType w) {
+ Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(z); Q_UNUSED(w);
+ }
+
+ bool apply(const GeometryRenderer *renderer, const QString &attributeName)
+ {
+ if (renderer == nullptr || renderer->instanceCount() != 1) {
+ return false;
+ }
+
+ Geometry *geom = m_manager->lookupResource<Geometry, GeometryManager>(renderer->geometryId());
+
+ if (!geom)
+ return false;
+
+ Attribute *attribute = nullptr;
+
+ const auto attrIds = geom->attributes();
+ for (const Qt3DCore::QNodeId attrId : attrIds) {
+ attribute = m_manager->lookupResource<Attribute, AttributeManager>(attrId);
+ if (attribute){
+ if (attribute->name() == attributeName
+ || (attributeName == QStringLiteral("default")
+ && attribute->name() == QAttribute::defaultTextureCoordinateAttributeName())) {
+ break;
+ }
+ }
+ attribute = nullptr;
+ }
+
+ if (!attribute)
+ return false;
+
+ return apply(attribute);
+ }
+
+ bool apply(Qt3DRender::Render::Attribute *attribute)
+ {
+ if (attribute->vertexBaseType() != VertexBaseType)
+ return false;
+ if (attribute->vertexSize() < dataSize)
+ return false;
+
+ auto data = m_manager->lookupResource<Buffer, BufferManager>(attribute->bufferId())->data();
+ auto buffer = BufferTypeInfo::castToType<VertexBaseType>(data, attribute->byteOffset());
+ switch (dataSize) {
+ case 1: traverseCoordinates1(buffer, attribute->byteStride(), attribute->count()); break;
+ case 2: traverseCoordinates2(buffer, attribute->byteStride(), attribute->count()); break;
+ case 3: traverseCoordinates3(buffer, attribute->byteStride(), attribute->count()); break;
+ case 4: traverseCoordinates4(buffer, attribute->byteStride(), attribute->count()); break;
+ default: Q_UNREACHABLE();
+ }
+
+ return true;
+ }
+
+protected:
+
+ template <typename Coordinate>
+ void traverseCoordinates1(Coordinate *coordinates,
+ const uint byteStride,
+ const uint count)
+ {
+ const uint stride = byteStride / sizeof(Coordinate);
+ for (uint ndx = 0; ndx < count; ++ndx) {
+ visit(ndx, coordinates[0]);
+ coordinates += stride;
+ }
+ }
+
+ template <typename Coordinate>
+ void traverseCoordinates2(Coordinate *coordinates,
+ const uint byteStride,
+ const uint count)
+ {
+ const uint stride = byteStride / sizeof(Coordinate);
+ for (uint ndx = 0; ndx < count; ++ndx) {
+ visit(ndx, coordinates[0], coordinates[1]);
+ coordinates += stride;
+ }
+ }
+
+ template <typename Coordinate>
+ void traverseCoordinates3(Coordinate *coordinates,
+ const uint byteStride,
+ const uint count)
+ {
+ const uint stride = byteStride / sizeof(Coordinate);
+ for (uint ndx = 0; ndx < count; ++ndx) {
+ visit(ndx, coordinates[0], coordinates[1], coordinates[2]);
+ coordinates += stride;
+ }
+ }
+
+ template <typename Coordinate>
+ void traverseCoordinates4(Coordinate *coordinates,
+ const uint byteStride,
+ const uint count)
+ {
+ const uint stride = byteStride / sizeof(Coordinate);
+ for (uint ndx = 0; ndx < count; ++ndx) {
+ visit(ndx, coordinates[0], coordinates[1], coordinates[2], coordinates[3]);
+ coordinates += stride;
+ }
+ }
+
+ NodeManagers *m_manager;
+};
+
+typedef BufferVisitor<float, QAttribute::Float, 3> Buffer3fVisitor;
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+
+#endif // QT3DRENDER_RENDER_BUFFERVISITOR_P_H
diff --git a/src/render/backend/cameralens.cpp b/src/render/backend/cameralens.cpp
index e60a32422..ef71507eb 100644
--- a/src/render/backend/cameralens.cpp
+++ b/src/render/backend/cameralens.cpp
@@ -39,8 +39,14 @@
#include "cameralens_p.h"
#include <Qt3DRender/qcameralens.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/qcameralens_p.h>
#include <Qt3DRender/private/renderlogging_p.h>
+#include <Qt3DRender/private/renderer_p.h>
+#include <Qt3DRender/private/entity_p.h>
+#include <Qt3DRender/private/sphere_p.h>
+#include <Qt3DRender/private/computefilteredboundingvolumejob_p.h>
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/qtransform.h>
@@ -52,8 +58,35 @@ using namespace Qt3DCore;
namespace Qt3DRender {
namespace Render {
+
+namespace {
+
+class GetBoundingVolumeWithoutCameraJob : public ComputeFilteredBoundingVolumeJob
+{
+public:
+ GetBoundingVolumeWithoutCameraJob(CameraLens *lens,
+ QNodeCommand::CommandId commandId)
+ : m_lens(lens), m_commandId(commandId)
+ {
+ }
+
+protected:
+ void finished(const Sphere &sphere) override
+ {
+ m_lens->notifySceneBoundingVolume(sphere, m_commandId);
+ }
+
+private:
+ CameraLens *m_lens;
+ QNodeCommand::CommandId m_commandId;
+};
+
+} // namespace
+
CameraLens::CameraLens()
- : BackendNode()
+ : BackendNode(QBackendNode::ReadWrite)
+ , m_renderAspect(nullptr)
+ , m_exposure(0.0f)
{
}
@@ -67,11 +100,52 @@ void CameraLens::cleanup()
QBackendNode::setEnabled(false);
}
+void CameraLens::setRenderAspect(QRenderAspect *renderAspect)
+{
+ m_renderAspect = renderAspect;
+}
+
void CameraLens::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
{
const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QCameraLensData>>(change);
const auto &data = typedChange->data;
m_projection = data.projectionMatrix;
+ m_exposure = data.exposure;
+}
+
+void CameraLens::computeSceneBoundingVolume(QNodeId entityId,
+ QNodeId cameraId,
+ QNodeCommand::CommandId commandId)
+{
+ if (!m_renderer || !m_renderAspect)
+ return;
+ NodeManagers *nodeManagers = m_renderer->nodeManagers();
+
+ Entity *root = m_renderer->sceneRoot();
+ if (!entityId.isNull())
+ root = nodeManagers->renderNodesManager()->lookupResource(entityId);
+ if (!root)
+ return;
+
+ Entity *camNode = nodeManagers->renderNodesManager()->lookupResource(cameraId);
+ ComputeFilteredBoundingVolumeJobPtr job(new GetBoundingVolumeWithoutCameraJob(this, commandId));
+ job->addDependency(m_renderer->expandBoundingVolumeJob());
+ job->setRoot(root);
+ job->ignoreSubTree(camNode);
+ m_renderAspect->scheduleSingleShotJob(job);
+}
+
+void CameraLens::notifySceneBoundingVolume(const Sphere &sphere, QNodeCommand::CommandId commandId)
+{
+ if (m_pendingViewAllCommand != commandId)
+ return;
+ if (sphere.radius() > 0.f) {
+ QVector<float> data = { sphere.center().x(), sphere.center().y(), sphere.center().z(),
+ sphere.radius() };
+ QVariant v;
+ v.setValue(data);
+ sendCommand(QLatin1Literal("ViewAll"), v, m_pendingViewAllCommand);
+ }
}
void CameraLens::setProjection(const QMatrix4x4 &projection)
@@ -79,6 +153,11 @@ void CameraLens::setProjection(const QMatrix4x4 &projection)
m_projection = projection;
}
+void CameraLens::setExposure(float exposure)
+{
+ m_exposure = exposure;
+}
+
void CameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
{
switch (e->type()) {
@@ -88,18 +167,63 @@ void CameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
if (propertyChange->propertyName() == QByteArrayLiteral("projectionMatrix")) {
QMatrix4x4 projectionMatrix = propertyChange->value().value<QMatrix4x4>();
m_projection = projectionMatrix;
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("exposure")) {
+ setExposure(propertyChange->value().toFloat());
}
markDirty(AbstractRenderer::AllDirty);
}
break;
+ case CommandRequested: {
+ QNodeCommandPtr command = qSharedPointerCast<QNodeCommand>(e);
+
+ if (command->name() == QLatin1Literal("QueryRootBoundingVolume")) {
+ m_pendingViewAllCommand = command->commandId();
+ QVariant v = command->data();
+ QNodeId id = v.value<QNodeId>();
+ computeSceneBoundingVolume({}, id, command->commandId());
+ } else if (command->name() == QLatin1Literal("QueryEntityBoundingVolume")) {
+ m_pendingViewAllCommand = command->commandId();
+ QVariant v = command->data();
+ QVector<QNodeId> ids = v.value<QVector<QNodeId>>();
+ if (ids.size() == 2)
+ computeSceneBoundingVolume(ids[0], ids[1], command->commandId());
+ }
+ }
+ break;
+
default:
break;
}
BackendNode::sceneChangeEvent(e);
}
+CameraLensFunctor::CameraLensFunctor(AbstractRenderer *renderer, QRenderAspect *renderAspect)
+ : m_manager(renderer->nodeManagers()->manager<CameraLens, CameraManager>())
+ , m_renderer(renderer)
+ , m_renderAspect(renderAspect)
+{
+}
+
+QBackendNode *CameraLensFunctor::create(const QNodeCreatedChangeBasePtr &change) const
+{
+ CameraLens *backend = m_manager->getOrCreateResource(change->subjectId());
+ backend->setRenderer(m_renderer);
+ backend->setRenderAspect(m_renderAspect);
+ return backend;
+}
+
+QBackendNode *CameraLensFunctor::get(QNodeId id) const
+{
+ return m_manager->lookupResource(id);
+}
+
+void CameraLensFunctor::destroy(QNodeId id) const
+{
+ m_manager->releaseResource(id);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/cameralens_p.h b/src/render/backend/cameralens_p.h
index e5268da53..4bf147f48 100644
--- a/src/render/backend/cameralens_p.h
+++ b/src/render/backend/cameralens_p.h
@@ -52,6 +52,7 @@
//
#include <Qt3DRender/private/backendnode_p.h>
+#include <Qt3DCore/private/qnodecommand_p.h>
#include <QMatrix4x4>
#include <QRectF>
@@ -62,6 +63,21 @@ namespace Qt3DRender {
namespace Render {
class CameraManager;
+class Sphere;
+
+class CameraLensFunctor : public Qt3DCore::QBackendNodeMapper
+{
+public:
+ explicit CameraLensFunctor(AbstractRenderer *renderer, QRenderAspect *renderAspect);
+ Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const Q_DECL_OVERRIDE;
+ Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const Q_DECL_OVERRIDE;
+ void destroy(Qt3DCore::QNodeId id) const Q_DECL_OVERRIDE;
+
+private:
+ CameraManager *m_manager;
+ AbstractRenderer *m_renderer;
+ QRenderAspect *m_renderAspect;
+};
class CameraLens : public BackendNode
{
@@ -70,15 +86,27 @@ public:
~CameraLens();
void cleanup();
+ void setRenderAspect(QRenderAspect* renderAspect);
+
void setProjection(const QMatrix4x4 &projection);
inline QMatrix4x4 projection() const { return m_projection; }
+ void setExposure(float exposure);
+ inline float exposure() const { return m_exposure; }
+
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
+ void notifySceneBoundingVolume(const Sphere &sphere, Qt3DCore::QNodeCommand::CommandId commandId);
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+ void computeSceneBoundingVolume(Qt3DCore::QNodeId entityId,
+ Qt3DCore::QNodeId cameraId,
+ Qt3DCore::QNodeCommand::CommandId commandId);
+ QRenderAspect *m_renderAspect;
QMatrix4x4 m_projection;
+ Qt3DCore::QNodeCommand::CommandId m_pendingViewAllCommand;
+ float m_exposure;
};
} // namespace Render
diff --git a/src/render/backend/commandexecuter.cpp b/src/render/backend/commandexecuter.cpp
index 2f13b27ea..84bf7455a 100644
--- a/src/render/backend/commandexecuter.cpp
+++ b/src/render/backend/commandexecuter.cpp
@@ -34,9 +34,8 @@
**
****************************************************************************/
-#ifdef QT3D_JOBS_RUN_STATS
-
#include "commandexecuter_p.h"
+
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DCore/private/qabstractaspect_p.h>
#include <Qt3DCore/qbackendnode.h>
@@ -388,5 +387,3 @@ QVariant CommandExecuter::executeCommand(const QStringList &args)
} // Qt3DRenderer
QT_END_NAMESPACE
-
-#endif
diff --git a/src/render/backend/commandexecuter_p.h b/src/render/backend/commandexecuter_p.h
index 8135d97d9..896164543 100644
--- a/src/render/backend/commandexecuter_p.h
+++ b/src/render/backend/commandexecuter_p.h
@@ -48,8 +48,6 @@
// We mean it.
//
-#ifdef QT3D_JOBS_RUN_STATS
-
#include <QVector>
#include <QVariant>
@@ -92,6 +90,4 @@ private:
QT_END_NAMESPACE
-#endif // QT3D_JOBS_RUN_STATS
-
#endif // QT3DRENDER_DEBUG_COMMANDEXECUTER_H
diff --git a/src/render/backend/commandthread.cpp b/src/render/backend/commandthread.cpp
new file mode 100644
index 000000000..f91cff017
--- /dev/null
+++ b/src/render/backend/commandthread.cpp
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "commandthread_p.h"
+#include <QOpenGLContext>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+CommandThread::CommandThread(Renderer *renderer)
+ : QThread()
+ , m_renderer(renderer)
+ , m_waitForStartSemaphore(0)
+ , m_initializedSemaphore(0)
+{
+}
+
+CommandThread::~CommandThread()
+{
+}
+
+// Called by RenderThread or MainThread (Scene3d)
+void CommandThread::initialize(QOpenGLContext *mainContext)
+{
+ // Start the thread
+ start();
+
+ // Wait for thread to be started
+ m_waitForStartSemaphore.acquire();
+
+ m_mainContext = mainContext;
+ Q_ASSERT(m_mainContext);
+
+ // Allow thread to proceed
+ m_initializedSemaphore.release();
+}
+
+// Called by RenderThread of MainThread (Scene3D)
+void CommandThread::shutdown()
+{
+ // Tell thread to exit event loop
+ QThread::quit();
+
+ // Wait for thread to exit
+ wait();
+
+ // Reset semaphores (in case we ever want to restart)
+ m_waitForStartSemaphore.release(m_waitForStartSemaphore.available());
+ m_initializedSemaphore.release(m_initializedSemaphore.available());
+ m_localContext.reset();
+}
+
+// Any thread can call this, this is a blocking command
+void CommandThread::executeCommand(Command *command)
+{
+ if (!isRunning())
+ return;
+ QMetaObject::invokeMethod(this,
+ "executeCommandInternal",
+ Qt::BlockingQueuedConnection,
+ Q_ARG(Command *, command));
+}
+
+void CommandThread::run()
+{
+ // Allow initialize to proceed
+ m_waitForStartSemaphore.release();
+
+ // Wait for initialize to be completed
+ m_initializedSemaphore.acquire();
+
+ // Initialize shared context and resources for the thread
+ m_localContext.reset(new QOpenGLContext());
+ m_localContext->setShareContext(m_mainContext);
+
+ // Launch exec loop
+ QThread::exec();
+}
+
+// Executed in the Command Thread
+void CommandThread::executeCommandInternal(Command *command)
+{
+ command->execute(m_renderer, m_localContext.data());
+}
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/commandthread_p.h b/src/render/backend/commandthread_p.h
new file mode 100644
index 000000000..1955d13ac
--- /dev/null
+++ b/src/render/backend/commandthread_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_COMMANDTHREAD_P_H
+#define QT3DRENDER_RENDER_COMMANDTHREAD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QThread>
+#include <QtCore/QSemaphore>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLContext;
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class Renderer;
+
+class Command
+{
+public:
+ virtual void execute(Renderer *renderer, QOpenGLContext *localContext) = 0;
+};
+
+class CommandThread : public QThread
+{
+ Q_OBJECT
+public:
+ explicit CommandThread(Renderer *renderer);
+ ~CommandThread();
+
+ Render::Renderer* renderer() const { return m_renderer; }
+
+ void initialize(QOpenGLContext *mainContext);
+ void shutdown();
+
+ void executeCommand(Command *command);
+
+private:
+ void run() Q_DECL_OVERRIDE;
+ Q_INVOKABLE void executeCommandInternal(Command *command);
+
+private:
+ Renderer* m_renderer;
+ QSemaphore m_waitForStartSemaphore;
+ QSemaphore m_initializedSemaphore;
+ QOpenGLContext *m_mainContext;
+ QScopedPointer<QOpenGLContext> m_localContext;
+};
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_COMMANDTHREAD_P_H
diff --git a/src/render/backend/entity.cpp b/src/render/backend/entity.cpp
index 42233c85a..898c1e36e 100644
--- a/src/render/backend/entity.cpp
+++ b/src/render/backend/entity.cpp
@@ -41,6 +41,7 @@
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/qabstractlight.h>
+#include <Qt3DRender/qenvironmentlight.h>
#include <Qt3DRender/qlayer.h>
#include <Qt3DRender/qlevelofdetail.h>
#include <Qt3DRender/qmaterial.h>
@@ -118,6 +119,7 @@ void Entity::cleanup()
m_levelOfDetailComponents.clear();
m_shaderDataComponents.clear();
m_lightComponents.clear();
+ m_environmentLightComponents.clear();
m_localBoundingVolume.reset();
m_worldBoundingVolume.reset();
m_worldBoundingVolumeWithChildren.reset();
@@ -174,6 +176,7 @@ void Entity::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
m_levelOfDetailComponents.clear();
m_shaderDataComponents.clear();
m_lightComponents.clear();
+ m_environmentLightComponents.clear();
m_localBoundingVolume.reset(new Sphere(peerId()));
m_worldBoundingVolume.reset(new Sphere(peerId()));
m_worldBoundingVolumeWithChildren.reset(new Sphere(peerId()));
@@ -293,6 +296,8 @@ void Entity::addComponent(Qt3DCore::QComponent *component)
m_materialComponent = component->id();
} else if (qobject_cast<QAbstractLight *>(component) != nullptr) {
m_lightComponents.append(component->id());
+ } else if (qobject_cast<QEnvironmentLight *>(component) != nullptr) {
+ m_environmentLightComponents.append(component->id());
} else if (qobject_cast<QShaderData *>(component) != nullptr) {
m_shaderDataComponents.append(component->id());
} else if (qobject_cast<QGeometryRenderer *>(component) != nullptr) {
@@ -326,6 +331,8 @@ void Entity::addComponent(Qt3DCore::QNodeIdTypePair idAndType)
m_materialComponent = id;
} else if (type->inherits(&QAbstractLight::staticMetaObject)) { // QAbstractLight subclasses QShaderData
m_lightComponents.append(id);
+ } else if (type->inherits(&QEnvironmentLight::staticMetaObject)) {
+ m_environmentLightComponents.append(id);
} else if (type->inherits(&QShaderData::staticMetaObject)) {
m_shaderDataComponents.append(id);
} else if (type->inherits(&QGeometryRenderer::staticMetaObject)) {
@@ -363,6 +370,8 @@ void Entity::removeComponent(Qt3DCore::QNodeId nodeId)
// m_boundingVolumeDebugComponent = QNodeId();
} else if (m_lightComponents.contains(nodeId)) {
m_lightComponents.removeAll(nodeId);
+ } else if (m_environmentLightComponents.contains(nodeId)) {
+ m_environmentLightComponents.removeAll(nodeId);
} else if (m_computeComponent == nodeId) {
m_computeComponent = QNodeId();
}
@@ -457,6 +466,16 @@ QVector<HLight> Entity::componentsHandle<Light>() const
}
template<>
+QVector<HEnvironmentLight> Entity::componentsHandle<EnvironmentLight>() const
+{
+ QVector<HEnvironmentLight> lightHandles;
+ lightHandles.reserve(m_environmentLightComponents.size());
+ for (QNodeId id : m_environmentLightComponents)
+ lightHandles.append(m_nodeManagers->environmentLightManager()->lookupHandle(id));
+ return lightHandles;
+}
+
+template<>
HComputeCommand Entity::componentHandle<ComputeCommand>() const
{
return m_nodeManagers->computeJobManager()->lookupHandle(m_computeComponent);
@@ -534,6 +553,16 @@ QVector<Light *> Entity::renderComponents<Light>() const
return lights;
}
+template<>
+QVector<EnvironmentLight *> Entity::renderComponents<EnvironmentLight>() const
+{
+ QVector<EnvironmentLight *> lights;
+ lights.reserve(m_environmentLightComponents.size());
+ for (QNodeId id : m_environmentLightComponents)
+ lights.append(m_nodeManagers->environmentLightManager()->lookupResource(id));
+ return lights;
+}
+
//template<>
//BoundingVolumeDebug *Entity::renderComponent<BoundingVolumeDebug>() const
//{
@@ -581,6 +610,9 @@ QNodeId Entity::componentUuid<ComputeCommand>() const { return m_computeComponen
template<>
QVector<Qt3DCore::QNodeId> Entity::componentsUuid<Light>() const { return m_lightComponents; }
+template<>
+QVector<Qt3DCore::QNodeId> Entity::componentsUuid<EnvironmentLight>() const { return m_environmentLightComponents; }
+
RenderEntityFunctor::RenderEntityFunctor(AbstractRenderer *renderer, NodeManagers *manager)
: m_nodeManagers(manager)
, m_renderer(renderer)
diff --git a/src/render/backend/entity_p.h b/src/render/backend/entity_p.h
index c86019444..4619314ad 100644
--- a/src/render/backend/entity_p.h
+++ b/src/render/backend/entity_p.h
@@ -190,6 +190,7 @@ private:
QVector<Qt3DCore::QNodeId> m_levelOfDetailComponents;
QVector<Qt3DCore::QNodeId> m_shaderDataComponents;
QVector<Qt3DCore::QNodeId> m_lightComponents;
+ QVector<Qt3DCore::QNodeId> m_environmentLightComponents;
Qt3DCore::QNodeId m_geometryRendererComponent;
Qt3DCore::QNodeId m_objectPickerComponent;
Qt3DCore::QNodeId m_boundingVolumeDebugComponent;
@@ -233,6 +234,9 @@ template<>
QVector<HLight> Entity::componentsHandle<Light>() const;
template<>
+QVector<HEnvironmentLight> Entity::componentsHandle<EnvironmentLight>() const;
+
+template<>
Q_AUTOTEST_EXPORT HComputeCommand Entity::componentHandle<ComputeCommand>() const;
// Render components
@@ -246,10 +250,10 @@ template<>
Transform *Entity::renderComponent<Transform>() const;
template<>
-Q_AUTOTEST_EXPORT GeometryRenderer *Entity::renderComponent<GeometryRenderer>() const;
+QT3DRENDERSHARED_PRIVATE_EXPORT GeometryRenderer *Entity::renderComponent<GeometryRenderer>() const;
template<>
-Q_AUTOTEST_EXPORT ObjectPicker *Entity::renderComponent<ObjectPicker>() const;
+QT3DRENDERSHARED_PRIVATE_EXPORT ObjectPicker *Entity::renderComponent<ObjectPicker>() const;
template<>
QVector<Layer *> Entity::renderComponents<Layer>() const;
@@ -267,6 +271,9 @@ template<>
QVector<Light *> Entity::renderComponents<Light>() const;
template<>
+QVector<EnvironmentLight *> Entity::renderComponents<EnvironmentLight>() const;
+
+template<>
Q_AUTOTEST_EXPORT ComputeCommand *Entity::renderComponent<ComputeCommand>() const;
// UUid
@@ -289,10 +296,10 @@ template<>
Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<ShaderData>() const;
template<>
-Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<GeometryRenderer>() const;
+QT3DRENDERSHARED_PRIVATE_EXPORT Qt3DCore::QNodeId Entity::componentUuid<GeometryRenderer>() const;
template<>
-Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<ObjectPicker>() const;
+QT3DRENDERSHARED_PRIVATE_EXPORT Qt3DCore::QNodeId Entity::componentUuid<ObjectPicker>() const;
//template<>
//Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<BoundingVolumeDebug>() const;
@@ -303,6 +310,9 @@ Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<ComputeCommand>() cons
template<>
Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<Light>() const;
+template<>
+Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<EnvironmentLight>() const;
+
class RenderEntityFunctor : public Qt3DCore::QBackendNodeMapper
{
public:
diff --git a/src/render/backend/frameprofiler_p.h b/src/render/backend/frameprofiler_p.h
index 2412a8053..9e7bcd038 100644
--- a/src/render/backend/frameprofiler_p.h
+++ b/src/render/backend/frameprofiler_p.h
@@ -69,7 +69,7 @@ enum RecordingType
RenderTargetUpdate
};
-#ifdef QT3D_JOBS_RUN_STATS
+#ifdef QT3D_OPENGL_RUN_STATS
class FrameTimeRecorder
{
@@ -218,33 +218,35 @@ public:
explicit GLTimeRecorder(RecordingType type)
: m_type(type)
{
-#ifdef QT3D_JOBS_RUN_STATS
+#ifdef QT3D_OPENGL_RUN_STATS
frameProfiler.startRecordEvent();
#endif
}
~GLTimeRecorder()
{
-#ifdef QT3D_JOBS_RUN_STATS
+#ifdef QT3D_OPENGL_RUN_STATS
frameProfiler.recordEvent(m_type);
+#else
+ Q_UNUSED(m_type);
#endif
}
static void writeResults()
{
-#ifdef QT3D_JOBS_RUN_STATS
+#ifdef QT3D_OPENGL_RUN_STATS
frameProfiler.writeResults();
#endif
}
private:
-#ifdef QT3D_JOBS_RUN_STATS
+#ifdef QT3D_OPENGL_RUN_STATS
static FrameProfiler frameProfiler;
#endif
RecordingType m_type;
};
-#ifdef QT3D_JOBS_RUN_STATS
+#ifdef QT3D_OPENGL_RUN_STATS
FrameProfiler GLTimeRecorder::frameProfiler;
#endif
diff --git a/src/render/backend/handle_types_p.h b/src/render/backend/handle_types_p.h
index c8c73b749..352519e75 100644
--- a/src/render/backend/handle_types_p.h
+++ b/src/render/backend/handle_types_p.h
@@ -90,6 +90,7 @@ class ObjectPicker;
class BoundingVolumeDebug;
class OpenGLVertexArrayObject;
class Light;
+class EnvironmentLight;
class ComputeCommand;
class GLBuffer;
class RenderStateNode;
@@ -122,6 +123,7 @@ typedef Qt3DCore::QHandle<GeometryRenderer, 16> HGeometryRenderer;
typedef Qt3DCore::QHandle<ObjectPicker, 16> HObjectPicker;
typedef Qt3DCore::QHandle<BoundingVolumeDebug, 16> HBoundingVolumeDebug;
typedef Qt3DCore::QHandle<Light, 16> HLight;
+typedef Qt3DCore::QHandle<EnvironmentLight, 16> HEnvironmentLight;
typedef Qt3DCore::QHandle<ComputeCommand, 16> HComputeCommand;
typedef Qt3DCore::QHandle<GLBuffer, 16> HGLBuffer;
typedef Qt3DCore::QHandle<RenderStateNode, 16> HRenderState;
diff --git a/src/render/backend/levelofdetail.cpp b/src/render/backend/levelofdetail.cpp
index 474133d1c..157bfc004 100644
--- a/src/render/backend/levelofdetail.cpp
+++ b/src/render/backend/levelofdetail.cpp
@@ -39,11 +39,9 @@
#include "levelofdetail_p.h"
#include <Qt3DRender/QLevelOfDetail>
-#include <Qt3DRender/QBoundingSphere>
#include <Qt3DRender/private/qlevelofdetail_p.h>
#include <Qt3DRender/private/stringtoint_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
#include <QVariant>
QT_BEGIN_NAMESPACE
@@ -56,8 +54,8 @@ namespace Render {
LevelOfDetail::LevelOfDetail()
: BackendNode(BackendNode::ReadWrite)
, m_currentIndex(0)
- , m_thresholdType(QLevelOfDetail::DistanceToCamera)
- , m_radius(1.f)
+ , m_thresholdType(QLevelOfDetail::DistanceToCameraThreshold)
+ , m_volumeOverride()
{
}
@@ -74,8 +72,7 @@ void LevelOfDetail::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
m_currentIndex = data.currentIndex;
m_thresholdType = data.thresholdType;
m_thresholds = data.thresholds;
- m_radius = data.radius;
- m_center = data.center;
+ m_volumeOverride = data.volumeOverride;
}
void LevelOfDetail::cleanup()
@@ -87,23 +84,16 @@ void LevelOfDetail::sceneChangeEvent(const QSceneChangePtr &e)
{
if (e->type() == PropertyUpdated) {
const QPropertyUpdatedChangePtr &propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("currentIndex")) {
+ if (propertyChange->propertyName() == QByteArrayLiteral("currentIndex"))
m_currentIndex = propertyChange->value().value<int>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("camera")) {
+ else if (propertyChange->propertyName() == QByteArrayLiteral("camera"))
m_camera = propertyChange->value().value<Qt3DCore::QNodeId>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("thresholdType")) {
+ else if (propertyChange->propertyName() == QByteArrayLiteral("thresholdType"))
m_thresholdType = propertyChange->value().value<QLevelOfDetail::ThresholdType>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("thresholds")) {
+ else if (propertyChange->propertyName() == QByteArrayLiteral("thresholds"))
m_thresholds = propertyChange->value().value<QVector<qreal>>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("center")) {
- m_center = propertyChange->value().value<QVector3D>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("radius")) {
- m_radius = propertyChange->value().value<float>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("volumeOverride")) {
- auto volumeOverride = propertyChange->value().value<Qt3DRender::QBoundingSphere*>();
- m_center = volumeOverride ? volumeOverride->center() : QVector3D();
- m_radius = volumeOverride ? volumeOverride->radius() : -1.f;
- }
+ else if (propertyChange->propertyName() == QByteArrayLiteral("volumeOverride"))
+ m_volumeOverride = propertyChange->value().value<Qt3DRender::QLevelOfDetailBoundingSphere>();
}
markDirty(AbstractRenderer::GeometryDirty);
@@ -119,7 +109,6 @@ void LevelOfDetail::setCurrentIndex(int currentIndex)
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("currentIndex");
e->setValue(m_currentIndex);
- Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true;
notifyObservers(e);
}
}
diff --git a/src/render/backend/levelofdetail_p.h b/src/render/backend/levelofdetail_p.h
index 83809a631..05f5686bb 100644
--- a/src/render/backend/levelofdetail_p.h
+++ b/src/render/backend/levelofdetail_p.h
@@ -79,8 +79,9 @@ public:
int currentIndex() const { return m_currentIndex; }
QLevelOfDetail::ThresholdType thresholdType() const { return m_thresholdType; }
QVector<qreal> thresholds() const { return m_thresholds; }
- float radius() const { return m_radius; }
- QVector3D center() const { return m_center; }
+ float radius() const { return m_volumeOverride.radius(); }
+ QVector3D center() const { return m_volumeOverride.center(); }
+ bool hasBoundingVolumeOverride() const { return !m_volumeOverride.isEmpty(); }
void setCurrentIndex(int currentIndex);
@@ -90,8 +91,7 @@ private:
int m_currentIndex;
QLevelOfDetail::ThresholdType m_thresholdType;
QVector<qreal> m_thresholds;
- float m_radius;
- QVector3D m_center;
+ QLevelOfDetailBoundingSphere m_volumeOverride;
};
} // namespace Render
diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h
index ce6767958..1c1a34b83 100644
--- a/src/render/backend/managers_p.h
+++ b/src/render/backend/managers_p.h
@@ -77,6 +77,7 @@
#include <Qt3DRender/private/boundingvolumedebug_p.h>
#include <Qt3DRender/private/openglvertexarrayobject_p.h>
#include <Qt3DRender/private/light_p.h>
+#include <Qt3DRender/private/environmentlight_p.h>
#include <Qt3DRender/private/computecommand_p.h>
QT_BEGIN_NAMESPACE
@@ -260,7 +261,7 @@ public:
class VAOManager : public Qt3DCore::QResourceManager<
OpenGLVertexArrayObject,
- QPair<HGeometry, HShader>,
+ VAOIdentifier,
16,
Qt3DCore::ArrayAllocatingPolicy,
Qt3DCore::NonLockingPolicy>
@@ -381,6 +382,17 @@ public:
LightManager() {}
};
+class EnvironmentLightManager : public Qt3DCore::QResourceManager<
+ EnvironmentLight,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::ArrayAllocatingPolicy,
+ Qt3DCore::NonLockingPolicy>
+{
+public:
+ EnvironmentLightManager() {}
+};
+
class ComputeCommandManager : public Qt3DCore::QResourceManager<
ComputeCommand,
Qt3DCore::QNodeId,
@@ -422,6 +434,7 @@ Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::BoundingVolumeDebug, Q_REQUIRES_CLEA
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::ComputeCommand, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Parameter, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Transform, Q_REQUIRES_CLEANUP)
+Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::OpenGLVertexArrayObject, Q_REQUIRES_CLEANUP)
QT_END_NAMESPACE
diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp
index d83623ce2..2647bbb1a 100644
--- a/src/render/backend/nodemanagers.cpp
+++ b/src/render/backend/nodemanagers.cpp
@@ -46,6 +46,7 @@
#include <Qt3DRender/private/texturedatamanager_p.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
#include <Qt3DRender/private/techniquemanager_p.h>
+#include <private/resourceaccessor_p.h>
#include <QOpenGLVertexArrayObject>
@@ -88,8 +89,10 @@ NodeManagers::NodeManagers()
, m_objectPickerManager(new ObjectPickerManager())
// , m_boundingVolumeDebugManager(new BoundingVolumeDebugManager())
, m_lightManager(new LightManager())
+ , m_environmentLightManager(new EnvironmentLightManager())
, m_computeJobManager(new ComputeCommandManager())
, m_renderStateManager(new RenderStateManager())
+ , m_resourceAccessor(new ResourceAccessor(this))
{
}
@@ -126,11 +129,17 @@ NodeManagers::~NodeManagers()
delete m_objectPickerManager;
// delete m_boundingVolumeDebugManager;
delete m_lightManager;
+ delete m_environmentLightManager;
delete m_computeJobManager;
delete m_renderStateManager;
delete m_renderNodesManager;
}
+QSharedPointer<ResourceAccessor> NodeManagers::resourceAccessor()
+{
+ return m_resourceAccessor;
+}
+
template<>
CameraManager *NodeManagers::manager<CameraLens>() const Q_DECL_NOTHROW
{
@@ -312,6 +321,12 @@ LightManager *NodeManagers::manager<Light>() const Q_DECL_NOTHROW
}
template<>
+EnvironmentLightManager *NodeManagers::manager<EnvironmentLight>() const Q_DECL_NOTHROW
+{
+ return m_environmentLightManager;
+}
+
+template<>
ComputeCommandManager *NodeManagers::manager<ComputeCommand>() const Q_DECL_NOTHROW
{
return m_computeJobManager;
diff --git a/src/render/backend/nodemanagers_p.h b/src/render/backend/nodemanagers_p.h
index b1ea2a0de..9e913eec4 100644
--- a/src/render/backend/nodemanagers_p.h
+++ b/src/render/backend/nodemanagers_p.h
@@ -96,6 +96,7 @@ class TextureImageDataManager;
class LayerManager;
class LevelOfDetailManager;
class LightManager;
+class EnvironmentLightManager;
class ComputeCommandManager;
class RenderStateManager;
@@ -127,10 +128,13 @@ class GeometryRenderer;
class ObjectPicker;
//class BoundingVolumeDebug;
class Light;
+class EnvironmentLight;
class ComputeCommand;
class RenderStateNode;
class OpenGLVertexArrayObject;
+class ResourceAccessor;
+
class QT3DRENDERSHARED_PRIVATE_EXPORT NodeManagers
{
public:
@@ -203,9 +207,12 @@ public:
inline ObjectPickerManager *objectPickerManager() const Q_DECL_NOEXCEPT { return m_objectPickerManager; }
// inline BoundingVolumeDebugManager *boundingVolumeDebugManager() const Q_DECL_NOEXCEPT { return m_boundingVolumeDebugManager; }
inline LightManager *lightManager() const Q_DECL_NOEXCEPT { return m_lightManager; }
+ inline EnvironmentLightManager *environmentLightManager() const Q_DECL_NOEXCEPT { return m_environmentLightManager; }
inline ComputeCommandManager *computeJobManager() const Q_DECL_NOEXCEPT { return m_computeJobManager; }
inline RenderStateManager *renderStateManager() const Q_DECL_NOEXCEPT { return m_renderStateManager; }
+ QSharedPointer<ResourceAccessor> resourceAccessor();
+
private:
CameraManager *m_cameraManager;
EntityManager *m_renderNodesManager;
@@ -239,8 +246,11 @@ private:
ObjectPickerManager *m_objectPickerManager;
// BoundingVolumeDebugManager *m_boundingVolumeDebugManager;
LightManager *m_lightManager;
+ EnvironmentLightManager *m_environmentLightManager;
ComputeCommandManager *m_computeJobManager;
RenderStateManager *m_renderStateManager;
+
+ QSharedPointer<ResourceAccessor> m_resourceAccessor;
};
// Specializations
@@ -336,6 +346,9 @@ template<>
LightManager *NodeManagers::manager<Light>() const Q_DECL_NOEXCEPT;
template<>
+EnvironmentLightManager *NodeManagers::manager<EnvironmentLight>() const Q_DECL_NOEXCEPT;
+
+template<>
QT3DRENDERSHARED_PRIVATE_EXPORT ComputeCommandManager *NodeManagers::manager<ComputeCommand>() const Q_DECL_NOEXCEPT;
template<>
diff --git a/src/render/backend/openglvertexarrayobject.cpp b/src/render/backend/openglvertexarrayobject.cpp
index 6120c7233..eefc208d5 100644
--- a/src/render/backend/openglvertexarrayobject.cpp
+++ b/src/render/backend/openglvertexarrayobject.cpp
@@ -52,15 +52,8 @@ OpenGLVertexArrayObject::OpenGLVertexArrayObject()
: m_ctx(nullptr)
, m_specified(false)
, m_supportsVao(false)
- , m_createdEmulatedVAO(false)
{}
-void OpenGLVertexArrayObject::setGraphicsContext(GraphicsContext *ctx)
-{
- m_ctx = ctx;
- m_supportsVao = m_ctx->supportsVAO();
-}
-
void OpenGLVertexArrayObject::bind()
{
Q_ASSERT(m_ctx);
@@ -75,7 +68,7 @@ void OpenGLVertexArrayObject::bind()
m_ctx->m_currentVAO = this;
// We need to specify array and vertex attributes
- for (const GraphicsContext::VAOVertexAttribute &attr : m_vertexAttributes)
+ for (const GraphicsContext::VAOVertexAttribute &attr : qAsConst(m_vertexAttributes))
m_ctx->enableAttribute(attr);
if (!m_indexAttribute.isNull())
m_ctx->bindGLBuffer(m_ctx->m_renderer->nodeManagers()->glBufferManager()->data(m_indexAttribute),
@@ -92,44 +85,58 @@ void OpenGLVertexArrayObject::release()
m_vao->release();
} else {
if (m_ctx->m_currentVAO == this) {
- for (const GraphicsContext::VAOVertexAttribute &attr : m_vertexAttributes)
+ for (const GraphicsContext::VAOVertexAttribute &attr : qAsConst(m_vertexAttributes))
m_ctx->disableAttribute(attr);
m_ctx->m_currentVAO = nullptr;
}
}
}
-void OpenGLVertexArrayObject::create()
+// called from Render thread
+void OpenGLVertexArrayObject::create(GraphicsContext *ctx, const VAOIdentifier &key)
{
- Q_ASSERT(m_ctx);
- if (m_supportsVao) {
- Q_ASSERT(!m_vao.isNull());
- m_vao->create();
- } else {
- m_createdEmulatedVAO = true;
- }
+ QMutexLocker lock(&m_mutex);
+
+ Q_ASSERT(!m_ctx && !m_vao);
+
+ m_ctx = ctx;
+ m_supportsVao = m_ctx->supportsVAO();
+ m_vao.reset(m_supportsVao ? new QOpenGLVertexArrayObject() : nullptr);
+ m_vao->create();
+ m_owners = key;
}
+// called from Render thread
void OpenGLVertexArrayObject::destroy()
{
+ QMutexLocker locker(&m_mutex);
+
Q_ASSERT(m_ctx);
- if (m_supportsVao) {
- Q_ASSERT(!m_vao.isNull());
- m_vao->destroy();
- }
+ cleanup();
+}
+
+void OpenGLVertexArrayObject::cleanup()
+{
+ m_vao.reset();
+ m_ctx = nullptr;
m_specified = false;
+ m_supportsVao = false;
m_indexAttribute = GraphicsContext::VAOIndexAttribute();
m_vertexAttributes.clear();
}
-bool OpenGLVertexArrayObject::isCreated() const
+// called from job
+bool OpenGLVertexArrayObject::isAbandoned(GeometryManager *geomMgr, ShaderManager *shaderMgr)
{
- if (m_supportsVao) {
- Q_ASSERT(!m_vao.isNull());
- return m_vao->isCreated();
- } else {
- return m_createdEmulatedVAO;
- }
+ QMutexLocker lock(&m_mutex);
+
+ if (!m_ctx)
+ return false;
+
+ const bool geometryExists = (geomMgr->data(m_owners.first) != nullptr);
+ const bool shaderExists = (shaderMgr->data(m_owners.second) != nullptr);
+
+ return !geometryExists || !shaderExists;
}
void OpenGLVertexArrayObject::saveVertexAttribute(const GraphicsContext::VAOVertexAttribute &attr)
diff --git a/src/render/backend/openglvertexarrayobject_p.h b/src/render/backend/openglvertexarrayobject_p.h
index 4f21497f0..a564175f6 100644
--- a/src/render/backend/openglvertexarrayobject_p.h
+++ b/src/render/backend/openglvertexarrayobject_p.h
@@ -59,31 +59,39 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
namespace Render {
+class GeometryManager;
+class ShaderManager;
+
+typedef QPair<HGeometry, HShader> VAOIdentifier;
+
class OpenGLVertexArrayObject
{
public:
OpenGLVertexArrayObject();
- void setGraphicsContext(GraphicsContext *ctx);
void bind();
void release();
- void create();
+
+ void create(GraphicsContext *ctx, const VAOIdentifier &key);
void destroy();
- bool isCreated() const;
+ void cleanup();
+
+ bool isAbandoned(GeometryManager *geomMgr, ShaderManager *shaderMgr);
QOpenGLVertexArrayObject *vao() { return m_vao.data(); }
const QOpenGLVertexArrayObject *vao() const { return m_vao.data(); }
- void setVao(QOpenGLVertexArrayObject *vao) { m_vao.reset(vao); }
void setSpecified(bool b) { m_specified = b; }
bool isSpecified() const { return m_specified; }
+
private:
+ QMutex m_mutex;
GraphicsContext *m_ctx;
QScopedPointer<QOpenGLVertexArrayObject> m_vao;
bool m_specified;
bool m_supportsVao;
- bool m_createdEmulatedVAO;
+ VAOIdentifier m_owners;
friend class GraphicsContext;
diff --git a/src/render/backend/platformsurfacefilter.cpp b/src/render/backend/platformsurfacefilter.cpp
index 891e30c44..7458f607d 100644
--- a/src/render/backend/platformsurfacefilter.cpp
+++ b/src/render/backend/platformsurfacefilter.cpp
@@ -107,6 +107,10 @@ bool PlatformSurfaceFilter::eventFilter(QObject *obj, QEvent *e)
// If we remove it, the call to isSurfaceValid will
// implicitely return false
PlatformSurfaceFilter::m_surfacesValidity.remove(m_surface);
+ if (m_obj) {
+ m_obj->removeEventFilter(this);
+ m_obj = nullptr;
+ }
break;
}
diff --git a/src/render/backend/platformsurfacefilter_p.h b/src/render/backend/platformsurfacefilter_p.h
index ec10327fe..dbdc07b01 100644
--- a/src/render/backend/platformsurfacefilter_p.h
+++ b/src/render/backend/platformsurfacefilter_p.h
@@ -51,6 +51,8 @@
// We mean it.
//
+#include <private/qt3drender_global_p.h>
+
#include <QtCore/qobject.h>
#include <QtGui/qsurface.h>
#include <QSemaphore>
@@ -106,7 +108,7 @@ private:
void markSurfaceAsValid();
};
-class SurfaceLocker
+class QT3DRENDERSHARED_PRIVATE_EXPORT SurfaceLocker
{
public:
explicit SurfaceLocker(QSurface *surface);
diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri
index 93e323caa..5d515a173 100644
--- a/src/render/backend/render-backend.pri
+++ b/src/render/backend/render-backend.pri
@@ -1,6 +1,3 @@
-#DEFINES += QT3D_RENDER_VIEW_JOB_TIMING
-#DEFINES += QT3D_RENDER_DUMP_BACKEND_NODES
-
INCLUDEPATH += $$PWD
HEADERS += \
@@ -29,6 +26,8 @@ HEADERS += \
$$PWD/triangleboundingvolume_p.h \
$$PWD/openglvertexarrayobject_p.h \
$$PWD/trianglesextractor_p.h \
+ $$PWD/buffervisitor_p.h \
+ $$PWD/bufferutils_p.h \
$$PWD/trianglesvisitor_p.h \
$$PWD/abstractrenderer_p.h \
$$PWD/computecommand_p.h \
@@ -36,12 +35,13 @@ HEADERS += \
$$PWD/stringtoint_p.h \
$$PWD/backendnode_p.h \
$$PWD/rendertargetoutput_p.h \
- $$PWD/commandexecuter_p.h \
$$PWD/uniform_p.h \
$$PWD/shaderparameterpack_p.h \
$$PWD/renderviewbuilder_p.h \
$$PWD/frameprofiler_p.h \
- $$PWD/offscreensurfacehelper_p.h
+ $$PWD/offscreensurfacehelper_p.h \
+ $$PWD/resourceaccessor_p.h \
+ $$PWD/commandthread_p.h
SOURCES += \
$$PWD/renderthread.cpp \
@@ -70,10 +70,18 @@ SOURCES += \
$$PWD/backendnode.cpp \
$$PWD/rendertargetoutput.cpp \
$$PWD/attachmentpack.cpp \
- $$PWD/commandexecuter.cpp \
$$PWD/openglvertexarrayobject.cpp \
$$PWD/uniform.cpp \
$$PWD/shaderparameterpack.cpp \
$$PWD/renderviewbuilder.cpp \
- $$PWD/offscreensurfacehelper.cpp
+ $$PWD/offscreensurfacehelper.cpp \
+ $$PWD/resourceaccessor.cpp \
+ $$PWD/commandthread.cpp
+
+include($$OUT_PWD/../core/qt3dcore-config.pri)
+QT_FOR_CONFIG += 3dcore-private
+qtConfig(qt3d-profile-jobs): {
+ HEADERS += $$PWD/commandexecuter_p.h
+ SOURCES += $$PWD/commandexecuter.cpp
+}
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp
index af73b1ae5..b89f21522 100644
--- a/src/render/backend/renderer.cpp
+++ b/src/render/backend/renderer.cpp
@@ -68,6 +68,7 @@
#include <Qt3DRender/private/technique_p.h>
#include <Qt3DRender/private/renderthread_p.h>
#include <Qt3DRender/private/renderview_p.h>
+#include <Qt3DRender/private/scenemanager_p.h>
#include <Qt3DRender/private/techniquefilternode_p.h>
#include <Qt3DRender/private/viewportnode_p.h>
#include <Qt3DRender/private/vsyncframeadvanceservice_p.h>
@@ -84,13 +85,19 @@
#include <Qt3DRender/private/loadbufferjob_p.h>
#include <Qt3DRender/private/rendercapture_p.h>
#include <Qt3DRender/private/updatelevelofdetailjob_p.h>
+#include <Qt3DRender/private/buffercapture_p.h>
#include <Qt3DRender/private/offscreensurfacehelper_p.h>
+#include <Qt3DRender/private/renderviewbuilder_p.h>
#include <Qt3DRender/qcameralens.h>
+#include <Qt3DCore/qt3dcore-config.h>
#include <Qt3DCore/private/qeventfilterservice_p.h>
#include <Qt3DCore/private/qabstractaspectjobmanager_p.h>
#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+
+#if defined(QT3D_JOBS_RUN_STATS)
#include <Qt3DCore/private/aspectcommanddebugger_p.h>
+#endif
#include <QStack>
#include <QOffscreenSurface>
@@ -146,6 +153,7 @@ namespace Render {
Renderer::Renderer(QRenderAspect::RenderType type)
: m_services(nullptr)
, m_nodesManager(nullptr)
+ , m_renderSceneRoot(nullptr)
, m_defaultRenderStateSet(nullptr)
, m_graphicsContext(nullptr)
, m_renderQueue(new RenderQueue())
@@ -157,6 +165,7 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_changeSet(0)
, m_lastFrameCorrect(0)
, m_glContext(nullptr)
+ , m_shareContext(nullptr)
, m_pickBoundingVolumeJob(PickBoundingVolumeJobPtr::create())
, m_time(0)
, m_settings(nullptr)
@@ -168,10 +177,12 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_updateWorldBoundingVolumeJob(Render::UpdateWorldBoundingVolumeJobPtr::create())
, m_updateTreeEnabledJob(Render::UpdateTreeEnabledJobPtr::create())
, m_sendRenderCaptureJob(Render::SendRenderCaptureJobPtr::create(this))
+ , m_sendBufferCaptureJob(Render::SendBufferCaptureJobPtr::create())
, m_updateLevelOfDetailJob(Render::UpdateLevelOfDetailJobPtr::create())
, m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create())
, m_filterCompatibleTechniqueJob(Render::FilterCompatibleTechniqueJobPtr::create())
, m_bufferGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering))
+ , m_vaoGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForAbandonedVaos(); }, JobTypes::DirtyVaoGathering))
, m_textureGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering))
, m_shaderGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyShaders(); }, JobTypes::DirtyShaderGathering))
, m_syncTextureLoadingJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([] {}, JobTypes::SyncTextureLoading))
@@ -263,16 +274,35 @@ void Renderer::setNodeManagers(NodeManagers *managers)
m_pickBoundingVolumeJob->setManagers(m_nodesManager);
m_updateWorldBoundingVolumeJob->setManager(m_nodesManager->renderNodesManager());
m_sendRenderCaptureJob->setManagers(m_nodesManager);
+ m_sendBufferCaptureJob->setManagers(m_nodesManager);
m_updateLevelOfDetailJob->setManagers(m_nodesManager);
m_updateMeshTriangleListJob->setManagers(m_nodesManager);
m_filterCompatibleTechniqueJob->setManager(m_nodesManager->techniqueManager());
}
+void Renderer::setServices(QServiceLocator *services)
+{
+ m_services = services;
+
+ m_nodesManager->sceneManager()->setDownloadService(m_services->downloadHelperService());
+}
+
NodeManagers *Renderer::nodeManagers() const
{
return m_nodesManager;
}
+/*!
+ \internal
+
+ Return context which can be used to share resources safely
+ with qt3d main render context.
+*/
+QOpenGLContext *Renderer::shareContext() const
+{
+ return m_shareContext ? m_shareContext : m_graphicsContext->openGLContext();
+}
+
void Renderer::setOpenGLContext(QOpenGLContext *context)
{
m_glContext = context;
@@ -314,6 +344,10 @@ void Renderer::initialize()
// Context is not owned by us, so we need to know if it gets destroyed
m_contextConnection = QObject::connect(m_glContext, &QOpenGLContext::aboutToBeDestroyed,
[this] { releaseGraphicsResources(); });
+ m_shareContext = new QOpenGLContext;
+ m_shareContext->setFormat(m_glContext->format());
+ m_shareContext->setShareContext(m_glContext);
+ m_shareContext->create();
}
// Note: we don't have a surface at this point
@@ -358,6 +392,7 @@ void Renderer::shutdown()
// to be ready. The isReadyToSubmit() function checks for a shutdown
// having been requested.
m_submitRenderViewsSemaphore.release(1);
+ m_renderThread->wait();
}
}
@@ -405,6 +440,13 @@ void Renderer::releaseGraphicsResources()
buffer->destroy(m_graphicsContext.data());
}
+ // Do the same thing with VAOs
+ const QVector<HVao> activeVaos = m_nodesManager->vaoManager()->activeHandles();
+ for (const HVao &vaoHandle : activeVaos) {
+ OpenGLVertexArrayObject *vao = m_nodesManager->vaoManager()->data(vaoHandle);
+ vao->destroy();
+ }
+
context->doneCurrent();
} else {
qWarning() << "Failed to make context current: OpenGL resources will not be destroyed";
@@ -412,6 +454,8 @@ void Renderer::releaseGraphicsResources()
if (m_ownedContext)
delete context;
+ if (m_shareContext)
+ delete m_shareContext;
m_graphicsContext.reset(nullptr);
qCDebug(Backend) << Q_FUNC_INFO << "Renderer properly shutdown";
@@ -500,17 +544,26 @@ void Renderer::render()
void Renderer::doRender()
{
- bool submissionSucceeded = false;
- bool hasCleanedQueueAndProceeded = false;
Renderer::ViewSubmissionResultData submissionData;
+ bool hasCleanedQueueAndProceeded = false;
bool preprocessingComplete = false;
-
- if (isReadyToSubmit()) {
-
- // Lock the mutex to protect access to m_surface and check if we are still set
- // to the running state and that we have a valid surface on which to draw
- // TO DO: Is that still needed given the surface changes
- QMutexLocker locker(&m_mutex);
+ bool beganDrawing = false;
+ const bool canSubmit = isReadyToSubmit();
+
+ // Lock the mutex to protect access to the renderQueue while we look for its state
+ QMutexLocker locker(&m_renderQueueMutex);
+ const bool queueIsComplete = m_renderQueue->isFrameQueueComplete();
+ const bool queueIsEmpty = m_renderQueue->targetRenderViewCount() == 0;
+
+ // When using synchronous rendering (QtQuick)
+ // We are not sure that the frame queue is actually complete
+ // Since a call to render may not be synched with the completions
+ // of the RenderViewJobs
+ // In such a case we return early, waiting for a next call with
+ // the frame queue complete at this point
+
+ // RenderQueue is complete (but that means it may be of size 0)
+ if (canSubmit && (queueIsComplete && !queueIsEmpty)) {
const QVector<Render::RenderView *> renderViews = m_renderQueue->nextFrameQueue();
#ifdef QT3D_JOBS_RUN_STATS
@@ -525,8 +578,7 @@ void Renderer::doRender()
submissionStatsPart2.jobId.typeAndInstance[1] = 0;
submissionStatsPart2.threadId = reinterpret_cast<quint64>(QThread::currentThreadId());
#endif
-
- if (canRender() && (submissionSucceeded = renderViews.size() > 0) == true) {
+ if (canRender()) {
// Clear all dirty flags but Compute so that
// we still render every frame when a compute shader is used in a scene
BackendNodeDirtySet changesToUnset = m_changeSet;
@@ -548,7 +600,8 @@ void Renderer::doRender()
// Reset state for each draw if we don't have complete control of the context
if (!m_ownedContext)
m_graphicsContext->setCurrentStateSet(nullptr);
- if (m_graphicsContext->beginDrawing(surface)) {
+ beganDrawing = m_graphicsContext->beginDrawing(surface);
+ if (beganDrawing) {
// 1) Execute commands for buffer uploads, texture updates, shader loading first
updateGLResources();
// 2) Update VAO and copy data into commands to allow concurrent submission
@@ -559,6 +612,7 @@ void Renderer::doRender()
}
// 2) Proceed to next frame and start preparing frame n + 1
m_renderQueue->reset();
+ locker.unlock(); // Done protecting RenderQueue
m_vsyncFrameAdvanceService->proceedToNextFrame();
hasCleanedQueueAndProceeded = true;
@@ -602,61 +656,57 @@ void Renderer::doRender()
#endif
}
- // Note: submissionSucceeded is false when
- // * we cannot render because a shutdown has been scheduled
- // * the renderqueue is incomplete (only when rendering with a Scene3D)
- // Otherwise returns true even for cases like
- // * No render view
- // * No surface set
- // * OpenGLContext failed to be set current
- // This behavior is important as we need to
- // call proceedToNextFrame despite rendering errors that aren't fatal
-
// Only reset renderQueue and proceed to next frame if the submission
- // succeeded or it we are using a render thread and that is wasn't performed
+ // succeeded or if we are using a render thread and that is wasn't performed
// already
- // If submissionSucceeded isn't true this implies that something went wrong
+ // If hasCleanedQueueAndProceeded isn't true this implies that something went wrong
// with the rendering and/or the renderqueue is incomplete from some reason
// (in the case of scene3d the render jobs may be taking too long ....)
- if (m_renderThread || submissionSucceeded) {
-
- if (!hasCleanedQueueAndProceeded) {
- // Reset the m_renderQueue so that we won't try to render
- // with a queue used by a previous frame with corrupted content
- // if the current queue was correctly submitted
- m_renderQueue->reset();
-
- // We allow the RenderTickClock service to proceed to the next frame
- // In turn this will allow the aspect manager to request a new set of jobs
- // to be performed for each aspect
- m_vsyncFrameAdvanceService->proceedToNextFrame();
- }
+ // or alternatively it could be complete but empty (RenderQueue of size 0)
+ if (!hasCleanedQueueAndProceeded &&
+ (m_renderThread || queueIsComplete || queueIsEmpty)) {
+ // RenderQueue was full but something bad happened when
+ // trying to render it and therefore proceedToNextFrame was not called
+ // Note: in this case the renderQueue mutex is still locked
+
+ // Reset the m_renderQueue so that we won't try to render
+ // with a queue used by a previous frame with corrupted content
+ // if the current queue was correctly submitted
+ m_renderQueue->reset();
+
+ // We allow the RenderTickClock service to proceed to the next frame
+ // In turn this will allow the aspect manager to request a new set of jobs
+ // to be performed for each aspect
+ m_vsyncFrameAdvanceService->proceedToNextFrame();
+ }
- // Perform the last swapBuffers calls after the proceedToNextFrame
- // as this allows us to gain a bit of time for the preparation of the
- // next frame
+ // Perform the last swapBuffers calls after the proceedToNextFrame
+ // as this allows us to gain a bit of time for the preparation of the
+ // next frame
+ // Finish up with last surface used in the list of RenderViews
+ if (beganDrawing) {
+ SurfaceLocker surfaceLock(submissionData.surface);
// Finish up with last surface used in the list of RenderViews
- if (submissionSucceeded) {
- SurfaceLocker surfaceLock(submissionData.surface);
- // Finish up with last surface used in the list of RenderViews
- m_graphicsContext->endDrawing(submissionData.lastBoundFBOId == m_graphicsContext->defaultFBO() && surfaceLock.isSurfaceValid());
- }
+ m_graphicsContext->endDrawing(submissionData.lastBoundFBOId == m_graphicsContext->defaultFBO() && surfaceLock.isSurfaceValid());
}
}
// Called by RenderViewJobs
+// When the frameQueue is complete and we are using a renderThread
+// we allow the render thread to proceed
void Renderer::enqueueRenderView(Render::RenderView *renderView, int submitOrder)
{
- QMutexLocker locker(&m_mutex); // Prevent out of order execution
+ QMutexLocker locker(&m_renderQueueMutex); // Prevent out of order execution
// We cannot use a lock free primitive here because:
// - QVector is not thread safe
// - Even if the insert is made correctly, the isFrameComplete call
// could be invalid since depending on the order of execution
// the counter could be complete but the renderview not yet added to the
// buffer depending on whichever order the cpu decides to process this
-
- if (m_renderQueue->queueRenderView(renderView, submitOrder)) {
+ const bool isQueueComplete = m_renderQueue->queueRenderView(renderView, submitOrder);
+ locker.unlock(); // We're done protecting the queue at this point
+ if (isQueueComplete) {
if (m_renderThread && m_running.load())
Q_ASSERT(m_submitRenderViewsSemaphore.available() == 0);
m_submitRenderViewsSemaphore.release(1);
@@ -695,16 +745,6 @@ bool Renderer::isReadyToSubmit()
// something to render
// The case of shutdown should have been handled just before
Q_ASSERT(m_renderQueue->isFrameQueueComplete());
- } else {
- // When using synchronous rendering (QtQuick)
- // We are not sure that the frame queue is actually complete
- // Since a call to render may not be synched with the completions
- // of the RenderViewJobs
- // In such a case we return early, waiting for a next call with
- // the frame queue complete at this point
- QMutexLocker locker(&m_mutex);
- if (!m_renderQueue->isFrameQueueComplete())
- return false;
}
return true;
}
@@ -898,6 +938,23 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
}
// Executed in a job
+void Renderer::lookForAbandonedVaos()
+{
+ const QVector<HVao> activeVaos = m_nodesManager->vaoManager()->activeHandles();
+ for (HVao handle : activeVaos) {
+ OpenGLVertexArrayObject *vao = m_nodesManager->vaoManager()->data(handle);
+
+ // Make sure to only mark VAOs for deletion that were already created
+ // (ignore those that might be currently under construction in the render thread)
+ if (vao && vao->isAbandoned(m_nodesManager->geometryManager(), m_nodesManager->shaderManager())) {
+ m_abandonedVaosMutex.lock();
+ m_abandonedVaos.push_back(handle);
+ m_abandonedVaosMutex.unlock();
+ }
+ }
+}
+
+// Executed in a job
void Renderer::lookForDirtyBuffers()
{
const QVector<HBuffer> activeBufferHandles = m_nodesManager->bufferManager()->activeHandles();
@@ -908,6 +965,17 @@ void Renderer::lookForDirtyBuffers()
}
}
+void Renderer::lookForDownloadableBuffers()
+{
+ m_downloadableBuffers.clear();
+ const QVector<HBuffer> activeBufferHandles = m_nodesManager->bufferManager()->activeHandles();
+ for (HBuffer handle : activeBufferHandles) {
+ Buffer *buffer = m_nodesManager->bufferManager()->data(handle);
+ if (buffer->access() & QBuffer::Read)
+ m_downloadableBuffers.push_back(handle);
+ }
+}
+
// Executed in a job
void Renderer::lookForDirtyTextures()
{
@@ -935,6 +1003,8 @@ void Renderer::lookForDirtyShaders()
RenderPass *renderPass = m_nodesManager->renderPassManager()->lookupResource(passId);
HShader shaderHandle = m_nodesManager->shaderManager()->lookupHandle(renderPass->shaderProgram());
Shader *shader = m_nodesManager->shaderManager()->data(shaderHandle);
+ if (Q_UNLIKELY(shader->hasPendingNotifications()))
+ shader->submitPendingNotifications();
if (shader != nullptr && !shader->isLoaded())
m_dirtyShaders.push_back(shaderHandle);
}
@@ -951,12 +1021,11 @@ void Renderer::updateGLResources()
const QVector<HBuffer> dirtyBufferHandles = std::move(m_dirtyBuffers);
for (HBuffer handle: dirtyBufferHandles) {
Buffer *buffer = m_nodesManager->bufferManager()->data(handle);
- // Perform data upload
// Forces creation if it doesn't exit
if (!m_graphicsContext->hasGLBufferForBuffer(buffer))
m_graphicsContext->glBufferForRenderBuffer(buffer);
- else if (buffer->isDirty()) // Otherwise update the glBuffer
- m_graphicsContext->updateBuffer(buffer);
+ // Update the glBuffer data
+ m_graphicsContext->updateBuffer(buffer);
buffer->unsetDirty();
}
}
@@ -964,10 +1033,11 @@ void Renderer::updateGLResources()
{
Profiling::GLTimeRecorder recorder(Profiling::ShaderUpload);
const QVector<HShader> dirtyShaderHandles = std::move(m_dirtyShaders);
+ ShaderManager *shaderManager = m_nodesManager->shaderManager();
for (HShader handle: dirtyShaderHandles) {
- Shader *shader = m_nodesManager->shaderManager()->data(handle);
+ Shader *shader = shaderManager->data(handle);
// Compile shader
- m_graphicsContext->loadShader(shader);
+ m_graphicsContext->loadShader(shader, shaderManager);
}
}
@@ -990,13 +1060,16 @@ void Renderer::updateGLResources()
// We can really release the texture at this point
m_nodesManager->textureManager()->releaseResource(textureCleanedUpId);
}
-
-
}
// Render Thread
void Renderer::updateTexture(Texture *texture)
{
+ // Check that the current texture images are still in place, if not, do not update
+ const bool isValid = texture->isValid();
+ if (!isValid)
+ return;
+
// For implementing unique, non-shared, non-cached textures.
// for now, every texture is shared by default
@@ -1065,10 +1138,14 @@ void Renderer::updateTexture(Texture *texture)
!glTextureManager->setParameters(glTexture, texture->parameters()))
qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setParameters failed, should be non-shared";
- if (dirtyFlags.testFlag(Texture::DirtyGenerators) &&
+ if (dirtyFlags.testFlag(Texture::DirtyImageGenerators) &&
!glTextureManager->setImages(glTexture, texture->textureImages()))
qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setGenerators failed, should be non-shared";
+ if (dirtyFlags.testFlag(Texture::DirtyDataGenerator) &&
+ !glTextureManager->setGenerator(glTexture, texture->dataGenerator()))
+ qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setGenerator failed, should be non-shared";
+
// Unset the dirty flag on the texture
texture->unsetDirty();
}
@@ -1083,6 +1160,17 @@ void Renderer::cleanupTexture(const Texture *texture)
glTextureManager->abandon(glTexture, texture);
}
+void Renderer::downloadGLBuffers()
+{
+ lookForDownloadableBuffers();
+ const QVector<HBuffer> downloadableHandles = std::move(m_downloadableBuffers);
+ for (HBuffer handle : downloadableHandles) {
+ Buffer *buffer = m_nodesManager->bufferManager()->data(handle);
+ QByteArray content = m_graphicsContext->downloadBufferContent(buffer);
+ m_sendBufferCaptureJob->addRequest(QPair<Buffer*, QByteArray>(buffer, content));
+ }
+}
+
// Happens in RenderThread context when all RenderViewJobs are done
// Returns the id of the last bound FBO
@@ -1221,6 +1309,9 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
addRenderCaptureSendRequest(renderView->renderCaptureNodeId());
}
+ if (renderView->isDownloadBuffersEnable())
+ downloadGLBuffers();
+
frameElapsed = timer.elapsed() - frameElapsed;
qCDebug(Rendering) << Q_FUNC_INFO << "Submitted Renderview " << i + 1 << "/" << renderViewsCount << "in " << frameElapsed << "ms";
frameElapsed = timer.elapsed();
@@ -1311,6 +1402,7 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
m_pickBoundingVolumeJob->setFrameGraphRoot(frameGraphRoot());
m_pickBoundingVolumeJob->setRenderSettings(settings());
m_pickBoundingVolumeJob->setMouseEvents(pendingPickingEvents());
+ m_pickBoundingVolumeJob->setKeyEvents(pendingKeyEvents());
m_updateLevelOfDetailJob->setFrameGraphRoot(frameGraphRoot());
// Set dependencies of resource gatherer
@@ -1331,25 +1423,36 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
renderBinJobs.push_back(m_worldTransformJob);
renderBinJobs.push_back(m_cleanupJob);
renderBinJobs.push_back(m_sendRenderCaptureJob);
+ renderBinJobs.push_back(m_sendBufferCaptureJob);
renderBinJobs.push_back(m_filterCompatibleTechniqueJob);
renderBinJobs.append(bufferJobs);
// Jobs to prepare GL Resource upload
renderBinJobs.push_back(m_syncTextureLoadingJob);
+ renderBinJobs.push_back(m_vaoGathererJob);
renderBinJobs.push_back(m_bufferGathererJob);
renderBinJobs.push_back(m_textureGathererJob);
renderBinJobs.push_back(m_shaderGathererJob);
- // Traverse the current framegraph. For each leaf node create a
- // RenderView and set its configuration then create a job to
- // populate the RenderView with a set of RenderCommands that get
- // their details from the RenderNodes that are visible to the
- // Camera selected by the framegraph configuration
- FrameGraphVisitor visitor(this, m_nodesManager->frameGraphManager());
- visitor.traverse(frameGraphRoot(), &renderBinJobs);
+ QMutexLocker lock(&m_renderQueueMutex);
+ if (m_renderQueue->wasReset()) { // Have we rendered yet? (Scene3D case)
+ // Traverse the current framegraph. For each leaf node create a
+ // RenderView and set its configuration then create a job to
+ // populate the RenderView with a set of RenderCommands that get
+ // their details from the RenderNodes that are visible to the
+ // Camera selected by the framegraph configuration
+ FrameGraphVisitor visitor(m_nodesManager->frameGraphManager());
+ const QVector<FrameGraphNode *> fgLeaves = visitor.traverse(frameGraphRoot());
+
+ const int fgBranchCount = fgLeaves.size();
+ for (int i = 0; i < fgBranchCount; ++i) {
+ RenderViewBuilder builder(fgLeaves.at(i), i, this);
+ renderBinJobs.append(builder.buildJobHierachy());
+ }
- // Set target number of RenderViews
- m_renderQueue->setTargetRenderViewCount(visitor.leafNodeCount());
+ // Set target number of RenderViews
+ m_renderQueue->setTargetRenderViewCount(fgBranchCount);
+ }
return renderBinJobs;
}
@@ -1364,6 +1467,11 @@ QAspectJobPtr Renderer::syncTextureLoadingJob()
return m_syncTextureLoadingJob;
}
+QAspectJobPtr Renderer::expandBoundingVolumeJob()
+{
+ return m_expandBoundingVolumeJob;
+}
+
QAbstractFrameAdvanceService *Renderer::frameAdvanceService() const
{
return static_cast<Qt3DCore::QAbstractFrameAdvanceService *>(m_vsyncFrameAdvanceService.data());
@@ -1474,16 +1582,15 @@ void Renderer::createOrUpdateVAO(RenderCommand *command,
HVao *previousVaoHandle,
OpenGLVertexArrayObject **vao)
{
+ const VAOIdentifier vaoKey(command->m_geometry, command->m_shader);
+
VAOManager *vaoManager = m_nodesManager->vaoManager();
- command->m_vao = vaoManager->lookupHandle(QPair<HGeometry, HShader>(command->m_geometry, command->m_shader));
+ command->m_vao = vaoManager->lookupHandle(vaoKey);
if (command->m_vao.isNull()) {
qCDebug(Rendering) << Q_FUNC_INFO << "Allocating new VAO";
- command->m_vao = vaoManager->getOrAcquireHandle(QPair<HGeometry, HShader>(command->m_geometry, command->m_shader));
- vaoManager->data(command->m_vao)->setGraphicsContext(m_graphicsContext.data());
- if (m_graphicsContext->supportsVAO())
- vaoManager->data(command->m_vao)->setVao(new QOpenGLVertexArrayObject());
- vaoManager->data(command->m_vao)->create();
+ command->m_vao = vaoManager->getOrAcquireHandle(vaoKey);
+ vaoManager->data(command->m_vao)->create(m_graphicsContext.data(), vaoKey);
}
if (*previousVaoHandle != command->m_vao) {
@@ -1679,11 +1786,30 @@ void Renderer::cleanGraphicsResources()
tex->destroyGLTexture();
delete tex;
}
+
+ // Delete abandoned VAOs
+ m_abandonedVaosMutex.lock();
+ const QVector<HVao> abandonedVaos = std::move(m_abandonedVaos);
+ m_abandonedVaosMutex.unlock();
+ for (HVao vaoHandle : abandonedVaos) {
+ // might have already been destroyed last frame, but added by the cleanup job before, so
+ // check if the VAO is really still existent
+ OpenGLVertexArrayObject *vao = m_nodesManager->vaoManager()->data(vaoHandle);
+ if (vao) {
+ vao->destroy();
+ m_nodesManager->vaoManager()->release(vaoHandle);
+ }
+ }
}
QList<QMouseEvent> Renderer::pendingPickingEvents() const
{
- return m_pickEventFilter->pendingEvents();
+ return m_pickEventFilter->pendingMouseEvents();
+}
+
+QList<QKeyEvent> Renderer::pendingKeyEvents() const
+{
+ return m_pickEventFilter->pendingKeyEvents();
}
const GraphicsApiFilterData *Renderer::contextInfo() const
diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h
index 9b5c35ed1..e311261e0 100644
--- a/src/render/backend/renderer_p.h
+++ b/src/render/backend/renderer_p.h
@@ -71,6 +71,7 @@
#include <Qt3DRender/private/updatetreeenabledjob_p.h>
#include <Qt3DRender/private/platformsurfacefilter_p.h>
#include <Qt3DRender/private/sendrendercapturejob_p.h>
+#include <Qt3DRender/private/sendbuffercapturejob_p.h>
#include <Qt3DRender/private/genericlambdajob_p.h>
#include <Qt3DRender/private/updatemeshtrianglelistjob_p.h>
#include <Qt3DRender/private/filtercompatibletechniquejob_p.h>
@@ -156,7 +157,7 @@ public:
void setTime(qint64 time) Q_DECL_OVERRIDE;
void setNodeManagers(NodeManagers *managers) Q_DECL_OVERRIDE;
- void setServices(Qt3DCore::QServiceLocator *services) Q_DECL_OVERRIDE { m_services = services; }
+ void setServices(Qt3DCore::QServiceLocator *services) Q_DECL_OVERRIDE;
void setSurfaceExposed(bool exposed) Q_DECL_OVERRIDE;
NodeManagers *nodeManagers() const Q_DECL_OVERRIDE;
@@ -188,11 +189,11 @@ public:
QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() Q_DECL_OVERRIDE;
Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() Q_DECL_OVERRIDE;
Qt3DCore::QAspectJobPtr syncTextureLoadingJob() Q_DECL_OVERRIDE;
+ Qt3DCore::QAspectJobPtr expandBoundingVolumeJob() Q_DECL_OVERRIDE;
QVector<Qt3DCore::QAspectJobPtr> createRenderBufferJobs() const;
inline FrameCleanupJobPtr frameCleanupJob() const { return m_cleanupJob; }
- inline ExpandBoundingVolumeJobPtr expandBoundingVolumeJob() const { return m_expandBoundingVolumeJob; }
inline UpdateShaderDataTransformJobPtr updateShaderDataTransformJob() const { return m_updateShaderDataTransformJob; }
inline CalculateBoundingVolumeJobPtr calculateBoundingVolumeJob() const { return m_calculateBoundingVolumeJob; }
inline UpdateTreeEnabledJobPtr updateTreeEnabledJob() const { return m_updateTreeEnabledJob; }
@@ -209,10 +210,12 @@ public:
virtual void setSettings(RenderSettings *settings) Q_DECL_OVERRIDE;
virtual RenderSettings *settings() const Q_DECL_OVERRIDE;
+ QOpenGLContext *shareContext() const Q_DECL_OVERRIDE;
void updateGLResources();
void updateTexture(Texture *texture);
void cleanupTexture(const Texture *texture);
+ void downloadGLBuffers();
void prepareCommandsSubmission(const QVector<RenderView *> &renderViews);
bool executeCommandsSubmission(const RenderView *rv);
@@ -230,8 +233,8 @@ public:
inline RenderStateSet *defaultRenderState() const { return m_defaultRenderStateSet; }
-
QList<QMouseEvent> pendingPickingEvents() const;
+ QList<QKeyEvent> pendingKeyEvents() const;
void addRenderCaptureSendRequest(Qt3DCore::QNodeId nodeId);
const QVector<Qt3DCore::QNodeId> takePendingRenderCaptureSendRequests();
@@ -256,12 +259,13 @@ public:
ViewSubmissionResultData submitRenderViews(const QVector<Render::RenderView *> &renderViews);
- QMutex* mutex() { return &m_mutex; }
+ QMutex* mutex() { return &m_renderQueueMutex; }
#ifdef QT3D_RENDER_UNIT_TESTS
public:
#else
+
private:
#endif
bool canRender() const;
@@ -286,7 +290,7 @@ private:
QScopedPointer<RenderThread> m_renderThread;
QScopedPointer<VSyncFrameAdvanceService> m_vsyncFrameAdvanceService;
- QMutex m_mutex;
+ QMutex m_renderQueueMutex;
QSemaphore m_submitRenderViewsSemaphore;
QSemaphore m_waitForInitializationToBeCompleted;
@@ -300,6 +304,7 @@ private:
BackendNodeDirtySet m_changeSet;
QAtomicInt m_lastFrameCorrect;
QOpenGLContext *m_glContext;
+ QOpenGLContext *m_shareContext;
PickBoundingVolumeJobPtr m_pickBoundingVolumeJob;
qint64 m_time;
@@ -314,6 +319,7 @@ private:
UpdateWorldBoundingVolumeJobPtr m_updateWorldBoundingVolumeJob;
UpdateTreeEnabledJobPtr m_updateTreeEnabledJob;
SendRenderCaptureJobPtr m_sendRenderCaptureJob;
+ SendBufferCaptureJobPtr m_sendBufferCaptureJob;
UpdateLevelOfDetailJobPtr m_updateLevelOfDetailJob;
UpdateMeshTriangleListJobPtr m_updateMeshTriangleListJob;
FilterCompatibleTechniqueJobPtr m_filterCompatibleTechniqueJob;
@@ -327,16 +333,23 @@ private:
OpenGLVertexArrayObject **vao);
GenericLambdaJobPtr<std::function<void ()>> m_bufferGathererJob;
+ GenericLambdaJobPtr<std::function<void ()>> m_vaoGathererJob;
GenericLambdaJobPtr<std::function<void ()>> m_textureGathererJob;
GenericLambdaJobPtr<std::function<void ()>> m_shaderGathererJob;
SynchronizerJobPtr m_syncTextureLoadingJob;
+ void lookForAbandonedVaos();
void lookForDirtyBuffers();
+ void lookForDownloadableBuffers();
void lookForDirtyTextures();
void lookForDirtyShaders();
+ QMutex m_abandonedVaosMutex;
+ QVector<HVao> m_abandonedVaos;
+
QVector<HBuffer> m_dirtyBuffers;
+ QVector<HBuffer> m_downloadableBuffers;
QVector<HShader> m_dirtyShaders;
QVector<HTexture> m_dirtyTextures;
diff --git a/src/render/backend/renderqueue.cpp b/src/render/backend/renderqueue.cpp
index 6ec7da464..2fa1cb7d2 100644
--- a/src/render/backend/renderqueue.cpp
+++ b/src/render/backend/renderqueue.cpp
@@ -49,6 +49,7 @@ namespace Render {
RenderQueue::RenderQueue()
: m_noRender(false)
+ , m_wasReset(true)
, m_targetRenderViewCount(0)
, m_currentRenderViewCount(0)
, m_currentWorkQueue(1)
@@ -70,6 +71,7 @@ void RenderQueue::reset()
m_targetRenderViewCount = 0;
m_currentWorkQueue.clear();
m_noRender = false;
+ m_wasReset = true;
}
void RenderQueue::setNoRender()
@@ -88,6 +90,7 @@ bool RenderQueue::queueRenderView(RenderView *renderView, uint submissionOrderIn
Q_ASSERT(!m_noRender);
m_currentWorkQueue[submissionOrderIndex] = renderView;
++m_currentRenderViewCount;
+ Q_ASSERT(m_currentRenderViewCount <= m_targetRenderViewCount);
return isFrameQueueComplete();
}
@@ -109,6 +112,7 @@ void RenderQueue::setTargetRenderViewCount(int targetRenderViewCount)
Q_ASSERT(!m_noRender);
m_targetRenderViewCount = targetRenderViewCount;
m_currentWorkQueue.resize(targetRenderViewCount);
+ m_wasReset = false;
}
/*!
@@ -119,7 +123,7 @@ void RenderQueue::setTargetRenderViewCount(int targetRenderViewCount)
bool RenderQueue::isFrameQueueComplete() const
{
return (m_noRender
- || (m_targetRenderViewCount && m_targetRenderViewCount == currentRenderViewCount()));
+ || (m_targetRenderViewCount > 0 && m_targetRenderViewCount == m_currentRenderViewCount));
}
} // namespace Render
diff --git a/src/render/backend/renderqueue_p.h b/src/render/backend/renderqueue_p.h
index 49316049b..611f5849a 100644
--- a/src/render/backend/renderqueue_p.h
+++ b/src/render/backend/renderqueue_p.h
@@ -77,9 +77,13 @@ public:
void reset();
void setNoRender();
+ inline bool isNoRender() const { return m_noRender; }
+
+ inline bool wasReset() const { return m_wasReset; }
private:
bool m_noRender;
+ bool m_wasReset;
int m_targetRenderViewCount;
int m_currentRenderViewCount;
QVector<RenderView *> m_currentWorkQueue;
diff --git a/src/render/backend/rendertargetoutput.cpp b/src/render/backend/rendertargetoutput.cpp
index faebfacb6..cba92596d 100644
--- a/src/render/backend/rendertargetoutput.cpp
+++ b/src/render/backend/rendertargetoutput.cpp
@@ -121,9 +121,14 @@ void RenderTargetOutput::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
BackendNode::sceneChangeEvent(e);
}
-Attachment RenderTargetOutput::attachment() const
+Qt3DRender::Render::Attachment *RenderTargetOutput::attachment()
{
- return m_attachmentData;
+ return &m_attachmentData;
+}
+
+const Attachment *RenderTargetOutput::attachment() const
+{
+ return &m_attachmentData;
}
} // namespace Render
diff --git a/src/render/backend/rendertargetoutput_p.h b/src/render/backend/rendertargetoutput_p.h
index 14daa84e9..b7867c2cb 100644
--- a/src/render/backend/rendertargetoutput_p.h
+++ b/src/render/backend/rendertargetoutput_p.h
@@ -77,7 +77,8 @@ public:
QAbstractTexture::CubeMapFace face() const;
QRenderTargetOutput::AttachmentPoint point() const;
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
- Attachment attachment() const;
+ Attachment *attachment();
+ const Attachment *attachment() const;
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
diff --git a/src/render/backend/renderthread_p.h b/src/render/backend/renderthread_p.h
index 026a98609..8d7c083ed 100644
--- a/src/render/backend/renderthread_p.h
+++ b/src/render/backend/renderthread_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef RENDERTHREAD_H
-#define RENDERTHREAD_H
+#ifndef QT3DRENDER_RENDER_RENDERTHREAD_H
+#define QT3DRENDER_RENDER_RENDERTHREAD_H
//
// W A R N I N G
@@ -75,7 +75,7 @@ public:
Render::Renderer* renderer() const { return m_renderer; }
protected:
- void run();
+ void run() Q_DECL_OVERRIDE;
private:
Renderer* m_renderer;
@@ -88,4 +88,4 @@ private:
QT_END_NAMESPACE
-#endif // RENDERTHREAD_H
+#endif // QT3DRENDER_RENDER_RENDERTHREAD_H
diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp
index bfdb68eb1..03f61b2d9 100644
--- a/src/render/backend/renderview.cpp
+++ b/src/render/backend/renderview.cpp
@@ -66,6 +66,7 @@
#include <Qt3DRender/private/buffermanager_p.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
#include <Qt3DRender/private/rendercapture_p.h>
+#include <Qt3DRender/private/buffercapture_p.h>
#include <Qt3DRender/private/stringtoint_p.h>
#include <Qt3DCore/qentity.h>
#include <QtGui/qsurface.h>
@@ -128,6 +129,8 @@ RenderView::StandardUniformsNameToTypeHash RenderView::initializeStandardUniform
setters.insert(StringToInt::lookupId(QLatin1String("modelViewNormal")), ModelViewNormalMatrix);
setters.insert(StringToInt::lookupId(QLatin1String("viewportMatrix")), ViewportMatrix);
setters.insert(StringToInt::lookupId(QLatin1String("inverseViewportMatrix")), InverseViewportMatrix);
+ setters.insert(StringToInt::lookupId(QLatin1String("exposure")), Exposure);
+ setters.insert(StringToInt::lookupId(QLatin1String("gamma")), Gamma);
setters.insert(StringToInt::lookupId(QLatin1String("time")), Time);
setters.insert(StringToInt::lookupId(QLatin1String("eyePosition")), EyePosition);
@@ -190,6 +193,10 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa
viewportMatrix.viewport(resolveViewport(m_viewport, m_surfaceSize));
return UniformValue(viewportMatrix.inverted());
}
+ case Exposure:
+ return UniformValue(m_data.m_renderCameraLens->exposure());
+ case Gamma:
+ return UniformValue(m_gamma);
case Time:
return UniformValue(float(m_renderer->time() / 1000000000.0f));
case EyePosition:
@@ -201,9 +208,11 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa
}
RenderView::RenderView()
- : m_renderer(nullptr)
+ : m_isDownloadBuffersEnable(false)
+ , m_renderer(nullptr)
, m_devicePixelRatio(1.)
, m_viewport(QRectF(0.0f, 0.0f, 1.0f, 1.0f))
+ , m_gamma(2.2f)
, m_surface(nullptr)
, m_clearBuffer(QClearBuffers::None)
, m_stateSet(nullptr)
@@ -211,6 +220,7 @@ RenderView::RenderView()
, m_compute(false)
, m_frustumCulling(false)
, m_memoryBarrier(QMemoryBarrier::None)
+ , m_environmentLight(nullptr)
{
m_workGroups[0] = 1;
m_workGroups[1] = 1;
@@ -352,6 +362,7 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
// is only accessed from the same thread
UniformBlockValueBuilder *builder = new UniformBlockValueBuilder();
builder->shaderDataManager = m_manager->shaderDataManager();
+ builder->textureManager = m_manager->textureManager();
m_localData.setLocalData(builder);
QVector<RenderCommand *> commands;
@@ -404,7 +415,12 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
ParameterInfoList globalParameters = passData.parameterInfo;
// setShaderAndUniforms can initialize a localData
// make sure this is cleared before we leave this function
- setShaderAndUniforms(command, pass, globalParameters, *(node->worldTransform()), lightSources.mid(0, std::max(lightSources.size(), MAX_LIGHTS)));
+ setShaderAndUniforms(command,
+ pass,
+ globalParameters,
+ *(node->worldTransform()),
+ lightSources.mid(0, std::max(lightSources.size(), MAX_LIGHTS)),
+ m_environmentLight);
// Store all necessary information for actual drawing if command is valid
command->m_isValid = !command->m_attributes.empty();
@@ -470,6 +486,7 @@ QVector<RenderCommand *> RenderView::buildComputeRenderCommands(const QVector<En
// is only accessed from the same thread
UniformBlockValueBuilder *builder = new UniformBlockValueBuilder();
builder->shaderDataManager = m_manager->shaderDataManager();
+ builder->textureManager = m_manager->textureManager();
m_localData.setLocalData(builder);
// If the RenderView contains only a ComputeDispatch then it cares about
@@ -503,7 +520,8 @@ QVector<RenderCommand *> RenderView::buildComputeRenderCommands(const QVector<En
pass,
globalParameters,
*(node->worldTransform()),
- QVector<LightSource>());
+ QVector<LightSource>(),
+ nullptr);
commands.append(command);
}
}
@@ -579,7 +597,7 @@ void RenderView::setUniformBlockValue(ShaderParameterPack &uniformPack,
// If two shaders define the same block with the exact same layout, in that case the UBO could be shared
// but how do we know that ? We'll need to compare ShaderUniformBlocks
- // Note: we assume that if a buffer is shared accross multiple shaders
+ // Note: we assume that if a buffer is shared across multiple shaders
// then it implies that they share the same layout
// Temporarly disabled
@@ -691,7 +709,7 @@ void RenderView::buildSortingKey(RenderCommand *command) const
}
void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass, ParameterInfoList &parameters, const QMatrix4x4 &worldTransform,
- const QVector<LightSource> &activeLightSources) const
+ const QVector<LightSource> &activeLightSources, EnvironmentLight *environmentLight) const
{
// The VAO Handle is set directly in the renderer thread so as to avoid having to use a mutex here
// Set shader, technique, and effect by basically doing :
@@ -812,13 +830,25 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass,
if (uniformNamesIds.contains(LIGHT_COUNT_NAME_ID))
setUniformValue(command->m_parameterPack, LIGHT_COUNT_NAME_ID, UniformValue(qMax(1, lightIdx)));
- if (activeLightSources.isEmpty()) {
+ // If no active light sources and no environment light, add a default light
+ if (activeLightSources.isEmpty() && !environmentLight) {
// Note: implicit conversion of values to UniformValue
setUniformValue(command->m_parameterPack, LIGHT_POSITION_NAMES[0], QVector3D(10.0f, 10.0f, 0.0f));
setUniformValue(command->m_parameterPack, LIGHT_TYPE_NAMES[0], int(QAbstractLight::PointLight));
setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[0], QVector3D(1.0f, 1.0f, 1.0f));
setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_NAMES[0], 0.5f);
}
+
+ // Environment Light
+ int envLightCount = 0;
+ if (environmentLight && environmentLight->isEnabled()) {
+ ShaderData *shaderData = m_manager->shaderDataManager()->lookupResource(environmentLight->shaderData());
+ if (shaderData) {
+ setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, QStringLiteral("envLight"));
+ envLightCount = 1;
+ }
+ }
+ setUniformValue(command->m_parameterPack, StringToInt::lookupId(QStringLiteral("envLightCount")), envLightCount);
}
// Set frag outputs in the shaders if hash not empty
if (!fragOutputs.isEmpty())
@@ -830,6 +860,16 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass,
}
}
+bool RenderView::isDownloadBuffersEnable() const
+{
+ return m_isDownloadBuffersEnable;
+}
+
+void RenderView::setIsDownloadBuffersEnable(bool isDownloadBuffersEnable)
+{
+ m_isDownloadBuffersEnable = isDownloadBuffersEnable;
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/renderview_p.h b/src/render/backend/renderview_p.h
index 1f00e2aae..440d51638 100644
--- a/src/render/backend/renderview_p.h
+++ b/src/render/backend/renderview_p.h
@@ -181,6 +181,9 @@ public:
inline void setViewport(const QRectF &vp) Q_DECL_NOTHROW { m_viewport = vp; }
inline QRectF viewport() const Q_DECL_NOTHROW { return m_viewport; }
+ inline float gamma() const Q_DECL_NOTHROW { return m_gamma; }
+ inline void setGamma(float gamma) Q_DECL_NOTHROW { m_gamma = gamma; }
+
// depth and stencil ClearBuffers are cached locally
// color ClearBuffers are collected, as there may be multiple
// color buffers to be cleared. we need to apply all these at rendering
@@ -212,14 +215,15 @@ public:
QSurface *surface() const { return m_surface; }
void setLightSources(const QVector<LightSource> &lightSources) Q_DECL_NOTHROW { m_lightSources = lightSources; }
+ void setEnvironmentLight(EnvironmentLight *environmentLight) Q_DECL_NOTHROW { m_environmentLight = environmentLight; }
void updateMatrices();
inline void setRenderCaptureNodeId(const Qt3DCore::QNodeId nodeId) Q_DECL_NOTHROW { m_renderCaptureNodeId = nodeId; }
inline const Qt3DCore::QNodeId renderCaptureNodeId() const Q_DECL_NOTHROW { return m_renderCaptureNodeId; }
- void setMemoryBarrier(QMemoryBarrier::BarrierTypes barrier) Q_DECL_NOTHROW { m_memoryBarrier = barrier; }
- QMemoryBarrier::BarrierTypes memoryBarrier() const Q_DECL_NOTHROW { return m_memoryBarrier; }
+ void setMemoryBarrier(QMemoryBarrier::Operations barrier) Q_DECL_NOTHROW { m_memoryBarrier = barrier; }
+ QMemoryBarrier::Operations memoryBarrier() const Q_DECL_NOTHROW { return m_memoryBarrier; }
// Helps making the size of RenderView smaller
// Contains all the data needed for the actual building of the RenderView
@@ -245,13 +249,17 @@ public:
QVector3D m_eyePos;
};
+ bool isDownloadBuffersEnable() const;
+ void setIsDownloadBuffersEnable(bool isDownloadBuffersEnable);
+
private:
void setShaderAndUniforms(RenderCommand *command, RenderPass *pass, ParameterInfoList &parameters, const QMatrix4x4 &worldTransform,
- const QVector<LightSource> &activeLightSources) const;
+ const QVector<LightSource> &activeLightSources, EnvironmentLight *environmentLight) const;
mutable QThreadStorage<UniformBlockValueBuilder*> m_localData;
Qt3DCore::QNodeId m_renderCaptureNodeId;
+ bool m_isDownloadBuffersEnable;
Renderer *m_renderer;
NodeManagers *m_manager;
@@ -261,6 +269,7 @@ private:
InnerData m_data;
QRectF m_viewport;
+ float m_gamma;
Qt3DCore::QNodeId m_renderTarget;
QSurface *m_surface;
AttachmentPack m_attachmentPack;
@@ -274,13 +283,14 @@ private:
bool m_compute:1;
bool m_frustumCulling:1;
int m_workGroups[3];
- QMemoryBarrier::BarrierTypes m_memoryBarrier;
+ QMemoryBarrier::Operations m_memoryBarrier;
// We do not use pointers to RenderNodes or Drawable's here so that the
// render aspect is free to change the drawables on the next frame whilst
// the render thread is submitting these commands.
QVector<RenderCommand *> m_commands;
mutable QVector<LightSource> m_lightSources;
+ EnvironmentLight *m_environmentLight;
QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> m_parameters;
@@ -303,6 +313,8 @@ private:
ViewportMatrix,
InverseViewportMatrix,
Time,
+ Exposure,
+ Gamma,
EyePosition
};
diff --git a/src/render/backend/renderviewbuilder.cpp b/src/render/backend/renderviewbuilder.cpp
index 55d8ba462..f47c6f419 100644
--- a/src/render/backend/renderviewbuilder.cpp
+++ b/src/render/backend/renderviewbuilder.cpp
@@ -66,14 +66,14 @@ public:
RenderView *rv = m_renderViewJob->renderView();
int totalCommandCount = 0;
- for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
+ for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
totalCommandCount += renderViewCommandBuilder->commands().size();
QVector<RenderCommand *> commands;
commands.reserve(totalCommandCount);
// Reduction
- for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
+ for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
commands += std::move(renderViewCommandBuilder->commands());
rv->setCommands(commands);
@@ -139,13 +139,13 @@ public:
m_filterEntityByLayerJob->setLayers(rv->layerFilter());
// Material Parameter building
- for (const auto materialGatherer : qAsConst(m_materialGathererJobs)) {
+ for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) {
materialGatherer->setRenderPassFilter(const_cast<RenderPassFilter *>(rv->renderPassFilter()));
materialGatherer->setTechniqueFilter(const_cast<TechniqueFilter *>(rv->techniqueFilter()));
}
// Command builders
- for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
+ for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
renderViewCommandBuilder->setRenderView(rv);
// Set whether frustum culling is enabled or not
@@ -188,8 +188,7 @@ public:
RenderView *rv = m_renderViewJob->renderView();
if (!rv->noDraw()) {
- // Set the light sources
- rv->setLightSources(std::move(m_lightGathererJob->lights()));
+ rv->setEnvironmentLight(m_lightGathererJob->takeEnvironmentLight());
// We sort the vector so that the removal can then be performed linearly
@@ -207,6 +206,14 @@ public:
QVector<Entity *> filteredEntities = m_filterEntityByLayerJob->filteredEntities();
RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, filteredEntities);
+ // Set the light sources, with layer filters applied.
+ QVector<LightSource> lightSources = m_lightGathererJob->lights();
+ for (int i = 0; i < lightSources.count(); ++i) {
+ if (!filteredEntities.contains(lightSources[i].entity))
+ lightSources.removeAt(i--);
+ }
+ rv->setLightSources(lightSources);
+
// Filter out frustum culled entity for drawable entities
if (isDraw && rv->frustumCulling())
RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, m_frustumCullingJob->visibleEntities());
@@ -224,7 +231,7 @@ public:
// Reduction
QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> params;
- for (const auto materialGatherer : qAsConst(m_materialGathererJobs))
+ for (const auto &materialGatherer : qAsConst(m_materialGathererJobs))
params.unite(materialGatherer->materialToPassAndParameter());
// Set all required data on the RenderView for final processing
rv->setMaterialParameterTable(std::move(params));
@@ -424,7 +431,7 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
m_filterEntityByLayerJob->addDependency(m_renderer->updateTreeEnabledJob());
m_syncRenderCommandBuildingJob->addDependency(m_syncRenderViewInitializationJob);
- for (const auto materialGatherer : qAsConst(m_materialGathererJobs)) {
+ for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) {
materialGatherer->addDependency(m_syncRenderViewInitializationJob);
materialGatherer->addDependency(m_renderer->filterCompatibleTechniqueJob());
m_syncRenderCommandBuildingJob->addDependency(materialGatherer);
@@ -435,7 +442,7 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
m_syncRenderCommandBuildingJob->addDependency(m_lightGathererJob);
m_syncRenderCommandBuildingJob->addDependency(m_frustumCullingJob);
- for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) {
+ for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) {
renderViewCommandBuilder->addDependency(m_syncRenderCommandBuildingJob);
m_syncRenderViewCommandBuildersJob->addDependency(renderViewCommandBuilder);
}
@@ -457,13 +464,13 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
jobs.push_back(m_filterEntityByLayerJob); // Step 3
jobs.push_back(m_setClearDrawBufferIndexJob); // Step 3
- for (const auto materialGatherer : qAsConst(m_materialGathererJobs)) // Step3
+ for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) // Step3
jobs.push_back(materialGatherer);
jobs.push_back(m_frustumCullingJob); // Step 4
jobs.push_back(m_syncRenderCommandBuildingJob); // Step 4
- for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) // Step 5
+ for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) // Step 5
jobs.push_back(renderViewCommandBuilder);
jobs.push_back(m_syncRenderViewCommandBuildersJob); // Step 6
diff --git a/src/render/backend/resourceaccessor.cpp b/src/render/backend/resourceaccessor.cpp
new file mode 100644
index 000000000..7558eb4ad
--- /dev/null
+++ b/src/render/backend/resourceaccessor.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** 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 "resourceaccessor_p.h"
+
+#include <Qt3DRender/qrendertargetoutput.h>
+
+#include <private/qrendertargetoutput_p.h>
+#include <private/nodemanagers_p.h>
+#include <private/texture_p.h>
+#include <private/rendertargetoutput_p.h>
+#include <private/texturedatamanager_p.h>
+#include <private/gltexturemanager_p.h>
+#include <private/managers_p.h>
+#include <private/gltexture_p.h>
+
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+RenderBackendResourceAccessor::~RenderBackendResourceAccessor()
+{
+
+}
+
+ResourceAccessor::ResourceAccessor(NodeManagers *mgr)
+ : m_glTextureManager(mgr->glTextureManager())
+ , m_textureManager(mgr->textureManager())
+ , m_attachmentManager(mgr->attachmentManager())
+ , m_entityManager(mgr->renderNodesManager())
+{
+
+}
+
+// called by render plugins from arbitrary thread
+bool ResourceAccessor::accessResource(ResourceType type, Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock)
+{
+ switch (type) {
+
+ case RenderBackendResourceAccessor::OGLTexture: {
+ Texture *tex = m_textureManager->lookupResource(nodeId);
+ if (!tex)
+ return false;
+
+ GLTexture *glTex = m_glTextureManager->lookupResource(tex->peerId());
+ if (!glTex)
+ return false;
+
+ if (glTex->isDirty())
+ return false;
+
+ QOpenGLTexture **glTextureHandle = reinterpret_cast<QOpenGLTexture **>(handle);
+ *glTextureHandle = glTex->getOrCreateGLTexture();
+ *lock = glTex->textureLock();
+ return true;
+ }
+
+ case RenderBackendResourceAccessor::OutputAttachment: {
+ RenderTargetOutput *output = m_attachmentManager->lookupResource(nodeId);
+ if (output) {
+ Attachment **attachmentData = reinterpret_cast<Attachment **>(handle);
+ *attachmentData = output->attachment();
+ return true;
+ }
+ break;
+ }
+
+ case RenderBackendResourceAccessor::EntityHandle: {
+ Entity *entity = m_entityManager->lookupResource(nodeId);
+ if (entity) {
+ Entity **pEntity = reinterpret_cast<Entity **>(handle);
+ *pEntity = entity;
+ return true;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ return false;
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/resourceaccessor_p.h b/src/render/backend/resourceaccessor_p.h
new file mode 100644
index 000000000..b4ed2a3eb
--- /dev/null
+++ b/src/render/backend/resourceaccessor_p.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_RESOURCEACCESSOR_P_H
+#define QT3DRENDER_RENDER_RESOURCEACCESSOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/qnodeid.h>
+
+#include <private/qt3drender_global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMutex;
+
+namespace Qt3DRender
+{
+namespace Render {
+
+class TextureManager;
+class AttachmentManager;
+class GLTextureManager;
+class EntityManager;
+class NodeManagers;
+
+class RenderBackendResourceAccessor
+{
+public:
+ enum ResourceType {
+ OGLTexture,
+ OutputAttachment,
+ EntityHandle,
+ };
+
+ virtual ~RenderBackendResourceAccessor();
+ virtual bool accessResource(ResourceType type, Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) = 0;
+};
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT ResourceAccessor : public RenderBackendResourceAccessor
+{
+public:
+ ResourceAccessor(NodeManagers *mgr);
+ bool accessResource(ResourceType type, Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) Q_DECL_FINAL;
+private:
+ GLTextureManager *m_glTextureManager;
+ TextureManager *m_textureManager;
+ AttachmentManager *m_attachmentManager;
+ EntityManager *m_entityManager;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_RESOURCEACCESSOR_P_H
diff --git a/src/render/backend/shadervariables_p.h b/src/render/backend/shadervariables_p.h
index 2177abe0e..e0fa07dff 100644
--- a/src/render/backend/shadervariables_p.h
+++ b/src/render/backend/shadervariables_p.h
@@ -81,6 +81,7 @@ struct ShaderUniform
{
ShaderUniform()
: m_nameId(-1)
+ , m_type(GL_NONE)
, m_size(0)
, m_offset(-1)
, m_location(-1)
diff --git a/src/render/backend/triangleboundingvolume.cpp b/src/render/backend/triangleboundingvolume.cpp
index 80a23572c..ca2d26897 100644
--- a/src/render/backend/triangleboundingvolume.cpp
+++ b/src/render/backend/triangleboundingvolume.cpp
@@ -112,15 +112,18 @@ Qt3DCore::QNodeId TriangleBoundingVolume::id() const
return m_id;
}
-bool TriangleBoundingVolume::intersects(const RayCasting::QRay3D &ray, QVector3D *q) const
+bool TriangleBoundingVolume::intersects(const RayCasting::QRay3D &ray, QVector3D *q, QVector3D *uvw) const
{
float t = 0.0f;
- QVector3D uvw;
- const bool intersected = intersectsSegmentTriangle(ray, m_c, m_b, m_a, uvw, t);
-
- if (intersected && q != nullptr)
- *q = ray.point(t * ray.distance());
-
+ QVector3D uvwr;
+ const float intersected = intersectsSegmentTriangle(ray, m_c, m_b, m_a, uvwr, t);
+
+ if (intersected) {
+ if (q != nullptr)
+ *q = ray.point(t);
+ if (uvw != nullptr)
+ *uvw = uvwr;
+ }
return intersected;
}
diff --git a/src/render/backend/triangleboundingvolume_p.h b/src/render/backend/triangleboundingvolume_p.h
index 1163efc46..3192ad456 100644
--- a/src/render/backend/triangleboundingvolume_p.h
+++ b/src/render/backend/triangleboundingvolume_p.h
@@ -78,7 +78,7 @@ public:
const QVector3D &c);
Qt3DCore::QNodeId id() const Q_DECL_FINAL;
- bool intersects(const RayCasting::QRay3D &ray, QVector3D *q) const Q_DECL_FINAL;
+ bool intersects(const RayCasting::QRay3D &ray, QVector3D *q, QVector3D *uvw) const Q_DECL_FINAL;
Type type() const Q_DECL_FINAL;
QVector3D a() const;
diff --git a/src/render/backend/trianglesvisitor.cpp b/src/render/backend/trianglesvisitor.cpp
index 35cdecc29..036f43fa0 100644
--- a/src/render/backend/trianglesvisitor.cpp
+++ b/src/render/backend/trianglesvisitor.cpp
@@ -48,6 +48,7 @@
#include <Qt3DRender/private/geometry_p.h>
#include <Qt3DRender/private/attribute_p.h>
#include <Qt3DRender/private/buffer_p.h>
+#include <Qt3DRender/private/bufferutils_p.h>
QT_BEGIN_NAMESPACE
@@ -71,24 +72,6 @@ bool isTriangleBased(Qt3DRender::QGeometryRenderer::PrimitiveType type) Q_DECL_N
}
}
-struct BufferInfo
-{
- BufferInfo()
- : type(QAttribute::VertexBaseType::Float)
- , dataSize(0)
- , count(0)
- , byteStride(0)
- , byteOffset(0)
- {}
-
- QByteArray data;
- QAttribute::VertexBaseType type;
- uint dataSize;
- uint count;
- uint byteStride;
- uint byteOffset;
-};
-
// TO DO: Add methods for triangle strip adjacency
// What about primitive restart ?
@@ -328,48 +311,67 @@ void traverseTriangleAdjacency(Vertex *vertices,
}
}
-
-template <QAttribute::VertexBaseType> struct EnumToType;
-template <> struct EnumToType<QAttribute::Byte> { typedef const char type; };
-template <> struct EnumToType<QAttribute::UnsignedByte> { typedef const uchar type; };
-template <> struct EnumToType<QAttribute::Short> { typedef const short type; };
-template <> struct EnumToType<QAttribute::UnsignedShort> { typedef const ushort type; };
-template <> struct EnumToType<QAttribute::Int> { typedef const int type; };
-template <> struct EnumToType<QAttribute::UnsignedInt> { typedef const uint type; };
-template <> struct EnumToType<QAttribute::Float> { typedef const float type; };
-template <> struct EnumToType<QAttribute::Double> { typedef const double type; };
-
-template<QAttribute::VertexBaseType v>
-typename EnumToType<v>::type *castToType(const QByteArray &u, uint byteOffset)
+template<typename Coordinate>
+QVector4D readCoordinate(const BufferInfo &info, Coordinate *coordinates, uint index)
{
- return reinterpret_cast< typename EnumToType<v>::type *>(u.constData() + byteOffset);
+ const uint stride = info.byteStride / sizeof(Coordinate);
+ QVector4D ret(0, 0, 0, 1.0f);
+ coordinates += stride * index;
+ for (uint e = 0; e < info.dataSize; ++e)
+ ret[e] = coordinates[e];
+ return ret;
}
template<typename Func>
void processBuffer(const BufferInfo &info, Func &f)
{
switch (info.type) {
- case QAttribute::Byte: f(info, castToType<QAttribute::Byte>(info.data, info.byteOffset));
+ case QAttribute::Byte: f(info, BufferTypeInfo::castToType<QAttribute::Byte>(info.data, info.byteOffset));
return;
- case QAttribute::UnsignedByte: f(info, castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset));
+ case QAttribute::UnsignedByte: f(info, BufferTypeInfo::castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset));
return;
- case QAttribute::Short: f(info, castToType<QAttribute::Short>(info.data, info.byteOffset));
+ case QAttribute::Short: f(info, BufferTypeInfo::castToType<QAttribute::Short>(info.data, info.byteOffset));
return;
- case QAttribute::UnsignedShort: f(info, castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset));
+ case QAttribute::UnsignedShort: f(info, BufferTypeInfo::castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset));
return;
- case QAttribute::Int: f(info, castToType<QAttribute::Int>(info.data, info.byteOffset));
+ case QAttribute::Int: f(info, BufferTypeInfo::castToType<QAttribute::Int>(info.data, info.byteOffset));
return;
- case QAttribute::UnsignedInt: f(info, castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset));
+ case QAttribute::UnsignedInt: f(info, BufferTypeInfo::castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset));
return;
- case QAttribute::Float: f(info, castToType<QAttribute::Float>(info.data, info.byteOffset));
+ case QAttribute::Float: f(info, BufferTypeInfo::castToType<QAttribute::Float>(info.data, info.byteOffset));
return;
- case QAttribute::Double: f(info, castToType<QAttribute::Double>(info.data, info.byteOffset));
+ case QAttribute::Double: f(info, BufferTypeInfo::castToType<QAttribute::Double>(info.data, info.byteOffset));
return;
default:
return;
}
}
+QVector4D readBuffer(const BufferInfo &info, uint index)
+{
+ switch (info.type) {
+ case QAttribute::Byte:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::Byte>(info.data, info.byteOffset), index);
+ case QAttribute::UnsignedByte:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset), index);
+ case QAttribute::Short:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::Short>(info.data, info.byteOffset), index);
+ case QAttribute::UnsignedShort:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset), index);
+ case QAttribute::Int:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::Int>(info.data, info.byteOffset), index);
+ case QAttribute::UnsignedInt:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset), index);
+ case QAttribute::Float:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::Float>(info.data, info.byteOffset), index);
+ case QAttribute::Double:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::Double>(info.data, info.byteOffset), index);
+ default:
+ break;
+ }
+ return QVector4D();
+}
+
template<typename Index>
struct IndexedVertexExecutor
{
@@ -530,6 +532,53 @@ void TrianglesVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::Q
}
}
+bool CoordinateReader::setGeometry(const GeometryRenderer *renderer, const QString &attributeName)
+{
+ if (renderer == nullptr || renderer->instanceCount() != 1
+ || !isTriangleBased(renderer->primitiveType())) {
+ return false;
+ }
+
+ Geometry *geom = m_manager->lookupResource<Geometry, GeometryManager>(renderer->geometryId());
+
+ if (!geom)
+ return false;
+
+ Attribute *attribute = nullptr;
+
+ const auto attrIds = geom->attributes();
+ for (const Qt3DCore::QNodeId attrId : attrIds) {
+ attribute = m_manager->lookupResource<Attribute, AttributeManager>(attrId);
+ if (attribute){
+ if (attribute->name() == attributeName
+ || (attributeName == QStringLiteral("default")
+ && attribute->name() == QAttribute::defaultTextureCoordinateAttributeName())) {
+ break;
+ }
+ }
+ attribute = nullptr;
+ }
+
+ if (!attribute)
+ return false;
+
+ m_attribute = attribute;
+ m_buffer = m_manager->lookupResource<Buffer, BufferManager>(attribute->bufferId());
+
+ m_bufferInfo.data = m_buffer->data();
+ m_bufferInfo.type = m_attribute->vertexBaseType();
+ m_bufferInfo.byteOffset = m_attribute->byteOffset();
+ m_bufferInfo.byteStride = m_attribute->byteStride();
+ m_bufferInfo.dataSize = m_attribute->vertexSize();
+ m_bufferInfo.count = m_attribute->count();
+ return true;
+}
+
+QVector4D CoordinateReader::getCoordinate(uint vertexIndex)
+{
+ return readBuffer(m_bufferInfo, vertexIndex);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/trianglesvisitor_p.h b/src/render/backend/trianglesvisitor_p.h
index 5f7cff9c0..9428857ac 100644
--- a/src/render/backend/trianglesvisitor_p.h
+++ b/src/render/backend/trianglesvisitor_p.h
@@ -52,6 +52,10 @@
//
#include <Qt3DCore/qnodeid.h>
+#include <Qt3DRender/QAttribute>
+#include <Qt3DRender/private/bufferutils_p.h>
+
+#include <private/qt3drender_global_p.h>
QT_BEGIN_NAMESPACE
@@ -65,6 +69,8 @@ namespace Render {
class GeometryRenderer;
class NodeManagers;
+class Attribute;
+class Buffer;
class Q_AUTOTEST_EXPORT TrianglesVisitor
{
@@ -84,6 +90,27 @@ protected:
Qt3DCore::QNodeId m_nodeId;
};
+class QT3DRENDERSHARED_PRIVATE_EXPORT CoordinateReader
+{
+public:
+ explicit CoordinateReader(NodeManagers *manager)
+ : m_manager(manager)
+ , m_attribute(nullptr)
+ , m_buffer(nullptr)
+ {
+ }
+
+ bool setGeometry(const GeometryRenderer *renderer, const QString &attributeName);
+
+ QVector4D getCoordinate(uint vertexIndex);
+
+protected:
+ NodeManagers *m_manager;
+ Attribute *m_attribute;
+ Buffer *m_buffer;
+ BufferInfo m_bufferInfo;
+};
+
} // namespace Render
} // namespace Qt3DRender