summaryrefslogtreecommitdiffstats
path: root/src/core/jobs
diff options
context:
space:
mode:
authorMike Krus <mike.krus@kdab.com>2020-02-26 11:01:31 +0000
committerMike Krus <mike.krus@kdab.com>2020-04-22 08:54:47 +0100
commitee476605629a74fb824d3f014deb6e6be9e40e9f (patch)
tree036c630586925a1a0a0bc956b6f15d5752f1ccea /src/core/jobs
parent5f282d1b0d10725e367c1734541da9e99e0cbb08 (diff)
Add bounding volume calculations to core aspect
If an entity uses a QBoundingVolume and a QGeometryView, compute the bounding volume data in the core aspect. All other cases will still happen in the render aspect. Result not currently used (ie it's done again in render aspect). Change-Id: I4b5ed21bac42b79777c3112aa76d876ac5b6f52d Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Diffstat (limited to 'src/core/jobs')
-rw-r--r--src/core/jobs/calcboundingvolumejob.cpp317
-rw-r--r--src/core/jobs/calcboundingvolumejob_p.h113
-rw-r--r--src/core/jobs/job_common_p.h73
-rw-r--r--src/core/jobs/jobs.pri7
4 files changed, 508 insertions, 2 deletions
diff --git a/src/core/jobs/calcboundingvolumejob.cpp b/src/core/jobs/calcboundingvolumejob.cpp
new file mode 100644
index 000000000..37ee92e84
--- /dev/null
+++ b/src/core/jobs/calcboundingvolumejob.cpp
@@ -0,0 +1,317 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 "calcboundingvolumejob_p.h"
+
+#include <Qt3DCore/qattribute.h>
+#include <Qt3DCore/qboundingvolume.h>
+#include <Qt3DCore/qbuffer.h>
+#include <Qt3DCore/qgeometryview.h>
+#include <Qt3DCore/private/job_common_p.h>
+#include <Qt3DCore/private/qaspectjob_p.h>
+#include <Qt3DCore/private/qaspectmanager_p.h>
+#include <Qt3DCore/private/qattribute_p.h>
+#include <Qt3DCore/private/qboundingvolume_p.h>
+#include <Qt3DCore/private/qbuffer_p.h>
+#include <Qt3DCore/private/qentity_p.h>
+#include <Qt3DCore/private/qgeometry_p.h>
+#include <Qt3DCore/private/qgeometryview_p.h>
+#include <Qt3DCore/private/qnodevisitor_p.h>
+
+#include <QtCore/qmath.h>
+#if QT_CONFIG(concurrent)
+#include <QtConcurrent/QtConcurrent>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+namespace {
+
+BoundingVolumeComputeData findBoundingVolumeComputeData(QGeometryView *node)
+{
+ if (!node->isEnabled())
+ return {};
+
+ if (node->primitiveType() == QGeometryView::Patches)
+ return {};
+
+ QGeometry *geom = node->geometry();
+ QGeometryPrivate *dgeom = QGeometryPrivate::get(geom);
+ if (!geom)
+ return {};
+
+ int drawVertexCount = node->vertexCount(); // may be 0, gets changed below if so
+
+ QAttribute *positionAttribute = dgeom->m_boundingVolumePositionAttribute;
+ const QVector<Qt3DCore::QAttribute *> attributes = geom->attributes();
+
+ // Use the default position attribute if attribute is null
+ if (!positionAttribute) {
+ for (QAttribute *attr : attributes) {
+ if (attr->name() == QAttribute::defaultPositionAttributeName()) {
+ positionAttribute = attr;
+ break;
+ }
+ }
+ }
+
+ if (!positionAttribute
+ || positionAttribute->attributeType() != QAttribute::VertexAttribute
+ || positionAttribute->vertexBaseType() != QAttribute::Float
+ || positionAttribute->vertexSize() < 3) {
+ qWarning("findBoundingVolumeComputeData: Position attribute not suited for bounding volume computation");
+ return {};
+ }
+
+ Qt3DCore::QBuffer *positionBuffer = positionAttribute->buffer();
+ // No point in continuing if the positionAttribute doesn't have a suitable buffer
+ if (!positionBuffer) {
+ qWarning("findBoundingVolumeComputeData: Position attribute not referencing a valid buffer");
+ return {};
+ }
+
+ // Check if there is an index attribute.
+ QAttribute *indexAttribute = nullptr;
+ Qt3DCore::QBuffer *indexBuffer = nullptr;
+
+ for (const auto attr : attributes) {
+ if (attr->attributeType() == QAttribute::IndexAttribute) {
+ indexBuffer = attr->buffer();
+ if (indexBuffer) {
+ indexAttribute = attr;
+
+ if (!drawVertexCount)
+ drawVertexCount = static_cast<int>(indexAttribute->count());
+
+ static const QAttribute::VertexBaseType validIndexTypes[] = {
+ QAttribute::UnsignedShort,
+ QAttribute::UnsignedInt,
+ QAttribute::UnsignedByte
+ };
+
+ if (std::find(std::begin(validIndexTypes),
+ std::end(validIndexTypes),
+ indexAttribute->vertexBaseType()) == std::end(validIndexTypes)) {
+ qWarning() << "findBoundingVolumeComputeData: Unsupported index attribute type" << indexAttribute->name() << indexAttribute->vertexBaseType();
+ return {};
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (!indexAttribute && !drawVertexCount)
+ drawVertexCount = static_cast<int>(positionAttribute->count());
+
+ return { nullptr, nullptr, positionAttribute, indexAttribute, drawVertexCount };
+}
+
+BoundingVolumeComputeResult calculateLocalBoundingVolume(const BoundingVolumeComputeData &data) {
+ BoundingVolumeCalculator calculator;
+ if (calculator.apply(data.positionAttribute, data.indexAttribute, data.vertexCount,
+ data.provider->view()->primitiveRestartEnabled(),
+ data.provider->view()->restartIndexValue()))
+ return {
+ data.entity, data.provider, data.positionAttribute, data.indexAttribute,
+ calculator.min(), calculator.max(),
+ calculator.center(), calculator.radius()
+ };
+ return {};
+}
+
+bool isTreeEnabled(QEntity *entity) {
+ if (!entity->isEnabled())
+ return false;
+
+ QEntity *parent = entity->parentEntity();
+ while (parent) {
+ if (!parent->isEnabled())
+ return false;
+ parent = parent->parentEntity();
+ }
+
+ return true;
+}
+
+struct UpdateBoundFunctor
+{
+ // This define is required to work with QtConcurrent
+ typedef QVector<BoundingVolumeComputeResult> result_type;
+ result_type operator ()(const BoundingVolumeComputeData &data)
+ {
+ return { calculateLocalBoundingVolume(data) };
+ }
+};
+
+struct ReduceUpdateBoundFunctor
+{
+ void operator ()(QVector<BoundingVolumeComputeResult> &result, const QVector<BoundingVolumeComputeResult> &values)
+ {
+ result += values;
+ }
+};
+
+} // anonymous
+
+//class CalculateBoundingVolumeJobPrivate : public Qt3DCore::QAspectJobPrivate
+//{
+//public:
+// CalculateBoundingVolumeJobPrivate() { }
+// ~CalculateBoundingVolumeJobPrivate() override { }
+
+// void postFrame(Qt3DCore::QAspectManager *manager) override
+// {
+// Q_UNUSED(manager)
+//// for (Geometry *backend : qAsConst(m_updatedGeometries)) {
+//// Qt3DCore::QGeometry *node = qobject_cast<Qt3DCore::QGeometry *>(manager->lookupNode(backend->peerId()));
+//// if (!node)
+//// continue;
+//// Qt3DCore::QGeometryPrivate *dNode = static_cast<Qt3DCore::QGeometryPrivate *>(Qt3DCore::QNodePrivate::get(node));
+//// dNode->setExtent(backend->min(), backend->max());
+//// }
+// }
+
+//};
+
+CalculateBoundingVolumeJob::CalculateBoundingVolumeJob()
+ : Qt3DCore::QAspectJob()
+ , m_root(nullptr)
+{
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::CalcBoundingVolume, 0)
+}
+
+void CalculateBoundingVolumeJob::run()
+{
+ m_results.clear();
+
+ QHash<QEntity *, BoundingVolumeComputeData> dirtyEntities;
+ QNodeVisitor visitor;
+ visitor.traverse(m_root, [](QNode *) {}, [&dirtyEntities](QEntity *entity) {
+ if (!isTreeEnabled(entity))
+ return;
+
+ const auto bvProviders = entity->componentsOfType<QBoundingVolume>();
+ if (bvProviders.isEmpty())
+ return;
+
+ // we go through the list until be find a dirty provider,
+ // or THE primary provider
+ bool foundBV = false;
+ for (auto bv: bvProviders) {
+ if (!bv->view())
+ continue;
+ auto dbv = QBoundingVolumePrivate::get(bv);
+ if (foundBV && !dbv->m_primaryProvider)
+ continue;
+
+ auto bvdata = findBoundingVolumeComputeData(bv->view());
+ if (!bvdata.valid())
+ continue;
+ bvdata.entity = entity;
+ bvdata.provider = bv;
+
+ bool dirty = QEntityPrivate::get(entity)->m_dirty;
+ dirty |= QGeometryViewPrivate::get(bv->view())->m_dirty;
+ dirty |= QGeometryPrivate::get(bv->view()->geometry())->m_dirty;
+ dirty |= QAttributePrivate::get(bvdata.positionAttribute)->m_dirty;
+ dirty |= QBufferPrivate::get(bvdata.positionAttribute->buffer())->m_dirty;
+ if (bvdata.indexAttribute) {
+ dirty |= QAttributePrivate::get(bvdata.indexAttribute)->m_dirty;
+ dirty |= QBufferPrivate::get(bvdata.indexAttribute->buffer())->m_dirty;
+ }
+
+ if (dbv->m_primaryProvider) {
+ if (dirty)
+ dirtyEntities[entity] = bvdata;
+ break;
+ } else if (dirty) {
+ dirtyEntities[entity] = bvdata;
+ foundBV = true;
+ }
+ }
+ });
+
+#if QT_CONFIG(concurrent)
+ if (dirtyEntities.size() > 1) {
+ UpdateBoundFunctor functor;
+ ReduceUpdateBoundFunctor reduceFunctor;
+ m_results = QtConcurrent::blockingMappedReduced<decltype(m_results)>(dirtyEntities, functor, reduceFunctor);
+ } else
+#endif
+ {
+ for (auto it = dirtyEntities.begin(); it != dirtyEntities.end(); ++it) {
+ auto res = calculateLocalBoundingVolume(it.value());
+ if (res.valid())
+ m_results.push_back(res); // How do we push it to the backends????
+ }
+ }
+
+ for (auto result: qAsConst(m_results)) {
+ // set the results
+ QBoundingVolumePrivate::get(result.provider)->setImplicitBounds(result.m_min, result.m_max, result.m_center, result.m_radius);
+ }
+}
+
+void CalculateBoundingVolumeJob::postFrame(QAspectEngine *aspectEngine)
+{
+ Q_UNUSED(aspectEngine)
+
+ for (auto result: qAsConst(m_results)) {
+ // reset dirty flags
+ QEntityPrivate::get(result.entity)->m_dirty = false;
+ QGeometryViewPrivate::get(result.provider->view())->m_dirty = false;
+ QGeometryPrivate::get(result.provider->view()->geometry())->m_dirty = false;
+ QAttributePrivate::get(result.positionAttribute)->m_dirty = false;
+ QBufferPrivate::get(result.positionAttribute->buffer())->m_dirty = false;
+ if (result.indexAttribute) {
+ QAttributePrivate::get(result.indexAttribute)->m_dirty = false;
+ QBufferPrivate::get(result.indexAttribute->buffer())->m_dirty = false;
+ }
+ }
+
+ m_results.clear();
+}
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
diff --git a/src/core/jobs/calcboundingvolumejob_p.h b/src/core/jobs/calcboundingvolumejob_p.h
new file mode 100644
index 000000000..498fe766f
--- /dev/null
+++ b/src/core/jobs/calcboundingvolumejob_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 QT3DCORE_CALCBOUNDINGVOLUMEJOB_H
+#define QT3DCORE_CALCBOUNDINGVOLUMEJOB_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/qaspectjob.h>
+#include <Qt3DCore/private/qt3dcore_global_p.h>
+
+#include <QtCore/QSharedPointer>
+#include <QtGui/qvector3d.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class CalculateBoundingVolumeJobPrivate;
+class QEntity;
+class QAttribute;
+class QBoundingVolume;
+
+struct BoundingVolumeComputeData {
+ QEntity *entity = nullptr;
+ QBoundingVolume *provider = nullptr;
+ QAttribute *positionAttribute = nullptr;
+ QAttribute *indexAttribute = nullptr;
+ int vertexCount = 0;
+
+ bool valid() const { return positionAttribute != nullptr; }
+};
+
+struct BoundingVolumeComputeResult {
+ QEntity *entity = nullptr;
+ QBoundingVolume *provider = nullptr;
+ QAttribute *positionAttribute = nullptr;
+ QAttribute *indexAttribute = nullptr;
+ QVector3D m_min;
+ QVector3D m_max;
+ QVector3D m_center;
+ float m_radius = -1.f;
+
+ bool valid() const { return m_radius >= 0.f; }
+};
+
+class Q_3DCORE_PRIVATE_EXPORT CalculateBoundingVolumeJob : public Qt3DCore::QAspectJob
+{
+public:
+ explicit CalculateBoundingVolumeJob();
+
+ void setRoot(QEntity *root) { m_root = root; }
+ void run() override;
+ void postFrame(QAspectEngine *aspectEngine) override;
+
+private:
+ Q_DECLARE_PRIVATE(CalculateBoundingVolumeJob)
+ QEntity *m_root;
+ QVector<BoundingVolumeComputeResult> m_results;
+};
+
+typedef QSharedPointer<CalculateBoundingVolumeJob> CalculateBoundingVolumeJobPtr;
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_CALCBOUNDINGVOLUMEJOB_H
diff --git a/src/core/jobs/job_common_p.h b/src/core/jobs/job_common_p.h
new file mode 100644
index 000000000..6cbf17800
--- /dev/null
+++ b/src/core/jobs/job_common_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 QT3DCORE_JOB_COMMON_P_H
+#define QT3DCORE_JOB_COMMON_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/private/qaspectjob_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+namespace JobTypes {
+
+ enum JobType {
+ LoadBuffer = 4096,
+ CalcBoundingVolume,
+ };
+
+} // JobTypes
+
+} // Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_JOB_COMMON_P_H
diff --git a/src/core/jobs/jobs.pri b/src/core/jobs/jobs.pri
index 5d262f5c7..a0453395c 100644
--- a/src/core/jobs/jobs.pri
+++ b/src/core/jobs/jobs.pri
@@ -4,7 +4,8 @@ SOURCES += \
$$PWD/qaspectjobmanager.cpp \
$$PWD/qabstractaspectjobmanager.cpp \
$$PWD/qthreadpooler.cpp \
- $$PWD/task.cpp
+ $$PWD/task.cpp \
+ $$PWD/calcboundingvolumejob.cpp
HEADERS += \
$$PWD/qaspectjob.h \
@@ -13,7 +14,9 @@ HEADERS += \
$$PWD/qaspectjobmanager_p.h \
$$PWD/qabstractaspectjobmanager_p.h \
$$PWD/task_p.h \
- $$PWD/qthreadpooler_p.h
+ $$PWD/qthreadpooler_p.h \
+ $$PWD/calcboundingvolumejob_p.h \
+ $$PWD/job_common_p.h
INCLUDEPATH += $$PWD