summaryrefslogtreecommitdiffstats
path: root/src/core/aspects/qaspectmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/aspects/qaspectmanager.cpp')
-rw-r--r--src/core/aspects/qaspectmanager.cpp167
1 files changed, 100 insertions, 67 deletions
diff --git a/src/core/aspects/qaspectmanager.cpp b/src/core/aspects/qaspectmanager.cpp
index 71e05b34f..f0dc366b2 100644
--- a/src/core/aspects/qaspectmanager.cpp
+++ b/src/core/aspects/qaspectmanager.cpp
@@ -57,6 +57,7 @@
#include <Qt3DCore/private/qchangearbiter_p.h>
#include <Qt3DCore/private/qscheduler_p.h>
#include <Qt3DCore/private/qservicelocator_p.h>
+#include <Qt3DCore/private/qsysteminformationservice_p_p.h>
#include <Qt3DCore/private/qthreadpooler_p.h>
#include <Qt3DCore/private/qtickclock_p.h>
#include <Qt3DCore/private/qtickclockservice_p.h>
@@ -65,15 +66,29 @@
#include <Qt3DCore/private/qscene_p.h>
#include <QtCore/QCoreApplication>
-
-#if defined(QT3D_CORE_JOB_TIMING)
-#include <QElapsedTimer>
-#endif
+#include <QtCore/QAbstractAnimation>
QT_BEGIN_NAMESPACE
namespace Qt3DCore {
+#if QT_CONFIG(animation)
+class RequestFrameAnimation final : public QAbstractAnimation
+{
+public:
+ RequestFrameAnimation(QObject *parent)
+ : QAbstractAnimation(parent)
+ {
+ }
+
+ ~RequestFrameAnimation() override;
+
+ int duration() const override { return 1; }
+ void updateCurrentTime(int currentTime) override { Q_UNUSED(currentTime) }
+};
+
+RequestFrameAnimation::~RequestFrameAnimation() = default;
+#else
namespace {
class RequestFrameEvent : public QEvent
@@ -92,21 +107,27 @@ private:
int RequestFrameEvent::requestEventType = QEvent::registerEventType();
} // anonymous
-
+#endif
/*!
\class Qt3DCore::QAspectManager
\internal
*/
-QAspectManager::QAspectManager(QObject *parent)
+QAspectManager::QAspectManager(QAspectEngine *parent)
: QObject(parent)
+ , m_engine(parent)
, m_root(nullptr)
, m_scheduler(new QScheduler(this))
, m_jobManager(new QAspectJobManager(this))
, m_changeArbiter(new QChangeArbiter(this))
- , m_serviceLocator(new QServiceLocator())
+ , m_serviceLocator(new QServiceLocator(parent))
, m_simulationLoopRunning(false)
, m_driveMode(QAspectEngine::Automatic)
+ , m_postConstructorInit(nullptr)
+#if QT_CONFIG(animation)
+ , m_simulationAnimation(nullptr)
+#endif
+ , m_jobsInLastFrame(0)
{
qRegisterMetaType<QSurface *>("QSurface*");
qCDebug(Aspects) << Q_FUNC_INFO;
@@ -148,8 +169,19 @@ void QAspectManager::enterSimulationLoop()
qCDebug(Aspects) << "Done calling onEngineStartup() for each aspect";
// Start running loop if Qt3D is in charge of driving it
- if (m_driveMode == QAspectEngine::Automatic)
+ if (m_driveMode == QAspectEngine::Automatic) {
+#if QT_CONFIG(animation)
+ if (!m_simulationAnimation) {
+ m_simulationAnimation = new RequestFrameAnimation(this);
+ connect(m_simulationAnimation, &QAbstractAnimation::finished, this, [this]() {
+ processFrame();
+ if (m_simulationLoopRunning && m_driveMode == QAspectEngine::Automatic)
+ requestNextFrame();
+ });
+ }
+#endif
requestNextFrame();
+ }
}
// Main thread (called by QAspectEngine)
@@ -163,6 +195,11 @@ void QAspectManager::exitSimulationLoop()
return;
}
+#if QT_CONFIG(animation)
+ if (m_simulationAnimation)
+ m_simulationAnimation->stop();
+#endif
+
QAbstractFrameAdvanceService *frameAdvanceService =
m_serviceLocator->service<QAbstractFrameAdvanceService>(QServiceLocator::FrameAdvanceService);
if (frameAdvanceService)
@@ -192,7 +229,6 @@ void QAspectManager::exitSimulationLoop()
}
qCDebug(Aspects) << "Done calling onEngineShutdown() for each aspect";
-
m_simulationLoopRunning = false;
qCDebug(Aspects) << "exitSimulationLoop completed";
}
@@ -398,6 +434,7 @@ QVector<QNode *> QAspectManager::lookupNodes(const QVector<QNodeId> &ids) const
return d->m_scene ? d->m_scene->lookupNodes(ids) : QVector<QNode *>{};
}
+#if !QT_CONFIG(animation)
/*!
\internal
\brief Drives the Qt3D simulation loop in the main thread
@@ -413,17 +450,24 @@ bool QAspectManager::event(QEvent *e)
// the loop
if (m_simulationLoopRunning && m_driveMode == QAspectEngine::Automatic)
requestNextFrame();
+
+ return true;
}
return QObject::event(e);
}
+#endif
void QAspectManager::requestNextFrame()
{
qCDebug(Aspects) << "Requesting new Frame";
// Post event in the event loop to force
// next frame to be processed
- qApp->postEvent(this, new RequestFrameEvent());
+#if QT_CONFIG(animation)
+ m_simulationAnimation->start();
+#else
+ QCoreApplication::postEvent(this, new RequestFrameEvent());
+#endif
}
void QAspectManager::processFrame()
@@ -435,6 +479,8 @@ void QAspectManager::processFrame()
m_serviceLocator->service<QAbstractFrameAdvanceService>(QServiceLocator::FrameAdvanceService);
const qint64 t = frameAdvanceService->waitForNextFrame();
+ if (t < 0)
+ return;
// Distribute accumulated changes. This includes changes sent from the frontend
// to the backend nodes. We call this before the call to m_scheduler->update() to ensure
@@ -444,71 +490,58 @@ void QAspectManager::processFrame()
//
// Doing this as the first call in the new frame ensures the lock free approach works
// without any such data race.
-#if QT_CONFIG(qt3d_profile_jobs)
- const quint32 arbiterId = 4096;
- JobRunStats changeArbiterStats;
- changeArbiterStats.jobId.typeAndInstance[0] = arbiterId;
- changeArbiterStats.jobId.typeAndInstance[1] = 0;
- changeArbiterStats.threadId = reinterpret_cast<quint64>(QThread::currentThreadId());
- changeArbiterStats.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
-#endif
-
- // Tell the NodePostConstructorInit to process any pending nodes which will add them to our list of
- // tree changes
- m_postConstructorInit->processNodes();
-
- // Add and Remove Nodes
- const QVector<NodeTreeChange> nodeTreeChanges = std::move(m_nodeTreeChanges);
- for (const NodeTreeChange &change : nodeTreeChanges) {
- // Buckets ensure that even if we have intermingled node added / removed
- // buckets, we preserve the order of the sequences
-
- for (QAbstractAspect *aspect : qAsConst(m_aspects)) {
- switch (change.type) {
- case NodeTreeChange::Added:
- aspect->d_func()->createBackendNode(change);
- break;
- case NodeTreeChange::Removed:
- aspect->d_func()->clearBackendNode(change);
- break;
+ {
+ // scope for QTaskLogger
+ QTaskLogger logger(m_serviceLocator->systemInformation(), 4096, 0, QTaskLogger::AspectJob);
+
+ // Tell the NodePostConstructorInit to process any pending nodes which will add them to our list of
+ // tree changes
+ m_postConstructorInit->processNodes();
+
+ // Add and Remove Nodes
+ const QVector<NodeTreeChange> nodeTreeChanges = std::move(m_nodeTreeChanges);
+ for (const NodeTreeChange &change : nodeTreeChanges) {
+ // Buckets ensure that even if we have intermingled node added / removed
+ // buckets, we preserve the order of the sequences
+
+ for (QAbstractAspect *aspect : qAsConst(m_aspects)) {
+ switch (change.type) {
+ case NodeTreeChange::Added:
+ aspect->d_func()->createBackendNode(change);
+ break;
+ case NodeTreeChange::Removed:
+ aspect->d_func()->clearBackendNode(change);
+ break;
+ }
}
}
- }
-
- // Sync node / subnode relationship changes
- const auto dirtySubNodes = m_changeArbiter->takeDirtyFrontEndSubNodes();
- if (dirtySubNodes.size())
- for (QAbstractAspect *aspect : qAsConst(m_aspects))
- aspect->syncDirtyFrontEndSubNodes(dirtySubNodes);
- // Sync property updates
- const auto dirtyFrontEndNodes = m_changeArbiter->takeDirtyFrontEndNodes();
- if (dirtyFrontEndNodes.size())
- for (QAbstractAspect *aspect : qAsConst(m_aspects))
- aspect->syncDirtyFrontEndNodes(dirtyFrontEndNodes);
-
- // TO DO: Having this done in the main thread actually means aspects could just
- // as simply read info out of the Frontend classes without risk of introducing
- // races. This could therefore be removed for Qt 6.
- m_changeArbiter->syncChanges();
-#if QT_CONFIG(qt3d_profile_jobs)
- changeArbiterStats.endTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
- QThreadPooler::addJobLogStatsEntry(changeArbiterStats);
-#endif
+ // Sync node / subnode relationship changes
+ const auto dirtySubNodes = m_changeArbiter->takeDirtyFrontEndSubNodes();
+ if (dirtySubNodes.size())
+ for (QAbstractAspect *aspect : qAsConst(m_aspects))
+ QAbstractAspectPrivate::get(aspect)->syncDirtyFrontEndSubNodes(dirtySubNodes);
+
+ // Sync property updates
+ const auto dirtyFrontEndNodes = m_changeArbiter->takeDirtyFrontEndNodes();
+ if (dirtyFrontEndNodes.size())
+ for (QAbstractAspect *aspect : qAsConst(m_aspects))
+ QAbstractAspectPrivate::get(aspect)->syncDirtyFrontEndNodes(dirtyFrontEndNodes);
+
+ // TO DO: Having this done in the main thread actually means aspects could just
+ // as simply read info out of the Frontend classes without risk of introducing
+ // races. This could therefore be removed for Qt 6.
+ m_changeArbiter->syncChanges();
+ }
// For each Aspect
// Ask them to launch set of jobs for the current frame
// Updates matrices, bounding volumes, render bins ...
-#if defined(QT3D_CORE_JOB_TIMING)
- QElapsedTimer timer;
- timer.start();
-#endif
- m_scheduler->scheduleAndWaitForFrameAspectJobs(t);
-#if defined(QT3D_CORE_JOB_TIMING)
- qDebug() << "Jobs took" << timer.nsecsElapsed() / 1.0e6;
-#endif
+ m_jobsInLastFrame = m_scheduler->scheduleAndWaitForFrameAspectJobs(t);
- // TODO sync backend changes to frontend
+ // Tell the aspect the frame is complete (except rendering)
+ for (QAbstractAspect *aspect : qAsConst(m_aspects))
+ QAbstractAspectPrivate::get(aspect)->frameDone();
}
} // namespace Qt3DCore