summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/resources/qhandle_p.h89
-rw-r--r--src/core/resources/qresourcemanager_p.h177
-rw-r--r--src/render/backend/renderview.cpp2
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;