diff options
author | Sean Harmer <sean.harmer@kdab.com> | 2017-09-12 12:10:03 +0100 |
---|---|---|
committer | Sean Harmer <sean.harmer@kdab.com> | 2017-09-12 12:39:05 +0100 |
commit | 3f03499bf8a7cf3c3f8d19a020179c1205980bde (patch) | |
tree | 518b0ef3fb1b31d3856f43124150ef41acb8c1aa /src/core | |
parent | 8a4b9ebadb9e63ae367694f04786c7faf6306f27 (diff) | |
parent | bf5fd7a78c91e29332ce70ad844b756150f32f18 (diff) |
Merge branch '5.9' into 5.10
Change-Id: Id6a3d4ec579a2f2a2e559c22a2293d0e184f0bdf
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/jobs/dependencyhandler.cpp | 157 | ||||
-rw-r--r-- | src/core/jobs/dependencyhandler_p.h | 116 | ||||
-rw-r--r-- | src/core/jobs/jobs.pri | 4 | ||||
-rw-r--r-- | src/core/jobs/qaspectjobmanager.cpp | 21 | ||||
-rw-r--r-- | src/core/jobs/qaspectjobmanager_p.h | 1 | ||||
-rw-r--r-- | src/core/jobs/qthreadpooler.cpp | 35 | ||||
-rw-r--r-- | src/core/jobs/qthreadpooler_p.h | 4 | ||||
-rw-r--r-- | src/core/jobs/task.cpp | 24 | ||||
-rw-r--r-- | src/core/jobs/task_p.h | 26 | ||||
-rw-r--r-- | src/core/resources/qhandle_p.h | 27 | ||||
-rw-r--r-- | src/core/resources/qhandlemanager_p.h | 263 | ||||
-rw-r--r-- | src/core/resources/qresourcemanager_p.h | 213 | ||||
-rw-r--r-- | src/core/resources/resources.pri | 1 |
13 files changed, 136 insertions, 756 deletions
diff --git a/src/core/jobs/dependencyhandler.cpp b/src/core/jobs/dependencyhandler.cpp deleted file mode 100644 index 6a925d037..000000000 --- a/src/core/jobs/dependencyhandler.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "dependencyhandler_p.h" - -#include <iterator> - -QT_BEGIN_NAMESPACE - -namespace Qt3DCore { - -namespace { - template <template <typename T> class Op> - struct ByDepender { - typedef bool result_type; - - bool operator()(const RunnableInterface *lhs, const RunnableInterface *rhs) const Q_DECL_NOTHROW - { return Op<const RunnableInterface *>()(lhs, rhs); } - - bool operator()(const RunnableInterface *lhs, const Dependency &rhs) const Q_DECL_NOTHROW - { return operator()(lhs, rhs.depender); } - - bool operator()(const Dependency &lhs, const RunnableInterface *rhs) const Q_DECL_NOTHROW - { return operator()(lhs.depender, rhs); } - - bool operator()(const Dependency &lhs, const Dependency &rhs) const Q_DECL_NOTHROW - { return operator()(lhs.depender, rhs.depender); } - }; - - struct DependeeEquals : std::unary_function<Dependency, bool> - { - const RunnableInterface *dependee; - QVector<RunnableInterface *> *freedList; - explicit DependeeEquals(const RunnableInterface *dependee, QVector<RunnableInterface *> *freedList) - : dependee(qMove(dependee)), freedList(qMove(freedList)) {} - bool operator()(const Dependency &candidate) const - { - if (dependee == candidate.dependee) { - if (!candidate.depender->reserved()) - freedList->append(candidate.depender); - return true; - } - return false; - } - }; - - struct DependerEquals : std::unary_function<Dependency, bool> - { - const RunnableInterface *depender; - explicit DependerEquals(const RunnableInterface *depender) - : depender(qMove(depender)) {} - bool operator()(const Dependency &candidate) const - { - return depender == candidate.depender; - } - }; - - struct ByDependerThenDependee : std::binary_function<Dependency, Dependency, bool> - { - // Defines a lexicographical order (depender first). - bool operator()(const Dependency &lhs, const Dependency &rhs) - { - if (lhs.depender < rhs.depender) return true; - if (rhs.depender < lhs.depender) return false; - return lhs.dependee < rhs.dependee; - } - }; -} - -DependencyHandler::DependencyHandler() - : m_mutex() -{ -} - -void DependencyHandler::addDependencies(QVector<Dependency> dependencies) -{ - std::sort(dependencies.begin(), dependencies.end(), ByDependerThenDependee()); - - const QMutexLocker locker(m_mutex); - - QVector<Dependency> newDependencyMap; - newDependencyMap.reserve(dependencies.size() + m_dependencyMap.size()); - std::set_union(m_dependencyMap.begin(), m_dependencyMap.end(), - dependencies.begin(), dependencies.end(), - std::back_inserter(newDependencyMap), ByDependerThenDependee()); - m_dependencyMap.swap(newDependencyMap); // commit -} - -bool DependencyHandler::hasDependency(const RunnableInterface *depender) -{ - // The caller has to set the mutex, which is QThreadPooler::enqueueTasks - - return std::binary_search(m_dependencyMap.begin(), m_dependencyMap.end(), - depender, ByDepender<std::less>()); -} - -/* - * Removes all the entries on the m_dependencyMap that have given task as a dependee, - * i.e. entries where the dependency is on the given task. - */ -QVector<RunnableInterface *> DependencyHandler::freeDependencies(const RunnableInterface *task) -{ - // The caller has to set the mutex, which is QThreadPooler::taskFinished - - m_dependencyMap.erase(std::remove_if(m_dependencyMap.begin(), - m_dependencyMap.end(), - DependerEquals(task)), - m_dependencyMap.end()); - - QVector<RunnableInterface *> freedList; - m_dependencyMap.erase(std::remove_if(m_dependencyMap.begin(), - m_dependencyMap.end(), - DependeeEquals(task, &freedList)), - m_dependencyMap.end()); - - return freedList; -} - -} // namespace Qt3DCore - -QT_END_NAMESPACE diff --git a/src/core/jobs/dependencyhandler_p.h b/src/core/jobs/dependencyhandler_p.h deleted file mode 100644 index a5a023139..000000000 --- a/src/core/jobs/dependencyhandler_p.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DCORE_DEPENDENCYHANDLER_P_H -#define QT3DCORE_DEPENDENCYHANDLER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/QMutex> -#include <QtCore/QVector> - -#include <Qt3DCore/private/task_p.h> - -QT_BEGIN_NAMESPACE - -namespace Qt3DCore { - -struct Dependency -{ - Dependency() - : depender(nullptr) - , dependee(nullptr) - {} - Dependency(RunnableInterface *depender, RunnableInterface *dependee) - : depender(qMove(depender)), - dependee(qMove(dependee)) {} - - RunnableInterface *depender; - RunnableInterface *dependee; -}; - -} // namespace Qt3DCore - -template <> -class QTypeInfo<Qt3DCore::Dependency> : public QTypeInfoMerger<Qt3DCore::Dependency, Qt3DCore::RunnableInterface *> {}; - -namespace Qt3DCore { - -inline bool operator==(const Dependency &left, const Dependency &right) -{ - return left.depender == right.depender && left.dependee == right.dependee; -} - -inline bool operator!=(const Dependency &left, const Dependency &right) -{ - return !operator==(left, right); -} - -class DependencyHandler -{ -public: - DependencyHandler(); - - void addDependencies(QVector<Dependency> dependencies); - bool hasDependency(const RunnableInterface *depender); - QVector<RunnableInterface *> freeDependencies(const RunnableInterface *task); - void setMutex(QMutex *mutex) { m_mutex = mutex; } - -private: - Q_DISABLE_COPY(DependencyHandler) - - QVector<Dependency> m_dependencyMap; - QMutex *m_mutex; -}; - -} // namespace Qt3DCore - -QT_END_NAMESPACE - -#endif // QT3DCORE_DEPENDENCYHANDLER_P_H - diff --git a/src/core/jobs/jobs.pri b/src/core/jobs/jobs.pri index d12c42237..5d262f5c7 100644 --- a/src/core/jobs/jobs.pri +++ b/src/core/jobs/jobs.pri @@ -4,8 +4,7 @@ SOURCES += \ $$PWD/qaspectjobmanager.cpp \ $$PWD/qabstractaspectjobmanager.cpp \ $$PWD/qthreadpooler.cpp \ - $$PWD/task.cpp \ - $$PWD/dependencyhandler.cpp + $$PWD/task.cpp HEADERS += \ $$PWD/qaspectjob.h \ @@ -13,7 +12,6 @@ HEADERS += \ $$PWD/qaspectjobproviderinterface_p.h \ $$PWD/qaspectjobmanager_p.h \ $$PWD/qabstractaspectjobmanager_p.h \ - $$PWD/dependencyhandler_p.h \ $$PWD/task_p.h \ $$PWD/qthreadpooler_p.h diff --git a/src/core/jobs/qaspectjobmanager.cpp b/src/core/jobs/qaspectjobmanager.cpp index e543b60a2..328899433 100644 --- a/src/core/jobs/qaspectjobmanager.cpp +++ b/src/core/jobs/qaspectjobmanager.cpp @@ -45,7 +45,6 @@ #include <QtCore/QThread> #include <QtCore/QFuture> -#include <Qt3DCore/private/dependencyhandler_p.h> #include <Qt3DCore/private/qthreadpooler_p.h> #include <Qt3DCore/private/task_p.h> @@ -56,9 +55,7 @@ namespace Qt3DCore { QAspectJobManager::QAspectJobManager(QObject *parent) : QAbstractAspectJobManager(parent) , m_threadPooler(new QThreadPooler(this)) - , m_dependencyHandler(new DependencyHandler) { - m_threadPooler->setDependencyHandler(m_dependencyHandler.data()); } QAspectJobManager::~QAspectJobManager() @@ -84,24 +81,24 @@ void QAspectJobManager::enqueueJobs(const QVector<QAspectJobPtr> &jobQueue) taskList << task; } - // Resolve dependencies - QVector<Dependency> dependencyList; - for (const QSharedPointer<QAspectJob> &job : jobQueue) { const QVector<QWeakPointer<QAspectJob> > &deps = job->dependencies(); + AspectTaskRunnable *taskDepender = tasksMap.value(job.data()); + int dependerCount = 0; for (const QWeakPointer<QAspectJob> &dep : deps) { AspectTaskRunnable *taskDependee = tasksMap.value(dep.data()); - + // The dependencies here are not hard requirements, i.e., the dependencies + // not in the jobQueue should already have their data ready. if (taskDependee) { - AspectTaskRunnable *taskDepender = tasksMap.value(job.data()); - dependencyList.append(Dependency(taskDepender, taskDependee)); - taskDepender->setDependencyHandler(m_dependencyHandler.data()); - taskDependee->setDependencyHandler(m_dependencyHandler.data()); + taskDependee->m_dependers.append(taskDepender); + ++dependerCount; } } + + taskDepender->m_dependerCount += dependerCount; } - m_dependencyHandler->addDependencies(qMove(dependencyList)); + #if QT_CONFIG(qt3d_profile_jobs) QThreadPooler::writeFrameJobLogStats(); #endif diff --git a/src/core/jobs/qaspectjobmanager_p.h b/src/core/jobs/qaspectjobmanager_p.h index 6fbf03d22..fac71f057 100644 --- a/src/core/jobs/qaspectjobmanager_p.h +++ b/src/core/jobs/qaspectjobmanager_p.h @@ -81,7 +81,6 @@ public: private: QThreadPooler *m_threadPooler; - QScopedPointer<DependencyHandler> m_dependencyHandler; }; } // namespace Qt3DCore diff --git a/src/core/jobs/qthreadpooler.cpp b/src/core/jobs/qthreadpooler.cpp index 57a1b09a6..6819faca7 100644 --- a/src/core/jobs/qthreadpooler.cpp +++ b/src/core/jobs/qthreadpooler.cpp @@ -48,8 +48,6 @@ #include <QtCore/QCoreApplication> #endif -#include <Qt3DCore/private/dependencyhandler_p.h> - QT_BEGIN_NAMESPACE namespace Qt3DCore { @@ -62,7 +60,6 @@ QThreadPooler::QThreadPooler(QObject *parent) : QObject(parent) , m_futureInterface(nullptr) , m_mutex() - , m_dependencyHandler(nullptr) , m_taskCount(0) { const QByteArray maxThreadCount = qgetenv("QT3D_MAX_THREAD_COUNT"); @@ -86,12 +83,6 @@ QThreadPooler::~QThreadPooler() locker.unlock(); } -void QThreadPooler::setDependencyHandler(DependencyHandler *handler) -{ - m_dependencyHandler = handler; - m_dependencyHandler->setMutex(&m_mutex); -} - void QThreadPooler::enqueueTasks(const QVector<RunnableInterface *> &tasks) { // The caller have to set the mutex @@ -99,7 +90,14 @@ void QThreadPooler::enqueueTasks(const QVector<RunnableInterface *> &tasks) for (QVector<RunnableInterface *>::const_iterator it = tasks.cbegin(); it != end; ++it) { - if (!m_dependencyHandler->hasDependency((*it)) && !(*it)->reserved()) { + + // Only AspectTaskRunnables are checked for dependencies. + static const auto hasDependencies = [](RunnableInterface *task) -> bool { + return (task->type() == RunnableInterface::RunnableType::AspectTask) + && (static_cast<AspectTaskRunnable *>(task)->m_dependerCount > 0); + }; + + if (!hasDependencies(*it) && !(*it)->reserved()) { (*it)->setReserved(true); (*it)->setPooler(this); m_threadPool.start((*it)); @@ -113,10 +111,19 @@ void QThreadPooler::taskFinished(RunnableInterface *task) release(); - if (task->dependencyHandler()) { - const QVector<RunnableInterface *> freedTasks = m_dependencyHandler->freeDependencies(task); - if (!freedTasks.empty()) - enqueueTasks(freedTasks); + if (task->type() == RunnableInterface::RunnableType::AspectTask) { + AspectTaskRunnable *aspectTask = static_cast<AspectTaskRunnable *>(task); + const auto &dependers = aspectTask->m_dependers; + for (auto it = dependers.begin(); it != dependers.end(); ++it) { + aspectTask = static_cast<AspectTaskRunnable *>(*it); + if (--aspectTask->m_dependerCount == 0) { + if (!aspectTask->reserved()) { + aspectTask->setReserved(true); + aspectTask->setPooler(this); + m_threadPool.start(aspectTask); + } + } + } } if (currentCount() == 0) { diff --git a/src/core/jobs/qthreadpooler_p.h b/src/core/jobs/qthreadpooler_p.h index 5a2104cdd..00742f8fc 100644 --- a/src/core/jobs/qthreadpooler_p.h +++ b/src/core/jobs/qthreadpooler_p.h @@ -57,7 +57,6 @@ #include <QtCore/QSharedPointer> #include <QtCore/QThreadPool> -#include <Qt3DCore/private/dependencyhandler_p.h> #include <Qt3DCore/private/qaspectjob_p.h> #include <Qt3DCore/private/task_p.h> @@ -81,8 +80,6 @@ public: void taskFinished(RunnableInterface *task); QFuture<void> future(); - void setDependencyHandler(DependencyHandler *handler); - int maxThreadCount() const; #if QT_CONFIG(qt3d_profile_jobs) static QElapsedTimer m_jobsStatTimer; @@ -105,7 +102,6 @@ private: private: QFutureInterface<void> *m_futureInterface; QMutex m_mutex; - DependencyHandler *m_dependencyHandler; QAtomicInt m_taskCount; QThreadPool m_threadPool; }; diff --git a/src/core/jobs/task.cpp b/src/core/jobs/task.cpp index cbaa993b1..4291a4779 100644 --- a/src/core/jobs/task.cpp +++ b/src/core/jobs/task.cpp @@ -43,7 +43,6 @@ #include <QtCore/QElapsedTimer> #include <QtCore/QMutexLocker> -#include <Qt3DCore/private/dependencyhandler_p.h> #include <Qt3DCore/private/qthreadpooler_p.h> QT_BEGIN_NAMESPACE @@ -57,8 +56,7 @@ RunnableInterface::~RunnableInterface() // Aspect task AspectTaskRunnable::AspectTaskRunnable() - : m_dependencyHandler(nullptr) - , m_pooler(nullptr) + : m_pooler(nullptr) , m_reserved(false) { } @@ -94,16 +92,6 @@ void AspectTaskRunnable::run() m_pooler->taskFinished(this); } -void AspectTaskRunnable::setDependencyHandler(DependencyHandler *handler) -{ - m_dependencyHandler = handler; -} - -DependencyHandler *AspectTaskRunnable::dependencyHandler() -{ - return m_dependencyHandler; -} - // Synchronized task SyncTaskRunnable::SyncTaskRunnable(QAbstractAspectJobManager::JobFunction func, @@ -137,16 +125,6 @@ void SyncTaskRunnable::run() m_pooler->taskFinished(this); } -void SyncTaskRunnable::setDependencyHandler(DependencyHandler *handler) -{ - Q_UNUSED(handler); -} - -DependencyHandler *SyncTaskRunnable::dependencyHandler() -{ - return nullptr; -} - } // namespace Qt3DCore { QT_END_NAMESPACE diff --git a/src/core/jobs/task_p.h b/src/core/jobs/task_p.h index 8193abaf6..91e3f5f3d 100644 --- a/src/core/jobs/task_p.h +++ b/src/core/jobs/task_p.h @@ -69,13 +69,15 @@ class QThreadPooler; class RunnableInterface : public QRunnable { public: + enum class RunnableType { + AspectTask, + SyncTask + }; + virtual ~RunnableInterface(); virtual void run() = 0; - virtual void setDependencyHandler(DependencyHandler *) = 0; - virtual DependencyHandler *dependencyHandler() = 0; - virtual int id() = 0; virtual void setId(int id) = 0; @@ -83,6 +85,8 @@ public: virtual bool reserved() = 0; virtual void setPooler(QThreadPooler *pooler) = 0; + + virtual RunnableType type() const = 0; }; class AspectTaskRunnable : public RunnableInterface @@ -93,9 +97,6 @@ public: void run() Q_DECL_OVERRIDE; - void setDependencyHandler(DependencyHandler *handler) Q_DECL_OVERRIDE; - DependencyHandler *dependencyHandler() Q_DECL_OVERRIDE; - void setPooler(QThreadPooler *pooler) Q_DECL_OVERRIDE { m_pooler = pooler; } void setReserved(bool reserved) Q_DECL_OVERRIDE { m_reserved = reserved; } @@ -104,15 +105,17 @@ public: int id() Q_DECL_OVERRIDE { return m_id; } void setId(int id) Q_DECL_OVERRIDE { m_id = id; } + RunnableType type() const Q_DECL_OVERRIDE { return RunnableType::AspectTask; } + public: QSharedPointer<QAspectJob> m_job; + QVector<AspectTaskRunnable *> m_dependers; + int m_dependerCount = 0; private: - DependencyHandler *m_dependencyHandler; QThreadPooler *m_pooler; - bool m_reserved; - int m_id; // For testing purposes for now + bool m_reserved; }; class SyncTaskRunnable : public RunnableInterface @@ -124,9 +127,6 @@ public: void run() Q_DECL_OVERRIDE; - void setDependencyHandler(DependencyHandler *handler) Q_DECL_OVERRIDE; - DependencyHandler *dependencyHandler() Q_DECL_OVERRIDE; - void setPooler(QThreadPooler *pooler) Q_DECL_OVERRIDE { m_pooler = pooler; } void setReserved(bool reserved) Q_DECL_OVERRIDE { m_reserved = reserved; } @@ -135,6 +135,8 @@ public: int id() Q_DECL_OVERRIDE { return m_id; } void setId(int id) Q_DECL_OVERRIDE { m_id = id; } + RunnableType type() const Q_DECL_OVERRIDE { return RunnableType::SyncTask; } + private: QAbstractAspectJobManager::JobFunction m_func; void *m_arg; diff --git a/src/core/resources/qhandle_p.h b/src/core/resources/qhandle_p.h index 94dc7ca45..c4b53ec21 100644 --- a/src/core/resources/qhandle_p.h +++ b/src/core/resources/qhandle_p.h @@ -53,6 +53,7 @@ #include <Qt3DCore/qt3dcore_global.h> #include <QtCore/QDebug> +#include <limits.h> class tst_Handle; // needed for friend class declaration below @@ -60,9 +61,6 @@ QT_BEGIN_NAMESPACE namespace Qt3DCore { -template <typename T, uint INDEXBITS> -class QHandleManager; - template <typename T, uint INDEXBITS = 16> class QHandle { @@ -82,18 +80,6 @@ public: static quint32 maxIndex() { return MaxIndex; } static quint32 maxCounter() { return MaxCounter; } - -private: - enum { - // Sizes to use for bit fields - IndexBits = INDEXBITS, - CounterBits = 32 - INDEXBITS - 2, // We use 2 bits for book-keeping in QHandleManager - - // Sizes to compare against for asserting dereferences - MaxIndex = (1 << IndexBits) - 1, - MaxCounter = (1 << CounterBits) - 1 - }; - QHandle(quint32 i, quint32 count) { d.m_index = i; @@ -103,10 +89,17 @@ private: Q_ASSERT(count < MaxCounter); } + enum { + // Sizes to use for bit fields + IndexBits = INDEXBITS, + CounterBits = 32 - INDEXBITS - 2, // We use 2 bits for book-keeping in QHandleManager - friend class QHandleManager<T, INDEXBITS>; - friend class ::tst_Handle; + // Sizes to compare against for asserting dereferences + MaxIndex = (1 << IndexBits) - 1, + MaxCounter = ((1 << CounterBits) - 1 > SHRT_MAX) ? SHRT_MAX - 1 : (1 << CounterBits) - 1 + }; +private: struct Data { quint32 m_index : IndexBits; quint32 m_counter : CounterBits; diff --git a/src/core/resources/qhandlemanager_p.h b/src/core/resources/qhandlemanager_p.h deleted file mode 100644 index 0c3609bb9..000000000 --- a/src/core/resources/qhandlemanager_p.h +++ /dev/null @@ -1,263 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DCORE_QHANDLEMANAGER_P_H -#define QT3DCORE_QHANDLEMANAGER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <Qt3DCore/qt3dcore_global.h> -#include <QtCore/QtGlobal> -#include <QtCore/QVector> - -#include <Qt3DCore/private/qhandle_p.h> - -QT_BEGIN_NAMESPACE - -namespace Qt3DCore { - -#ifndef QT_NO_DEBUG_STREAM -template <typename T, uint INDEXBITS> -class QHandleManager; - -template <typename T, uint INDEXBITS = 16> -QDebug operator<<(QDebug dbg, const QHandleManager<T, INDEXBITS> &manager); -#endif - -template <typename T, uint INDEXBITS = 16> -class QHandleManager -{ -public: - QHandleManager() - : m_firstFreeEntry(0) - , m_activeEntryCount(0) - , m_entries(1 << INDEXBITS) - { - reset(); - } - - quint32 activeEntries() const { return m_activeEntryCount; } - - void reset(); - QHandle<T, INDEXBITS> acquire(T *d); - void release(const QHandle<T, INDEXBITS> &handle); - void update(const QHandle<T, INDEXBITS> &, T *d); - T *data(const QHandle<T, INDEXBITS> &handle, bool *ok = 0); - const T *constData(const QHandle<T, INDEXBITS> &handle, bool *ok = 0) const; - QVector<T *> entries() const; - -private: - Q_DISABLE_COPY(QHandleManager) - - friend QDebug operator<< <>(QDebug dbg, const QHandleManager<T, INDEXBITS> &manager); - - template <typename U> - struct HandleEntry - { - HandleEntry() - : m_data(nullptr) - , m_nextFreeIndex(0) - , m_counter(0) - , m_active(false) - , m_endOfFreeList(false) - {} - - explicit HandleEntry(quint32 nextFreeIndex) - : m_data(nullptr) - , m_nextFreeIndex(nextFreeIndex) - , m_counter(0) - , m_active(false) - , m_endOfFreeList(false) - {} - - U *m_data; - unsigned int m_nextFreeIndex : QHandle<U, INDEXBITS>::IndexBits; - unsigned int m_counter : QHandle<U, INDEXBITS>::CounterBits; - unsigned int m_active : 1; - unsigned int m_endOfFreeList : 1; - }; - - quint32 m_firstFreeEntry; - int m_activeEntryCount; - QVector<HandleEntry<T> > m_entries; -}; - -template <typename T, uint INDEXBITS> -void QHandleManager<T, INDEXBITS>::reset() -{ - m_activeEntryCount = 0; - m_firstFreeEntry = 0; - - for (int i = 0; i < QHandle<T, INDEXBITS >::MaxIndex; ++i) - m_entries[i] = HandleEntry<T>(i + 1); - m_entries[QHandle<T, INDEXBITS>::MaxIndex] = HandleEntry<T>(); - m_entries[QHandle<T, INDEXBITS>::MaxIndex].m_endOfFreeList = true; -} - -template <typename T, uint INDEXBITS> -QHandle<T, INDEXBITS> QHandleManager<T, INDEXBITS>::acquire(T *d) -{ - typedef QHandle<T, INDEXBITS> qHandle; - Q_ASSERT(m_activeEntryCount < qHandle::MaxIndex); - - const quint32 newIndex = m_firstFreeEntry; - Q_ASSERT(newIndex < qHandle::MaxIndex); - Q_ASSERT(m_entries[newIndex].m_active == false); - Q_ASSERT(!m_entries[newIndex].m_endOfFreeList); - - m_firstFreeEntry = m_entries[newIndex].m_nextFreeIndex; - m_entries[newIndex].m_nextFreeIndex = 0; - ++m_entries[newIndex].m_counter; - // Check if the counter is about to overflow and reset if necessary - if (m_entries[newIndex].m_counter == qHandle::MaxCounter) - m_entries[newIndex].m_counter = 0; - if (m_entries[newIndex].m_counter == 0) - m_entries[newIndex].m_counter = 1; - m_entries[newIndex].m_active = true; - m_entries[newIndex].m_data = d; - - ++m_activeEntryCount; - - return qHandle(newIndex, m_entries[newIndex].m_counter); -} - -template <typename T, uint INDEXBITS> -void QHandleManager<T, INDEXBITS>::release(const QHandle<T, INDEXBITS> &handle) -{ - const quint32 index = handle.index(); - Q_ASSERT(m_entries[index].m_counter == handle.counter()); - Q_ASSERT(m_entries[index].m_active == true); - - m_entries[index].m_nextFreeIndex = m_firstFreeEntry; - m_entries[index].m_active = false; - m_firstFreeEntry = index; - - --m_activeEntryCount; -} - -// Needed in case the QResourceManager has reordered -// memory so that the handle still points to valid data -template <typename T, uint INDEXBITS> -void QHandleManager<T, INDEXBITS>::update(const QHandle<T, INDEXBITS> &handle, T *d) -{ - const quint32 index = handle.index(); - Q_ASSERT(m_entries[index].m_counter == handle.counter()); - Q_ASSERT(m_entries[index].m_active == true); - m_entries[index].m_data = d; -} - -template <typename T, uint INDEXBITS> -T *QHandleManager<T, INDEXBITS>::data(const QHandle<T, INDEXBITS> &handle, bool *ok) -{ - const quint32 index = handle.index(); - if (m_entries[index].m_counter != handle.counter() || - m_entries[index].m_active == false) { - if (ok) - *ok = false; - return nullptr; - } - - T *d = m_entries[index].m_data; - if (ok) - *ok = true; - return d; -} - -template <typename T, uint INDEXBITS> -const T *QHandleManager<T, INDEXBITS>::constData(const QHandle<T, INDEXBITS> &handle, bool *ok) const -{ - const quint32 index = handle.index(); - if (m_entries[index].m_counter != handle.counter() || - m_entries[index].m_active == false) { - if (ok) - *ok = false; - return nullptr; - } - - const T *d = m_entries[index].m_data; - if (ok) - *ok = true; - return d; -} - -#ifndef QT_NO_DEBUG_STREAM -template <typename T, uint INDEXBITS> -QDebug operator<<(QDebug dbg, const QHandleManager<T, INDEXBITS> &manager) -{ - QDebugStateSaver saver(dbg); - dbg << "First free entry =" << manager.m_firstFreeEntry << endl; - - const auto end = manager.m_entries.cend(); - const auto max = manager.m_activeEntryCount; - auto i = 0; - for (auto it = manager.m_entries.cbegin(); it != end && i < max; ++it) { - const auto isActive = it->m_active; - if (isActive) { - dbg << *(it->m_data); - ++i; - } - } - - return dbg; -} -#endif - -template <typename T, uint INDEXBITS> -QVector<T *> QHandleManager<T, INDEXBITS>::entries() const -{ - QVector<T *> entries; - for (auto handle : qAsConst(m_entries)) - entries.append(handle.m_data); - return entries; -} - -} // Qt3D - -QT_END_NAMESPACE - -#endif // QT3DCORE_QHANDLEMANAGER_H diff --git a/src/core/resources/qresourcemanager_p.h b/src/core/resources/qresourcemanager_p.h index 8ddc1c0a4..4cb2a38af 100644 --- a/src/core/resources/qresourcemanager_p.h +++ b/src/core/resources/qresourcemanager_p.h @@ -57,9 +57,9 @@ #include <QtCore/QReadLocker> #include <QtCore/QReadWriteLock> #include <QtCore/QtGlobal> +#include <limits> #include <Qt3DCore/private/qhandle_p.h> -#include <Qt3DCore/private/qhandlemanager_p.h> // Silence complaints about unreferenced local variables in // ArrayAllocatingPolicy::deallocateBuckets() when the compiler @@ -220,15 +220,16 @@ struct Int2Type }; }; -template <typename T, uint INDEXBITS> +template <typename T, uint INDEXBITS = 16> class ArrayAllocatingPolicy { public: + typedef QHandle<T, INDEXBITS> Handle; ArrayAllocatingPolicy() - : m_numBuckets(0) - , m_numConstructed(0) { - reset(); + m_freeList.resize(MaxSize); + for (int i = 0; i < MaxSize; i++) + m_freeList[i] = MaxSize - (i + 1); } ~ArrayAllocatingPolicy() @@ -236,7 +237,7 @@ public: deallocateBuckets(); } - T* allocateResource() + Handle allocateResource() { Q_ASSERT(!m_freeList.isEmpty()); int idx = m_freeList.takeLast(); @@ -245,9 +246,11 @@ public: Q_ASSERT(bucketIdx <= m_numBuckets); if (bucketIdx == m_numBuckets) { m_bucketDataPtrs[bucketIdx] = static_cast<T*>(malloc(sizeof(T) * BucketSize)); + m_counters[bucketIdx] = static_cast<short *>(malloc(sizeof(short) * BucketSize)); // ### memset is only needed as long as we also use this for primitive types (see FrameGraphManager) // ### remove once this is fixed, add a static_assert on T instead - memset((void*) m_bucketDataPtrs[bucketIdx], 0, sizeof(T) * BucketSize); + memset((void *)m_bucketDataPtrs[bucketIdx], 0, sizeof(T) * BucketSize); + memset(m_counters[bucketIdx], 0, sizeof(short) * BucketSize); ++m_numBuckets; } @@ -256,39 +259,47 @@ public: new (m_bucketDataPtrs[bucketIdx] + localIdx) T; ++m_numConstructed; } - - return m_bucketDataPtrs[bucketIdx] + localIdx; + Q_STATIC_ASSERT(Handle::MaxCounter < USHRT_MAX); + Q_ASSERT(m_counters[bucketIdx][localIdx] <= 0); + m_counters[bucketIdx][localIdx] *= -1; + ++m_counters[bucketIdx][localIdx]; + if (m_counters[bucketIdx][localIdx] >= Handle::MaxCounter) + m_counters[bucketIdx][localIdx] = 1; + + return Handle(idx, m_counters[bucketIdx][localIdx]); } - void releaseResource(T *r) + void releaseResource(Handle h) { - // search linearly over buckets to find the index of the resource - // and put it into the free list - for (int bucketIdx = 0; bucketIdx < m_numBuckets; ++bucketIdx) { - const T* firstItem = m_bucketDataPtrs[bucketIdx]; - if (firstItem > r || r >= firstItem + BucketSize) { - // resource is not in this bucket when its pointer address - // is outside the address range spanned by the addresses of - // the first and last items in a bucket - continue; - } + int idx = h.index(); + int bucketIdx = idx / BucketSize; + int localIdx = idx % BucketSize; - // now we found the bucket we can reconstruct the global index - // and put it back into the free list - const int localIdx = static_cast<int>(r - firstItem); - const int idx = bucketIdx * BucketSize + localIdx; - m_freeList.append(idx); - performCleanup(r, Int2Type<QResourceInfo<T>::needsCleanup>()); - break; + Q_ASSERT(h.counter() == static_cast<quint32>(m_counters[bucketIdx][localIdx])); + T *r = m_bucketDataPtrs[bucketIdx] + localIdx; + + m_freeList.append(idx); + m_counters[bucketIdx][localIdx] *= -1; + performCleanup(r, Int2Type<QResourceInfo<T>::needsCleanup>()); + } + + T *data(Handle h/*, bool *ok = 0*/) { + int bucketIdx = h.index() / BucketSize; + int localIdx = h.index() % BucketSize; + + if (h.counter() != static_cast<quint32>(m_counters[bucketIdx][localIdx])) { + return nullptr; } + return m_bucketDataPtrs[bucketIdx] + localIdx; } - void reset() - { - deallocateBuckets(); - m_freeList.resize(MaxSize); - for (int i = 0; i < MaxSize; i++) - m_freeList[i] = MaxSize - (i + 1); + void for_each(std::function<void(T*)> f) { + for (int idx = 0; idx < m_numConstructed; ++idx) { + int bucketIdx = idx / BucketSize; + int localIdx = idx % BucketSize; + T * t = m_bucketDataPtrs[bucketIdx] + localIdx; + f(t); + } } private: @@ -313,66 +324,15 @@ private: while (m_numBuckets > 0) { --m_numBuckets; free(m_bucketDataPtrs[m_numBuckets]); + free(m_counters[m_numBuckets]); } } T* m_bucketDataPtrs[MaxSize / BucketSize]; + short *m_counters[MaxSize / BucketSize]; QVector<int> m_freeList; - int m_numBuckets; - int m_numConstructed; - - void performCleanup(T *r, Int2Type<true>) - { - r->cleanup(); - } - - void performCleanup(T *, Int2Type<false>) - {} - -}; - -template <typename T, uint INDEXBITS> -class ArrayPreallocationPolicy -{ -public: - ArrayPreallocationPolicy() - { - reset(); - } - - T* allocateResource() - { - Q_ASSERT(!m_freeList.isEmpty()); - int idx = m_freeList.last(); - m_freeList.pop_back(); - return m_bucket.data() + idx; - } - - void releaseResource(T *r) - { - Q_ASSERT(m_bucket.data() <= r && r < m_bucket.data() + MaxSize); - int idx = r - m_bucket.data(); - m_freeList.append(idx); - performCleanup(r, Int2Type<QResourceInfo<T>::needsCleanup>()); - *r = T(); - } - - void reset() - { - m_bucket.clear(); - m_bucket.resize(MaxSize); - m_freeList.resize(MaxSize); - for (int i = 0; i < MaxSize; i++) - m_freeList[i] = MaxSize - (i + 1); - } - -private: - enum { - MaxSize = 1 << INDEXBITS - }; - - QVector<T> m_bucket; - QVector<int> m_freeList; + int m_numBuckets = 0; + int m_numConstructed = 0; void performCleanup(T *r, Int2Type<true>) { @@ -386,29 +346,29 @@ private: #ifndef QT_NO_DEBUG_STREAM template <typename ValueType, typename KeyType, uint INDEXBITS, - template <typename, uint> class AllocatingPolicy, template <class> class LockingPolicy > class QResourceManager; template <typename ValueType, typename KeyType, uint INDEXBITS = 16, - template <typename, uint> class AllocatingPolicy = ArrayAllocatingPolicy, template <class> class LockingPolicy = NonLockingPolicy > -QDebug operator<<(QDebug dbg, const QResourceManager<ValueType, KeyType, INDEXBITS, AllocatingPolicy, LockingPolicy> &manager); +QDebug operator<<(QDebug dbg, const QResourceManager<ValueType, KeyType, INDEXBITS, LockingPolicy> &manager); #endif template <typename ValueType, typename KeyType, uint INDEXBITS = 16, - template <typename, uint> class AllocatingPolicy = ArrayAllocatingPolicy, template <class> class LockingPolicy = NonLockingPolicy > class QResourceManager - : public AllocatingPolicy<ValueType, INDEXBITS> - , public LockingPolicy< QResourceManager<ValueType, KeyType, INDEXBITS, AllocatingPolicy, LockingPolicy> > + : public ArrayAllocatingPolicy<ValueType, INDEXBITS> + , public LockingPolicy< QResourceManager<ValueType, KeyType, INDEXBITS, LockingPolicy> > { public: + typedef ArrayAllocatingPolicy<ValueType, INDEXBITS> Allocator; + typedef QHandle<ValueType, INDEXBITS> Handle; + QResourceManager() : - AllocatingPolicy<ValueType, INDEXBITS>(), + Allocator(), m_maxSize((1 << INDEXBITS) - 1) { } @@ -416,52 +376,43 @@ public: ~QResourceManager() {} - QHandle<ValueType, INDEXBITS> acquire() + Handle acquire() { typename LockingPolicy<QResourceManager>::WriteLocker lock(this); - QHandle<ValueType, INDEXBITS> handle = m_handleManager.acquire(AllocatingPolicy<ValueType, INDEXBITS>::allocateResource()); + Handle handle = Allocator::allocateResource(); m_activeHandles.push_back(handle); return handle; } - ValueType* data(const QHandle<ValueType, INDEXBITS> &handle) + ValueType* data(const Handle &handle) { typename LockingPolicy<QResourceManager>::ReadLocker lock(this); - ValueType* d = m_handleManager.data(handle); - return d; + return Allocator::data(handle); } - void release(const QHandle<ValueType, INDEXBITS> &handle) + void release(const Handle &handle) { typename LockingPolicy<QResourceManager>::WriteLocker lock(this); releaseLocked(handle); } - void reset() - { - typename LockingPolicy<QResourceManager>::WriteLocker lock(this); - m_handleManager.reset(); - m_activeHandles.clear(); - AllocatingPolicy<ValueType, INDEXBITS>::reset(); - } - bool contains(const KeyType &id) const { typename LockingPolicy<QResourceManager>::ReadLocker lock(this); return m_keyToHandleMap.contains(id); } - QHandle<ValueType, INDEXBITS> getOrAcquireHandle(const KeyType &id) + Handle getOrAcquireHandle(const KeyType &id) { typename LockingPolicy<QResourceManager>::ReadLocker lock(this); - QHandle<ValueType, INDEXBITS> handle = m_keyToHandleMap.value(id); + Handle handle = m_keyToHandleMap.value(id); if (handle.isNull()) { lock.unlock(); typename LockingPolicy<QResourceManager>::WriteLocker writeLock(this); // Test that the handle hasn't been set (in the meantime between the read unlock and the write lock) - QHandle<ValueType, INDEXBITS> &handleToSet = m_keyToHandleMap[id]; + Handle &handleToSet = m_keyToHandleMap[id]; if (handleToSet.isNull()) { - handleToSet = m_handleManager.acquire(AllocatingPolicy<ValueType, INDEXBITS>::allocateResource()); + handleToSet = Allocator::allocateResource(); m_activeHandles.push_back(handleToSet); } return handleToSet; @@ -469,7 +420,7 @@ public: return handle; } - QHandle<ValueType, INDEXBITS> lookupHandle(const KeyType &id) + Handle lookupHandle(const KeyType &id) { typename LockingPolicy<QResourceManager>::ReadLocker lock(this); return m_keyToHandleMap.value(id); @@ -480,58 +431,54 @@ public: ValueType* ret = nullptr; { typename LockingPolicy<QResourceManager>::ReadLocker lock(this); - QHandle<ValueType, INDEXBITS> handle = m_keyToHandleMap.value(id); + Handle handle = m_keyToHandleMap.value(id); if (!handle.isNull()) - ret = m_handleManager.data(handle); + ret = Allocator::data(handle); } return ret; } ValueType *getOrCreateResource(const KeyType &id) { - const QHandle<ValueType, INDEXBITS> handle = getOrAcquireHandle(id); + const Handle handle = getOrAcquireHandle(id); typename LockingPolicy<QResourceManager>::ReadLocker lock(this); - return m_handleManager.data(handle); + return Allocator::data(handle); } void releaseResource(const KeyType &id) { typename LockingPolicy<QResourceManager>::WriteLocker lock(this); - QHandle<ValueType, INDEXBITS> handle = m_keyToHandleMap.take(id); + Handle handle = m_keyToHandleMap.take(id); if (!handle.isNull()) releaseLocked(handle); } int maximumSize() const { return m_maxSize; } - int count() const Q_DECL_NOEXCEPT { return m_handleManager.activeEntries(); } + int count() const Q_DECL_NOEXCEPT { return m_activeHandles.size(); } - inline QVector<QHandle<ValueType, INDEXBITS> > activeHandles() const Q_DECL_NOEXCEPT { return m_activeHandles; } + inline QVector<Handle > activeHandles() const Q_DECL_NOEXCEPT { return m_activeHandles; } protected: - QHandleManager<ValueType, INDEXBITS> m_handleManager; - QHash<KeyType, QHandle<ValueType, INDEXBITS> > m_keyToHandleMap; - QVector<QHandle<ValueType, INDEXBITS> > m_activeHandles; + QHash<KeyType, Handle > m_keyToHandleMap; + QVector<Handle > m_activeHandles; const int m_maxSize; private: - void releaseLocked(const QHandle<ValueType, INDEXBITS> &handle) + void releaseLocked(const Handle &handle) { - ValueType *val = m_handleManager.data(handle); - m_handleManager.release(handle); m_activeHandles.removeOne(handle); - AllocatingPolicy<ValueType, INDEXBITS>::releaseResource(val); + Allocator::releaseResource(handle); } - friend QDebug operator<< <>(QDebug dbg, const QResourceManager<ValueType, KeyType, INDEXBITS, AllocatingPolicy, LockingPolicy> &manager); + friend QDebug operator<< <>(QDebug dbg, const QResourceManager<ValueType, KeyType, INDEXBITS, LockingPolicy> &manager); }; #ifndef QT_NO_DEBUG_STREAM template <typename ValueType, typename KeyType, uint INDEXBITS, - template <typename, uint> class AllocatingPolicy, template <class> class LockingPolicy > -QDebug operator<<(QDebug dbg, const QResourceManager<ValueType, KeyType, INDEXBITS, AllocatingPolicy, LockingPolicy> &manager) +QDebug operator<<(QDebug dbg, const QResourceManager<ValueType, KeyType, INDEXBITS, LockingPolicy> &manager) { QDebugStateSaver saver(dbg); dbg << "Contains" << manager.count() << "items" << "of a maximum" << manager.maximumSize() << endl; @@ -541,8 +488,8 @@ QDebug operator<<(QDebug dbg, const QResourceManager<ValueType, KeyType, INDEXBI for (auto it = manager.m_keyToHandleMap.cbegin(); it != end; ++it) dbg << "QNodeId =" << it.key() << "Handle =" << it.value() << endl; - dbg << "Resources:" << endl; - dbg << manager.m_handleManager; +// dbg << "Resources:" << endl; +// dbg << manager.m_handleManager; return dbg; } #endif diff --git a/src/core/resources/resources.pri b/src/core/resources/resources.pri index 855d73b79..96ea21e93 100644 --- a/src/core/resources/resources.pri +++ b/src/core/resources/resources.pri @@ -1,5 +1,4 @@ HEADERS += \ - $$PWD/qhandlemanager_p.h \ $$PWD/qresourcemanager_p.h \ $$PWD/qcircularbuffer_p.h \ $$PWD/qboundedcircularbuffer_p.h \ |