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 "qaspectjobmanager_p.h" |
5 | |
6 | #include <QtCore/QAtomicInt> |
7 | #include <QtCore/QCoreApplication> |
8 | #include <QtCore/QDebug> |
9 | #include <QtCore/QThread> |
10 | #include <QtCore/QFuture> |
11 | #include <Qt3DCore/private/qaspectmanager_p.h> |
12 | #include <Qt3DCore/private/qthreadpooler_p.h> |
13 | #include <Qt3DCore/private/task_p.h> |
14 | |
15 | QT_BEGIN_NAMESPACE |
16 | |
17 | namespace Qt3DCore { |
18 | |
19 | QAspectJobManager::QAspectJobManager(QAspectManager *parent) |
20 | : QAbstractAspectJobManager(parent) |
21 | , m_threadPooler(new QThreadPooler(this)) |
22 | , m_aspectManager(parent) |
23 | { |
24 | } |
25 | |
26 | QAspectJobManager::~QAspectJobManager() |
27 | { |
28 | } |
29 | |
30 | void QAspectJobManager::initialize() |
31 | { |
32 | } |
33 | |
34 | // Adds all Aspect Jobs to be processed for a frame |
35 | void QAspectJobManager::enqueueJobs(const std::vector<QAspectJobPtr> &jobQueue) |
36 | { |
37 | auto systemService = m_aspectManager ? m_aspectManager->serviceLocator()->systemInformation() : nullptr; |
38 | if (systemService) |
39 | systemService->writePreviousFrameTraces(); |
40 | |
41 | // Convert QJobs to Tasks |
42 | QHash<QAspectJob *, AspectTaskRunnable *> tasksMap; |
43 | QList<RunnableInterface *> taskList; |
44 | taskList.reserve(asize: jobQueue.size()); |
45 | for (const QAspectJobPtr &job : jobQueue) { |
46 | AspectTaskRunnable *task = new AspectTaskRunnable(systemService); |
47 | task->m_job = job; |
48 | tasksMap.insert(key: job.data(), value: task); |
49 | |
50 | taskList << task; |
51 | } |
52 | |
53 | for (const QAspectJobPtr &job : jobQueue) { |
54 | const std::vector<QWeakPointer<QAspectJob> > &deps = job->dependencies(); |
55 | AspectTaskRunnable *taskDepender = tasksMap.value(key: job.data()); |
56 | |
57 | int dependerCount = 0; |
58 | for (const QWeakPointer<QAspectJob> &dep : deps) { |
59 | AspectTaskRunnable *taskDependee = tasksMap.value(key: dep.toStrongRef().data()); |
60 | // The dependencies here are not hard requirements, i.e., the dependencies |
61 | // not in the jobQueue should already have their data ready. |
62 | if (taskDependee) { |
63 | taskDependee->m_dependers.append(t: taskDepender); |
64 | ++dependerCount; |
65 | } |
66 | } |
67 | |
68 | taskDepender->m_dependerCount += dependerCount; |
69 | } |
70 | |
71 | m_threadPooler->mapDependables(taskQueue&: taskList); |
72 | } |
73 | |
74 | // Wait for all aspects jobs to be completed |
75 | int QAspectJobManager::waitForAllJobs() |
76 | { |
77 | return m_threadPooler->waitForAllJobs(); |
78 | } |
79 | |
80 | void QAspectJobManager::waitForPerThreadFunction(JobFunction func, void *arg) |
81 | { |
82 | const int threadCount = QAspectJobManager::idealThreadCount(); |
83 | QAtomicInt atomicCount(threadCount); |
84 | |
85 | QList<RunnableInterface *> taskList; |
86 | for (int i = 0; i < threadCount; ++i) { |
87 | SyncTaskRunnable *syncTask = new SyncTaskRunnable(func, arg, &atomicCount); |
88 | taskList << syncTask; |
89 | } |
90 | |
91 | QFuture<void> future = m_threadPooler->mapDependables(taskQueue&: taskList); |
92 | future.waitForFinished(); |
93 | } |
94 | |
95 | |
96 | int QAspectJobManager::idealThreadCount() |
97 | { |
98 | static int jobCount = 0; |
99 | if (jobCount) |
100 | return jobCount; |
101 | |
102 | const QByteArray maxThreadCount = qgetenv(varName: "QT3D_MAX_THREAD_COUNT"); |
103 | if (!maxThreadCount.isEmpty()) { |
104 | bool conversionOK = false; |
105 | const int maxThreadCountValue = maxThreadCount.toInt(ok: &conversionOK); |
106 | if (conversionOK) { |
107 | jobCount = maxThreadCountValue; |
108 | return jobCount; |
109 | } |
110 | } |
111 | |
112 | jobCount = QThread::idealThreadCount(); |
113 | return jobCount; |
114 | } |
115 | |
116 | } // namespace Qt3DCore |
117 | |
118 | QT_END_NAMESPACE |
119 | |
120 | #include "moc_qaspectjobmanager_p.cpp" |
121 |