diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/resources/qhandle_p.h | 89 | ||||
-rw-r--r-- | src/core/resources/qresourcemanager_p.h | 177 | ||||
-rw-r--r-- | src/render/backend/renderview.cpp | 2 |
3 files changed, 124 insertions, 144 deletions
diff --git a/src/core/resources/qhandle_p.h b/src/core/resources/qhandle_p.h index c4b53ec21..95483d197 100644 --- a/src/core/resources/qhandle_p.h +++ b/src/core/resources/qhandle_p.h @@ -53,9 +53,7 @@ #include <Qt3DCore/qt3dcore_global.h> #include <QtCore/QDebug> -#include <limits.h> - -class tst_Handle; // needed for friend class declaration below +#include <QtCore/qhashfunctions.h> QT_BEGIN_NAMESPACE @@ -65,69 +63,72 @@ template <typename T, uint INDEXBITS = 16> class QHandle { public: + struct Data { + union { + quintptr counter; + Data *nextFree; + }; + }; QHandle() - : m_handle(0) + : d(nullptr), + counter(0) {} - - - quint32 index() const { return d.m_index; } - quint32 counter() const { return d.m_counter; } - quint32 handle() const { return m_handle; } - bool isNull() const { return !m_handle; } - - operator quint32() const { return m_handle; } - - static quint32 maxIndex() { return MaxIndex; } - static quint32 maxCounter() { return MaxCounter; } - - QHandle(quint32 i, quint32 count) + QHandle(Data *d) + : d(d), + counter(d->counter) + { + } + QHandle(const QHandle &other) + : d(other.d), + counter(other.counter) + { + } + QHandle &operator=(const QHandle &other) { - d.m_index = i; - d.m_counter = count; - d.m_unused = 0; - Q_ASSERT(i < MaxIndex); - Q_ASSERT(count < MaxCounter); + d = other.d; + counter = other.counter; + return *this; } - enum { - // Sizes to use for bit fields - IndexBits = INDEXBITS, - CounterBits = 32 - INDEXBITS - 2, // We use 2 bits for book-keeping in QHandleManager + inline T *operator->() const; + T *data() const; - // Sizes to compare against for asserting dereferences - MaxIndex = (1 << IndexBits) - 1, - MaxCounter = ((1 << CounterBits) - 1 > SHRT_MAX) ? SHRT_MAX - 1 : (1 << CounterBits) - 1 - }; + quintptr handle() const { return reinterpret_cast<quintptr>(d); } + bool isNull() const { return !d; } + + Data *data_ptr() const { return d; } + bool operator==(const QHandle &other) const { return d == other.d && counter == other.counter; } + bool operator!=(const QHandle &other) const { return !operator==(other); } private: - struct Data { - quint32 m_index : IndexBits; - quint32 m_counter : CounterBits; - quint32 m_unused : 2; - }; - union { - Data d; - quint32 m_handle; - }; + Data *d; + quintptr counter; }; + template <typename T, uint INDEXBITS> QDebug operator<<(QDebug dbg, const QHandle<T, INDEXBITS> &h) { QDebugStateSaver saver(dbg); QString binNumber = QString::number(h.handle(), 2).rightJustified(32, QChar::fromLatin1('0')); - dbg.nospace() << "index = " << h.index() - << " magic/counter = " << h.counter() - << " m_handle = " << h.handle() + dbg.nospace() << " m_handle = " << h.handle() << " = " << binNumber; return dbg; } +template <typename T, uint INDEXBITS = 16> +uint qHash(const QHandle<T, INDEXBITS> &h, uint seed) +{ + using QT_PREPEND_NAMESPACE(qHash); + return qHash(h.handle(), seed); +} + } // Qt3DCore +// simpler than fighting the Q_DECLARE_TYPEINFO macro, use QString as a dummy to get movable semantics template <typename T, uint I> -class QTypeInfo<Qt3DCore::QHandle<T,I> > // simpler than fighting the Q_DECLARE_TYPEINFO macro - : public QTypeInfoMerger<Qt3DCore::QHandle<T,I>, quint32> {}; +class QTypeInfo<Qt3DCore::QHandle<T,I> > + : public QTypeInfoMerger<Qt3DCore::QHandle<T,I>, QString> {}; QT_END_NAMESPACE diff --git a/src/core/resources/qresourcemanager_p.h b/src/core/resources/qresourcemanager_p.h index 4cb2a38af..8f0440498 100644 --- a/src/core/resources/qresourcemanager_p.h +++ b/src/core/resources/qresourcemanager_p.h @@ -220,119 +220,114 @@ struct Int2Type }; }; +template<typename T, uint INDEXBITS = 16> +class QHandleData : public QHandle<T, INDEXBITS>::Data +{ +public: + T data; +}; + +template<typename T, uint INDEXBITS> +inline T *QHandle<T, INDEXBITS>::operator->() const { return (d && counter == d->counter) ? &static_cast<QHandleData<T, INDEXBITS> *>(d)->data : nullptr; } +template<typename T, uint INDEXBITS> +inline T *QHandle<T, INDEXBITS>::data() const { return (d && counter == d->counter) ? &static_cast<QHandleData<T, INDEXBITS> *>(d)->data : nullptr; } + template <typename T, uint INDEXBITS = 16> class ArrayAllocatingPolicy { public: + typedef QHandleData<T, INDEXBITS> HandleData; typedef QHandle<T, INDEXBITS> Handle; ArrayAllocatingPolicy() { - m_freeList.resize(MaxSize); - for (int i = 0; i < MaxSize; i++) - m_freeList[i] = MaxSize - (i + 1); } ~ArrayAllocatingPolicy() { + m_activeHandles.clear(); deallocateBuckets(); } Handle allocateResource() { - Q_ASSERT(!m_freeList.isEmpty()); - int idx = m_freeList.takeLast(); - int bucketIdx = idx / BucketSize; - int localIdx = idx % BucketSize; - 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(m_counters[bucketIdx], 0, sizeof(short) * BucketSize); - ++m_numBuckets; - } - - Q_ASSERT(idx <= m_numConstructed); - if (idx == m_numConstructed) { - new (m_bucketDataPtrs[bucketIdx] + localIdx) T; - ++m_numConstructed; - } - 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]); + if (!freeList) + allocateBucket(); + typename Handle::Data *d = freeList; + freeList = freeList->nextFree; + d->counter = allocCounter; + allocCounter += 2; // ensure this will never clash with a pointer in nextFree by keeping the lowest bit set + Handle handle(d); + m_activeHandles.push_back(handle); + return handle; } - void releaseResource(Handle h) + void releaseResource(const Handle &handle) { - int idx = h.index(); - int bucketIdx = idx / BucketSize; - int localIdx = idx % BucketSize; - - 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>()); + m_activeHandles.removeOne(handle); + typename Handle::Data *d = handle.data_ptr(); + d->nextFree = freeList; + freeList = d; + performCleanup(&static_cast<QHandleData<T, INDEXBITS> *>(d)->data, 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; + T *data(Handle h) { + return h.operator->(); } 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); + Bucket *b = firstBucket; + while (b) { + for (int idx = 0; idx < Bucket::NumEntries; ++idx) { + T *t = &b->data[idx].data; + f(t); + } + b = b->header.next; } } + int count() const { return m_activeHandles.size(); } + QVector<Handle> activeHandles() const { return m_activeHandles; } + private: Q_DISABLE_COPY(ArrayAllocatingPolicy) - - enum { - MaxSize = (1 << INDEXBITS), - // use at most 1024 items per bucket, or put all items into a single - // bucket if MaxSize is small enough - BucketSize = (1 << (INDEXBITS < 10 ? INDEXBITS : 10)) + struct Bucket { + struct Header { + Bucket *next; + } header; + enum { + Size = 4096, + NumEntries = (Size - sizeof(Header))/sizeof(HandleData) + }; + HandleData data[NumEntries]; }; - void deallocateBuckets() - { - while (m_numConstructed > 0) { - --m_numConstructed; - int bucketIdx = m_numConstructed / BucketSize; - int localIdx = m_numConstructed % BucketSize; - (m_bucketDataPtrs[bucketIdx] + localIdx)->~T(); - } + Bucket *firstBucket = 0; + QVector<Handle > m_activeHandles; + typename Handle::Data *freeList = 0; + int allocCounter = 1; + + void allocateBucket() { + // no free handle, allocate a new + Bucket *b = new Bucket; - while (m_numBuckets > 0) { - --m_numBuckets; - free(m_bucketDataPtrs[m_numBuckets]); - free(m_counters[m_numBuckets]); + b->header.next = firstBucket; + firstBucket = b; + for (int i = 0; i < Bucket::NumEntries - 1; ++i) { + b->data[i].nextFree = &b->data[i + 1]; } + b->data[Bucket::NumEntries - 1].nextFree = nullptr; + freeList = &b->data[0]; } - T* m_bucketDataPtrs[MaxSize / BucketSize]; - short *m_counters[MaxSize / BucketSize]; - QVector<int> m_freeList; - int m_numBuckets = 0; - int m_numConstructed = 0; + void deallocateBuckets() + { + Bucket *b = firstBucket; + while (b) { + Bucket *n = b->header.next; + delete b; + b = n; + } + } void performCleanup(T *r, Int2Type<true>) { @@ -379,21 +374,18 @@ public: Handle acquire() { typename LockingPolicy<QResourceManager>::WriteLocker lock(this); - Handle handle = Allocator::allocateResource(); - m_activeHandles.push_back(handle); - return handle; + return Allocator::allocateResource(); } ValueType* data(const Handle &handle) { - typename LockingPolicy<QResourceManager>::ReadLocker lock(this); - return Allocator::data(handle); + return handle.operator->(); } void release(const Handle &handle) { typename LockingPolicy<QResourceManager>::WriteLocker lock(this); - releaseLocked(handle); + Allocator::releaseResource(handle); } bool contains(const KeyType &id) const @@ -413,7 +405,6 @@ public: Handle &handleToSet = m_keyToHandleMap[id]; if (handleToSet.isNull()) { handleToSet = Allocator::allocateResource(); - m_activeHandles.push_back(handleToSet); } return handleToSet; } @@ -441,8 +432,7 @@ public: ValueType *getOrCreateResource(const KeyType &id) { const Handle handle = getOrAcquireHandle(id); - typename LockingPolicy<QResourceManager>::ReadLocker lock(this); - return Allocator::data(handle); + return handle.operator->(); } void releaseResource(const KeyType &id) @@ -450,27 +440,16 @@ public: typename LockingPolicy<QResourceManager>::WriteLocker lock(this); Handle handle = m_keyToHandleMap.take(id); if (!handle.isNull()) - releaseLocked(handle); + Allocator::releaseResource(handle); } int maximumSize() const { return m_maxSize; } - int count() const Q_DECL_NOEXCEPT { return m_activeHandles.size(); } - - inline QVector<Handle > activeHandles() const Q_DECL_NOEXCEPT { return m_activeHandles; } - protected: QHash<KeyType, Handle > m_keyToHandleMap; - QVector<Handle > m_activeHandles; const int m_maxSize; private: - void releaseLocked(const Handle &handle) - { - m_activeHandles.removeOne(handle); - Allocator::releaseResource(handle); - } - friend QDebug operator<< <>(QDebug dbg, const QResourceManager<ValueType, KeyType, INDEXBITS, LockingPolicy> &manager); }; diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp index 8c9737689..7adf7c5d2 100644 --- a/src/render/backend/renderview.cpp +++ b/src/render/backend/renderview.cpp @@ -379,7 +379,7 @@ void sortByMaterial(QVector<RenderCommand *> &commands, int begin, const int end while (begin != end) { if (begin + 1 < rangeEnd) { std::stable_sort(commands.begin() + begin + 1, commands.begin() + rangeEnd, [] (RenderCommand *a, RenderCommand *b){ - return a->m_material < b->m_material; + return a->m_material.handle() < b->m_material.handle(); }); } begin = rangeEnd; |