diff options
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(); } } |