diff options
Diffstat (limited to 'src/core/aspects/qaspectmanager.cpp')
-rw-r--r-- | src/core/aspects/qaspectmanager.cpp | 167 |
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 |