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
15QT_BEGIN_NAMESPACE
16
17namespace Qt3DCore {
18
19QAspectJobManager::QAspectJobManager(QAspectManager *parent)
20 : QAbstractAspectJobManager(parent)
21 , m_threadPooler(new QThreadPooler(this))
22 , m_aspectManager(parent)
23{
24}
25
26QAspectJobManager::~QAspectJobManager()
27{
28}
29
30void QAspectJobManager::initialize()
31{
32}
33
34// Adds all Aspect Jobs to be processed for a frame
35void 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
75int QAspectJobManager::waitForAllJobs()
76{
77 return m_threadPooler->waitForAllJobs();
78}
79
80void 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
96int 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
118QT_END_NAMESPACE
119
120#include "moc_qaspectjobmanager_p.cpp"
121

source code of qt3d/src/core/jobs/qaspectjobmanager.cpp