1// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qscheduler_p.h"
5
6#include <Qt3DCore/qabstractaspect.h>
7
8#include <Qt3DCore/private/qabstractaspect_p.h>
9#include <Qt3DCore/private/qaspectmanager_p.h>
10#include <Qt3DCore/private/qaspectjob_p.h>
11#include <Qt3DCore/private/qabstractaspectjobmanager_p.h>
12#include <Qt3DCore/private/vector_helper_p.h>
13
14#include <QtCore/QCoreApplication>
15#include <QtCore/QDateTime>
16#include <QtCore/QRegularExpression>
17
18QT_BEGIN_NAMESPACE
19
20namespace {
21
22// Creates a graphviz dot file. To view online: https://dreampuf.github.io/GraphvizOnline/
23void dumpJobs(const std::vector<Qt3DCore::QAspectJobPtr> &jobs) {
24 const QString fileName = QStringLiteral("qt3djobs_") + QCoreApplication::applicationName() +
25 QDateTime::currentDateTime().toString(QStringLiteral("_yyMMdd-hhmmss")) + QStringLiteral(".dot");
26
27 QFile f(fileName);
28 if (!f.open(flags: QFile::WriteOnly))
29 return;
30
31 auto formatJob = [](Qt3DCore::QAspectJob *job) -> QString {
32 auto jobId = Qt3DCore::QAspectJobPrivate::get(job)->m_jobId;
33 auto type = Qt3DCore::QAspectJobPrivate::get(job)->m_jobName.replace(re: QRegularExpression(QLatin1String("(^.*::)")), after: QLatin1String(""));
34 return QString(QLatin1String("\"%1_%2\"")).arg(a: type).arg(a: jobId.typeAndInstance[1]);
35 };
36
37 QTextStream stream(&f);
38 stream << "digraph qt3d_jobs {" << Qt::endl;
39
40 for (const auto &job: jobs) {
41 if (!Qt3DCore::QAspectJobPrivate::get(job: job.data())->isRequired())
42 stream << QLatin1String("\t") << formatJob(job.data()) << QLatin1String(" [style=dotted]") << Qt::endl;
43 }
44
45 for (const auto &job: jobs) {
46 auto dependencies = job->dependencies();
47 for (const auto &dependency: dependencies)
48 stream << QLatin1String("\t") << formatJob(dependency.toStrongRef().data()) << QLatin1String(" -> ") << formatJob(job.data()) << Qt::endl;
49 }
50
51 stream << "}" << Qt::endl;
52}
53
54}
55
56namespace Qt3DCore {
57
58QScheduler::QScheduler(QObject *parent)
59 : QObject(parent)
60 , m_aspectManager(nullptr)
61{
62}
63
64QScheduler::~QScheduler()
65{
66}
67
68void QScheduler::setAspectManager(QAspectManager *aspectManager)
69{
70 m_aspectManager = aspectManager;
71}
72
73QAspectManager *QScheduler::aspectManager() const
74{
75 return m_aspectManager;
76}
77
78int QScheduler::scheduleAndWaitForFrameAspectJobs(qint64 time, bool dumpJobs)
79{
80 std::vector<QAspectJobPtr> jobQueue;
81
82 // TODO: Allow clocks with custom scale factors and independent control
83 // over running / paused / stopped status
84 // TODO: Advance all clocks registered with the engine
85
86 // TODO: Set up dependencies between jobs as needed
87 // For now just queue them up as they are
88 const QList<QAbstractAspect *> &aspects = m_aspectManager->aspects();
89 for (QAbstractAspect *aspect : aspects) {
90 std::vector<QAspectJobPtr> aspectJobs = QAbstractAspectPrivate::get(aspect)->jobsToExecute(time);
91 Qt3DCore::moveAtEnd(destination&: jobQueue, source: std::move(aspectJobs));
92 }
93
94 if (jobQueue.empty())
95 return 0;
96
97 if (dumpJobs)
98 ::dumpJobs(jobs: jobQueue);
99
100 m_aspectManager->jobManager()->enqueueJobs(jobQueue);
101
102 // Do any other work here that the aspect thread can usefully be doing
103 // whilst the threadpool works its way through the jobs
104
105 const int totalJobs = m_aspectManager->jobManager()->waitForAllJobs();
106
107 {
108 QTaskLogger logger(m_aspectManager->serviceLocator()->systemInformation(), 4097, 0, QTaskLogger::AspectJob);
109
110 for (auto &job : std::as_const(t&: jobQueue))
111 job->postFrame(aspectEngine: m_aspectManager->engine());
112
113 for (QAbstractAspect *aspect : aspects)
114 aspect->jobsDone();
115 }
116
117 return totalJobs;
118}
119
120} // namespace Qt3DCore
121
122QT_END_NAMESPACE
123
124#include "moc_qscheduler_p.cpp"
125

source code of qt3d/src/core/qscheduler.cpp