summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2017-11-15 19:05:35 +0000
committerThe Qt Project <gerrit-noreply@qt-project.org>2017-11-15 19:05:35 +0000
commit728e5b1d80917c1ac1efaff62d0fbbf3b203550c (patch)
treef171db8c1b15244ecab08fe071a8e29f2f067e2c
parentdc82714a8f782bcd7fe2131ca15774ef4fb3c0dc (diff)
parentcda9cecde58ce6734c58fb5e545d62c3e7e12a3d (diff)
Merge "Merge remote-tracking branch 'origin/5.9' into 5.10" into refs/staging/5.10
-rw-r--r--src/core/resources/qhandle_p.h89
-rw-r--r--src/core/resources/qresourcemanager_p.h177
-rw-r--r--src/plugins/geometryloaders/default/objgeometryloader.cpp4
-rw-r--r--src/render/backend/abstractrenderer_p.h1
-rw-r--r--src/render/backend/layer.cpp4
-rw-r--r--src/render/backend/layer_p.h2
-rw-r--r--src/render/backend/render-backend.pri3
-rw-r--r--src/render/backend/renderer.cpp8
-rw-r--r--src/render/backend/renderer_p.h4
-rw-r--r--src/render/backend/renderercache_p.h83
-rw-r--r--src/render/backend/renderview.cpp2
-rw-r--r--src/render/backend/renderviewbuilder.cpp26
-rw-r--r--src/render/framegraph/layerfilternode.cpp3
-rw-r--r--tests/auto/core/handle/tst_handle.cpp96
-rw-r--r--tests/auto/core/qresourcemanager/tst_qresourcemanager.cpp25
-rw-r--r--tests/auto/render/geometryloaders/cube2.obj26
-rw-r--r--tests/auto/render/geometryloaders/geometryloaders.qrc1
-rw-r--r--tests/auto/render/geometryloaders/tst_geometryloaders.cpp10
-rw-r--r--tests/auto/render/renderer/tst_renderer.cpp2
-rw-r--r--tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp4
-rw-r--r--tests/benchmarks/core/qresourcesmanager/qresourcesmanager/tst_bench_qresourcesmanager.cpp7
21 files changed, 331 insertions, 246 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/plugins/geometryloaders/default/objgeometryloader.cpp b/src/plugins/geometryloaders/default/objgeometryloader.cpp
index 7184e2f69..6ebe91a09 100644
--- a/src/plugins/geometryloaders/default/objgeometryloader.cpp
+++ b/src/plugins/geometryloaders/default/objgeometryloader.cpp
@@ -102,6 +102,10 @@ bool ObjGeometryLoader::doLoad(QIODevice *ioDev, const QString &subMesh)
if (lineSize > 0 && line[0] != '#') {
if (line[lineSize - 1] == '\n')
--lineSize; // chop newline
+ if (line[lineSize - 1] == '\r')
+ --lineSize; // chop newline also for CRLF format
+ while (line[lineSize - 1] == ' ' || line[lineSize - 1] == '\t')
+ --lineSize; // chop trailing spaces
const ByteArraySplitter tokens(line, line + lineSize, ' ', QString::SkipEmptyParts);
diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h
index c1c1f7032..4d80ec87d 100644
--- a/src/render/backend/abstractrenderer_p.h
+++ b/src/render/backend/abstractrenderer_p.h
@@ -107,6 +107,7 @@ public:
ShadersDirty = 1 << 9,
SkeletonDataDirty = 1 << 10,
JointDirty = 1 << 11,
+ LayersDirty = 1 << 12,
AllDirty = 0xffffff
};
Q_DECLARE_FLAGS(BackendNodeDirtySet, BackendNodeDirtyFlag)
diff --git a/src/render/backend/layer.cpp b/src/render/backend/layer.cpp
index 6f50d071d..976c35fd5 100644
--- a/src/render/backend/layer.cpp
+++ b/src/render/backend/layer.cpp
@@ -74,8 +74,10 @@ void Layer::sceneChangeEvent(const QSceneChangePtr &e)
QByteArray propertyName = propertyChange->propertyName();
if (propertyName == QByteArrayLiteral("recursive")) {
m_recursive = propertyChange->value().toBool();
+ markDirty(AbstractRenderer::LayersDirty);
}
- markDirty(AbstractRenderer::AllDirty);
+ if (propertyName == QByteArrayLiteral("enabled"))
+ markDirty(AbstractRenderer::LayersDirty);
}
BackendNode::sceneChangeEvent(e);
}
diff --git a/src/render/backend/layer_p.h b/src/render/backend/layer_p.h
index 2ba3532d2..d01d190e9 100644
--- a/src/render/backend/layer_p.h
+++ b/src/render/backend/layer_p.h
@@ -77,7 +77,7 @@ public:
void setRecursive(bool recursive);
protected:
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e);
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change);
diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri
index 1d18c8efe..f7f30b5c9 100644
--- a/src/render/backend/render-backend.pri
+++ b/src/render/backend/render-backend.pri
@@ -44,7 +44,8 @@ HEADERS += \
$$PWD/commandthread_p.h \
$$PWD/visitorutils_p.h \
$$PWD/segmentsvisitor_p.h \
- $$PWD/pointsvisitor_p.h
+ $$PWD/pointsvisitor_p.h \
+ $$PWD/renderercache_p.h
SOURCES += \
$$PWD/renderthread.cpp \
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp
index eb64677c1..8056e8bef 100644
--- a/src/render/backend/renderer.cpp
+++ b/src/render/backend/renderer.cpp
@@ -1539,6 +1539,14 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
FrameGraphVisitor visitor(m_nodesManager->frameGraphManager());
const QVector<FrameGraphNode *> fgLeaves = visitor.traverse(frameGraphRoot());
+ // Remove leaf nodes that no longer exist from cache
+ const auto keys = m_cache.leafNodeCache.keys();
+ for (auto *leafNode : keys) {
+ if (!fgLeaves.contains(leafNode)) {
+ m_cache.leafNodeCache.remove(leafNode);
+ }
+ }
+
const int fgBranchCount = fgLeaves.size();
for (int i = 0; i < fgBranchCount; ++i) {
RenderViewBuilder builder(fgLeaves.at(i), i, this);
diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h
index 3cf99ec81..161c3c7ef 100644
--- a/src/render/backend/renderer_p.h
+++ b/src/render/backend/renderer_p.h
@@ -76,6 +76,7 @@
#include <Qt3DRender/private/updatemeshtrianglelistjob_p.h>
#include <Qt3DRender/private/filtercompatibletechniquejob_p.h>
#include <Qt3DRender/private/updateskinningpalettejob_p.h>
+#include <Qt3DRender/private/renderercache_p.h>
#include <QHash>
#include <QMatrix4x4>
@@ -266,6 +267,9 @@ public:
ViewSubmissionResultData submitRenderViews(const QVector<Render::RenderView *> &renderViews);
+ RendererCache m_cache;
+
+
#ifdef QT3D_RENDER_UNIT_TESTS
public:
#else
diff --git a/src/render/backend/renderercache_p.h b/src/render/backend/renderercache_p.h
new file mode 100644
index 000000000..35525492d
--- /dev/null
+++ b/src/render/backend/renderercache_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 QT3DRENDER_RENDER_RENDERERCACHE_P_H
+#define QT3DRENDER_RENDER_RENDERERCACHE_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 <Qt3DRender/QFrameGraphNode>
+
+#include <Qt3DRender/private/entity_p.h>
+#include <Qt3DRender/private/renderviewjobutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+struct RendererCache
+{
+ using FilterEntityByLayerData = QVector<Entity *>;
+
+ struct LeafNodeData
+ {
+ FilterEntityByLayerData filterEntityByLayerData;
+ };
+
+ QHash<FrameGraphNode *, LeafNodeData> leafNodeCache;
+};
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_RENDERERCACHE_P_H
diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp
index 572cda229..dbb6ead21 100644
--- a/src/render/backend/renderview.cpp
+++ b/src/render/backend/renderview.cpp
@@ -394,7 +394,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;
diff --git a/src/render/backend/renderviewbuilder.cpp b/src/render/backend/renderviewbuilder.cpp
index 2237802d8..7d2d7ab03 100644
--- a/src/render/backend/renderviewbuilder.cpp
+++ b/src/render/backend/renderviewbuilder.cpp
@@ -178,7 +178,9 @@ public:
const RenderableEntityFilterPtr &renderableEntityFilterJob,
const ComputableEntityFilterPtr &computableEntityFilterJob,
const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs,
- const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs)
+ const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs,
+ Renderer *renderer,
+ FrameGraphNode *leafNode)
: m_renderViewJob(renderViewJob)
, m_frustumCullingJob(frustumCullingJob)
, m_filterEntityByLayerJob(filterEntityByLayerJob)
@@ -188,6 +190,8 @@ public:
, m_computableEntityFilterJob(computableEntityFilterJob)
, m_materialGathererJobs(materialGathererJobs)
, m_renderViewBuilderJobs(renderViewBuilderJobs)
+ , m_renderer(renderer)
+ , m_leafNode(leafNode)
{}
void operator()()
@@ -211,14 +215,18 @@ public:
// Filter out entities that weren't selected by the layer filters
std::sort(renderableEntities.begin(), renderableEntities.end());
+ auto &filterEntityByLayerCache = m_renderer->m_cache.leafNodeCache[m_leafNode].filterEntityByLayerData;
+
// Remove all entities from the compute and renderable vectors that aren't in the filtered layer vector
- const QVector<Entity *> filteredEntities = m_filterEntityByLayerJob->filteredEntities();
- RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, filteredEntities);
+ if (m_renderer->dirtyBits() & AbstractRenderer::LayersDirty)
+ filterEntityByLayerCache = m_filterEntityByLayerJob->filteredEntities();
+
+ RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, filterEntityByLayerCache);
// Set the light sources, with layer filters applied.
QVector<LightSource> lightSources = m_lightGathererJob->lights();
for (int i = 0; i < lightSources.count(); ++i) {
- if (!filteredEntities.contains(lightSources[i].entity))
+ if (!filterEntityByLayerCache.contains(lightSources[i].entity))
lightSources.removeAt(i--);
}
rv->setLightSources(lightSources);
@@ -261,6 +269,8 @@ private:
ComputableEntityFilterPtr m_computableEntityFilterJob;
QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs;
+ Renderer *m_renderer;
+ FrameGraphNode *m_leafNode;
};
class SetClearDrawBufferIndex
@@ -353,7 +363,9 @@ RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int rende
m_renderableEntityFilterJob,
m_computableEntityFilterJob,
m_materialGathererJobs,
- m_renderViewBuilderJobs),
+ m_renderViewBuilderJobs,
+ m_renderer,
+ leafNode),
JobTypes::SyncRenderViewCommandBuilding);
m_syncRenderViewCommandBuildersJob = SynchronizerJobPtr::create(SyncRenderViewCommandBuilders(m_renderViewJob,
@@ -493,8 +505,10 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
jobs.push_back(m_syncRenderViewInitializationJob); // Step 2
jobs.push_back(m_syncFrustumCullingJob); // Step 3
- jobs.push_back(m_filterEntityByLayerJob); // Step 3
+ if (m_renderer->dirtyBits() & AbstractRenderer::LayersDirty)
+ jobs.push_back(m_filterEntityByLayerJob); // Step 3
jobs.push_back(m_filterProximityJob); // Step 3
+
jobs.push_back(m_setClearDrawBufferIndexJob); // Step 3
for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) // Step3
diff --git a/src/render/framegraph/layerfilternode.cpp b/src/render/framegraph/layerfilternode.cpp
index b8fa5c075..4b6842015 100644
--- a/src/render/framegraph/layerfilternode.cpp
+++ b/src/render/framegraph/layerfilternode.cpp
@@ -73,6 +73,7 @@ void LayerFilterNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
if (change->propertyName() == QByteArrayLiteral("layer"))
m_layerIds.append(change->addedNodeId());
+ markDirty(AbstractRenderer::LayersDirty);
break;
}
@@ -80,6 +81,7 @@ void LayerFilterNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
if (change->propertyName() == QByteArrayLiteral("layer"))
m_layerIds.removeOne(change->removedNodeId());
+ markDirty(AbstractRenderer::LayersDirty);
break;
}
@@ -94,7 +96,6 @@ void LayerFilterNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
default:
break;
}
- markDirty(AbstractRenderer::AllDirty);
FrameGraphNode::sceneChangeEvent(e);
}
diff --git a/tests/auto/core/handle/tst_handle.cpp b/tests/auto/core/handle/tst_handle.cpp
index 07155844f..4d4ccb645 100644
--- a/tests/auto/core/handle/tst_handle.cpp
+++ b/tests/auto/core/handle/tst_handle.cpp
@@ -28,12 +28,7 @@
#include <QtTest/QtTest>
#include <Qt3DCore/private/qhandle_p.h>
-
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
-#define GET_EXPECTED_HANDLE(qHandle) ((qHandle.index() << (qHandle.CounterBits + 2)) + (qHandle.counter() << 2))
-#else /* Q_LITTLE_ENDIAN */
-#define GET_EXPECTED_HANDLE(qHandle) (qHandle.index() + (qHandle.counter() << qHandle.IndexBits))
-#endif
+#include <Qt3DCore/private/qresourcemanager_p.h>
class tst_Handle : public QObject
{
@@ -49,8 +44,6 @@ private slots:
void assignment();
void equality();
void inequality();
- void staticLimits();
- void bigHandle();
};
class SimpleResource
@@ -64,107 +57,60 @@ public:
};
typedef Qt3DCore::QHandle<SimpleResource> Handle;
-typedef Qt3DCore::QHandle<SimpleResource, 22> BigHandle;
+typedef Qt3DCore::QHandleData<SimpleResource> HandleData;
void tst_Handle::defaultConstruction()
{
Handle h;
QVERIFY(h.isNull() == true);
- QVERIFY(h.index() == 0);
- QVERIFY(h.counter() == 0);
QVERIFY(h.handle() == 0);
}
void tst_Handle::construction()
{
- Handle h(0, 1);
+ HandleData d;
+ Handle h(&d);
QVERIFY(h.isNull() == false);
- QVERIFY(h.index() == 0);
- QVERIFY(h.counter() == 1);
qDebug() << h;
- QVERIFY(h.handle() == GET_EXPECTED_HANDLE(h));
-
- Handle h2(1, 1);
- QVERIFY(h2.isNull() == false);
- QVERIFY(h2.index() == 1);
- QVERIFY(h2.counter() == 1);
- qDebug() << h2;
- QVERIFY(h2.handle() == GET_EXPECTED_HANDLE(h2));
+ QVERIFY(h.handle() == reinterpret_cast<quintptr>(&d));
}
void tst_Handle::copyConstruction()
{
- Handle h1(0, 1);
- Handle h2(h1);
+ HandleData d;
+ Handle h(&d);
+ Handle h2(h);
QVERIFY(h2.isNull() == false);
- QVERIFY(h2.index() == 0);
- QVERIFY(h2.counter() == 1);
- QVERIFY(h2.handle() == GET_EXPECTED_HANDLE(h2));
+ QVERIFY(h2.handle() == h.handle());
}
void tst_Handle::assignment()
{
- Handle h1(0, 1);
- Handle h2 = h1;
+ HandleData d;
+ Handle h(&d);
+ Handle h2;
+ h2 = h;
QVERIFY(h2.isNull() == false);
- QVERIFY(h2.index() == 0);
- QVERIFY(h2.counter() == 1);
- QVERIFY(h2.handle() == GET_EXPECTED_HANDLE(h2));
+ QVERIFY(h2.handle() == h.handle());
}
void tst_Handle::equality()
{
- Handle h1(2, 1);
- Handle h2(2, 1);
+ HandleData d;
+ Handle h1(&d);
+ Handle h2(&d);
QVERIFY(h1.isNull() == false);
- QVERIFY(h1.index() == 2);
- QVERIFY(h1.counter() == 1);
- QVERIFY(h1.handle() == GET_EXPECTED_HANDLE(h1));
QVERIFY(h1 == h2);
}
void tst_Handle::inequality()
{
- Handle h1(2, 1);
- Handle h2(3, 1);
+ HandleData d1;
+ HandleData d2;
+ Handle h1(&d1);
+ Handle h2(&d2);
QVERIFY(h1.isNull() == false);
- QVERIFY(h1.index() == 2);
- QVERIFY(h1.counter() == 1);
- QVERIFY(h1.handle() == GET_EXPECTED_HANDLE(h1));
QVERIFY(h1 != h2);
-
- Handle h3(2, 2);
- QVERIFY(h1 != h3);
-}
-
-void tst_Handle::staticLimits()
-{
- QVERIFY(Handle::maxIndex() == (1 << 16) - 1);
- QVERIFY(Handle::maxCounter() == (1 << (32 - 16 - 2)) - 1);
-}
-
-void tst_Handle::bigHandle()
-{
- BigHandle h;
- QVERIFY(h.isNull() == true);
- QVERIFY(h.index() == 0);
- QVERIFY(h.counter() == 0);
- QVERIFY(h.handle() == 0);
-
- BigHandle h1(0, 1);
- QVERIFY(h1.isNull() == false);
- QVERIFY(h1.index() == 0);
- QVERIFY(h1.counter() == 1);
- QVERIFY(h1.handle() == GET_EXPECTED_HANDLE(h1));
-
- BigHandle h2(1, 1);
- QVERIFY(h2.isNull() == false);
- QVERIFY(h2.index() == 1);
- QVERIFY(h2.counter() == 1);
- QVERIFY(h2.handle() == GET_EXPECTED_HANDLE(h2));
-
- QVERIFY(BigHandle::maxIndex() == (1 << 22) - 1);
- QVERIFY(BigHandle::maxCounter() == (1 << (32 - 22 - 2)) - 1);
}
QTEST_APPLESS_MAIN(tst_Handle)
diff --git a/tests/auto/core/qresourcemanager/tst_qresourcemanager.cpp b/tests/auto/core/qresourcemanager/tst_qresourcemanager.cpp
index c3238fc8f..b7bd7c28a 100644
--- a/tests/auto/core/qresourcemanager/tst_qresourcemanager.cpp
+++ b/tests/auto/core/qresourcemanager/tst_qresourcemanager.cpp
@@ -97,8 +97,9 @@ void tst_DynamicArrayPolicy::acquireResources()
}
for (uint i = 0; i < 5; i++) {
- QVERIFY(handles.at(i).index() == i);
- QVERIFY(handles.at(i).counter() == 1);
+ QVERIFY(!handles.at(i).isNull());
+ if (i > 0)
+ QVERIFY(handles.at(i) != handles.at(i-1));
}
}
@@ -117,8 +118,6 @@ void tst_DynamicArrayPolicy::getResources()
}
for (uint i = 0; i < 5; i++) {
- QVERIFY(handles.at(i).index() == i);
- QVERIFY(handles.at(i).counter() == 1);
resources << manager.data(handles.at(i));
QVERIFY(resources.at(i) != nullptr);
resources.at(i)->m_value = i;
@@ -153,8 +152,6 @@ void tst_DynamicArrayPolicy::registerResourcesResize()
}
for (int i = 0; i < 7; i++) {
- QVERIFY(handles.at(i).index() == static_cast<uint>(i));
- QVERIFY(handles.at(i).counter() == 1);
if (i < 2)
QVERIFY(manager.data(handles.at(i))->m_value == i + 2);
else
@@ -169,14 +166,16 @@ void tst_DynamicArrayPolicy::removeResource()
{
Qt3DCore::QResourceManager<tst_ArrayResource, int> manager;
- QList<tst_ArrayResource *> resources;
QList<tHandle> handles;
for (int i = 0; i < 32; i++) {
handles << manager.acquire();
- resources << manager.data(handles.at(i));
}
+
+ tst_ArrayResource *resource = handles.at(2).data();
+ QVERIFY(resource != nullptr);
+
manager.release(handles.at(2));
QVERIFY(manager.data(handles.at(2)) == nullptr);
// Triggers QASSERT so commented
@@ -255,7 +254,7 @@ protected:
void run()
{
int i = 0;
- int max = tHandle::maxIndex();
+ int max = 65535;
while (i < max) {
tst_ArrayResource *r = m_manager->getOrCreateResource(i);
i++;
@@ -275,7 +274,7 @@ void tst_DynamicArrayPolicy::heavyDutyMultiThreadedAccess()
QList<tst_Thread *> threads;
int iterations = 8;
- int max = tHandle16::maxIndex();
+ int max = 65535;
for (int i = 0; i < iterations; i++) {
tst_Thread *thread = new tst_Thread();
@@ -326,7 +325,7 @@ protected:
void run()
{
int i = 0;
- int max = tHandle::maxIndex();
+ int max = 65535;
while (i < max) {
tst_ArrayResource *r = m_manager->getOrCreateResource(i);
QVERIFY(r != nullptr);
@@ -349,7 +348,7 @@ void tst_DynamicArrayPolicy::heavyDutyMultiThreadedAccessRelease()
QList<tst_Thread2 *> threads;
int iterations = 8;
- int max = tHandle16::maxIndex();
+ int max = 65535;
for (int u = 0; u < 2; u++) {
@@ -385,8 +384,6 @@ void tst_DynamicArrayPolicy::maximumNumberOfResources()
QList<tst_ArrayResource *> resources;
QList<tHandle16> handles;
- QCOMPARE(tHandle16::maxIndex(), (uint)manager.maximumSize());
-
for (int i = 0; i < manager.maximumSize(); i++) {
handles << manager.acquire();
resources << manager.data(handles.at(i));
diff --git a/tests/auto/render/geometryloaders/cube2.obj b/tests/auto/render/geometryloaders/cube2.obj
new file mode 100644
index 000000000..8ea0caf87
--- /dev/null
+++ b/tests/auto/render/geometryloaders/cube2.obj
@@ -0,0 +1,26 @@
+# Blender v2.77 (sub 0) OBJ File: ''
+# www.blender.org
+mtllib cube.mtl
+o Cube
+v 1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 -1.000000
+v 1.000000 1.000000 -0.999999
+v 0.999999 1.000000 1.000001
+v -1.000000 1.000000 1.000000
+v -1.000000 1.000000 -1.000000
+vn 0.0000 -1.0000 0.0000
+vn 0.0000 1.0000 0.0000
+vn 1.0000 0.0000 0.0000
+vn -0.0000 -0.0000 1.0000
+vn -1.0000 -0.0000 -0.0000
+vn 0.0000 0.0000 -1.0000
+usemtl Material
+s off
+f 1//1 2//1 3//1 4//1
+f 5//2 8//2 7//2 6//2
+f 1//3 5//3 6//3 2//3
+f 2//4 6//4 7//4 3//4
+f 3//5 7//5 8//5 4//5
+f 5//6 1//6 4//6 8//6
diff --git a/tests/auto/render/geometryloaders/geometryloaders.qrc b/tests/auto/render/geometryloaders/geometryloaders.qrc
index 730a0c452..8f98f5a14 100644
--- a/tests/auto/render/geometryloaders/geometryloaders.qrc
+++ b/tests/auto/render/geometryloaders/geometryloaders.qrc
@@ -1,6 +1,7 @@
<RCC>
<qresource prefix="/">
<file>cube.obj</file>
+ <file>cube2.obj</file>
<file>cube.ply</file>
<file>cube.stl</file>
<file>cube.gltf</file>
diff --git a/tests/auto/render/geometryloaders/tst_geometryloaders.cpp b/tests/auto/render/geometryloaders/tst_geometryloaders.cpp
index 7b9f09d23..07545403d 100644
--- a/tests/auto/render/geometryloaders/tst_geometryloaders.cpp
+++ b/tests/auto/render/geometryloaders/tst_geometryloaders.cpp
@@ -60,6 +60,7 @@ class tst_geometryloaders : public QObject
Q_OBJECT
private Q_SLOTS:
+ void testOBJLoader_data();
void testOBJLoader();
void testPLYLoader();
void testSTLLoader();
@@ -69,6 +70,12 @@ private Q_SLOTS:
#endif
};
+void tst_geometryloaders::testOBJLoader_data()
+{
+ QTest::addColumn<QString>("fileName");
+ QTest::newRow("nominal case") << QStringLiteral(":/cube.obj");
+ QTest::newRow("trailing space + crlf") << QStringLiteral(":/cube2.obj");
+}
void tst_geometryloaders::testOBJLoader()
{
QScopedPointer<QGeometryLoaderInterface> loader;
@@ -77,7 +84,8 @@ void tst_geometryloaders::testOBJLoader()
if (!loader)
return;
- QFile file(QStringLiteral(":/cube.obj"));
+ QFETCH(QString, fileName);
+ QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug("Could not open test file for reading");
return;
diff --git a/tests/auto/render/renderer/tst_renderer.cpp b/tests/auto/render/renderer/tst_renderer.cpp
index 855b07797..85d978926 100644
--- a/tests/auto/render/renderer/tst_renderer.cpp
+++ b/tests/auto/render/renderer/tst_renderer.cpp
@@ -60,7 +60,7 @@ private Q_SLOTS:
renderer.setSettings(&settings);
renderer.initialize();
- const int singleRenderViewJobCount = 12 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount();
+ const int singleRenderViewJobCount = 11 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount();
// RenderViewBuilder renderViewJob,
// renderableEntityFilterJob,
// lightGatherJob,
diff --git a/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp b/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp
index b781ff04d..7a29c3ebd 100644
--- a/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp
+++ b/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp
@@ -199,6 +199,10 @@ private Q_SLOTS:
QCOMPARE(renderViewBuilder.renderViewBuilderJobs().size(), Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
QCOMPARE(renderViewBuilder.materialGathererJobs().size(), Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
+ QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 11 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
+
+ // mark jobs dirty and recheck
+ testAspect.renderer()->markDirty(Qt3DRender::Render::AbstractRenderer::LayersDirty, nullptr);
QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 12 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
}
diff --git a/tests/benchmarks/core/qresourcesmanager/qresourcesmanager/tst_bench_qresourcesmanager.cpp b/tests/benchmarks/core/qresourcesmanager/qresourcesmanager/tst_bench_qresourcesmanager.cpp
index 6ddb058a1..51eb2d6fc 100644
--- a/tests/benchmarks/core/qresourcesmanager/qresourcesmanager/tst_bench_qresourcesmanager.cpp
+++ b/tests/benchmarks/core/qresourcesmanager/qresourcesmanager/tst_bench_qresourcesmanager.cpp
@@ -159,9 +159,14 @@ void benchmarkReleaseResources()
QVector<Qt3DCore::QHandle<Resource> > handles(max);
for (int i = 0; i < max; i++)
handles[i] = manager.acquire();
+ for (int i = 0; i < max; i++)
+ manager.release(handles.at(i));
+ handles.clear();
QBENCHMARK_ONCE {
- /*manager.reset()*/;
+ // the release/clear should have left many unused handled in the resourcemanager,
+ // so the next acquire will trigger a collection of all freed resources
+ manager.acquire();
}
}