diff options
author | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2017-11-20 13:48:26 +0100 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2017-11-20 13:48:26 +0100 |
commit | a2c7dbba0ad60cf17997f77372004339d4580a52 (patch) | |
tree | c0f7f03107438b85031808a9581bf9adecc138ba | |
parent | 2e26894fdd2d4593bee6ab9062f64a1f4210d619 (diff) | |
parent | 5e94e34c5b9567980929e677357467806aacaf1a (diff) |
Merge 5.10 into 5.10.0
Change-Id: I1d59f6d4f69c5ab33efe1a00a983a2af880ef79a
66 files changed, 2162 insertions, 538 deletions
diff --git a/examples/qt3d/controls/Logo.qml b/examples/qt3d/controls/Logo.qml index 2eb9abd1a..62742246f 100644 --- a/examples/qt3d/controls/Logo.qml +++ b/examples/qt3d/controls/Logo.qml @@ -91,8 +91,8 @@ Entity { PhongMaterial { id: material - ambient: Qt.rgba( color_r.value/255, color_g.value/255, color_b.value/255, 1.0 ) - diffuse: Qt.rgba( 0.1, 0.1, 0.1, 0.5 ) + diffuse: Qt.rgba( color_r.value/255, color_g.value/255, color_b.value/255, 1.0 ) + ambient: Qt.rgba( 0.1, 0.1, 0.1, 1.0 ) shininess: shining.value } @@ -110,4 +110,16 @@ Entity { id: logoEntity components: [ logoMesh, material, logoTransform ] } + + Entity { + components: [ + PointLight { + color: "white" + intensity: 0.6 + }, + Transform { + translation: Qt.vector3d(0, 0, 10) + } + ] + } } diff --git a/examples/qt3d/phong-cubes/main.qml b/examples/qt3d/phong-cubes/main.qml index 0e067fdad..311e65a63 100644 --- a/examples/qt3d/phong-cubes/main.qml +++ b/examples/qt3d/phong-cubes/main.qml @@ -51,7 +51,8 @@ import Qt3D.Core 2.0 import Qt3D.Render 2.0 import Qt3D.Input 2.0 -import Qt3D.Extras 2.0 +import Qt3D.Extras 2.10 +import QtQuick 2.0 Entity { components: [ @@ -84,19 +85,19 @@ Entity { CubeEntity { position: Qt.vector3d(-1, 1, 0) - material: PhongMaterial {} + material: DiffuseSpecularMaterial {} } CubeEntity { position: Qt.vector3d(0, 1, 0) - material: DiffuseMapMaterial { + material: DiffuseSpecularMaterial { diffuse: TextureLoader { source: "qrc:/assets/textures/pattern_09/diffuse.webp" } } } CubeEntity { position: Qt.vector3d(1, 1, 0) - material: DiffuseSpecularMapMaterial { + material: DiffuseSpecularMaterial { diffuse: TextureLoader { source: "qrc:/assets/textures/pattern_09/diffuse.webp" } specular: TextureLoader { source: "qrc:/assets/textures/pattern_09/specular.webp" } } @@ -104,12 +105,15 @@ Entity { CubeEntity { position: Qt.vector3d(-1, 0, 0) - material: PhongAlphaMaterial {} + material: DiffuseSpecularMaterial { + alphaBlending: true + diffuse: Qt.rgba(0.7, 0.7, 0.7, 0.5) + } } CubeEntity { position: Qt.vector3d(0, 0, 0) - material: NormalDiffuseMapMaterial { + material: DiffuseSpecularMaterial { normal: TextureLoader { source: "qrc:/assets/textures/pattern_09/normal.webp" } diffuse: TextureLoader { source: "qrc:/assets/textures/pattern_09/diffuse.webp" } } @@ -117,7 +121,8 @@ Entity { CubeEntity { position: Qt.vector3d(1, 0, 0) - material: NormalDiffuseMapAlphaMaterial { + material: DiffuseSpecularMaterial { + alphaBlending: true normal: TextureLoader { source: "qrc:/assets/textures/pattern_09/normal.webp" } diffuse: TextureLoader { source: "qrc:/assets/textures/pattern_09/diffuse.webp" } } @@ -125,7 +130,7 @@ Entity { CubeEntity { position: Qt.vector3d(-1, -1, 0) - material: NormalDiffuseSpecularMapMaterial { + material: DiffuseSpecularMaterial { normal: TextureLoader { source: "qrc:/assets/textures/pattern_09/normal.webp" } diffuse: TextureLoader { source: "qrc:/assets/textures/pattern_09/diffuse.webp" } specular: TextureLoader { source: "qrc:/assets/textures/pattern_09/specular.webp" } @@ -134,7 +139,7 @@ Entity { CubeEntity { position: Qt.vector3d(0, -1, 0) - material: NormalDiffuseSpecularMapMaterial { + material: DiffuseSpecularMaterial { normal: TextureLoader { source: "qrc:/assets/textures/pattern_09/normal.webp" } diffuse: TextureLoader { source: "qrc:/assets/textures/pattern_09/diffuse.webp" } specular: TextureLoader { source: "qrc:/assets/textures/pattern_09/specular.webp" } @@ -143,7 +148,7 @@ Entity { CubeEntity { position: Qt.vector3d(1, -1, 0) - material: NormalDiffuseSpecularMapMaterial { + material: DiffuseSpecularMaterial { normal: TextureLoader { source: "qrc:/assets/textures/pattern_09/normal.webp" } diffuse: TextureLoader { source: "qrc:/assets/textures/pattern_09/diffuse.webp" } specular: TextureLoader { source: "qrc:/assets/textures/pattern_09/specular.webp" } diff --git a/src/animation/backend/channelmapping.cpp b/src/animation/backend/channelmapping.cpp index 4c263edba..ecae8bbae 100644 --- a/src/animation/backend/channelmapping.cpp +++ b/src/animation/backend/channelmapping.cpp @@ -36,6 +36,7 @@ #include "channelmapping_p.h" #include <Qt3DAnimation/qchannelmapping.h> +#include <Qt3DAnimation/private/qcallbackmapping_p.h> #include <Qt3DAnimation/private/qchannelmapping_p.h> #include <Qt3DAnimation/private/qskeletonmapping_p.h> #include <Qt3DAnimation/private/animationlogging_p.h> @@ -58,6 +59,7 @@ ChannelMapping::ChannelMapping() , m_callback(nullptr) , m_callbackFlags(0) , m_skeletonId() + , m_mappingType(MappingType::ChannelMappingType) { } @@ -73,8 +75,6 @@ void ChannelMapping::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePt m_property = data.property; m_type = data.type; m_propertyName = data.propertyName; - m_callback = data.callback; - m_callbackFlags = data.callbackFlags; m_mappingType = ChannelMappingType; break; } @@ -88,8 +88,13 @@ void ChannelMapping::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePt } case QChannelMappingCreatedChangeBase::CallbackMapping: { - // TODO: Refactor callback support out of QChannelMapping and into its own type - m_mappingType = CallbackMappingType; + const auto typedChange = qSharedPointerCast<QChannelMappingCreatedChange<QCallbackMappingData>>(change); + const auto &data = typedChange->data; + m_channelName = data.channelName; + m_type = data.type; + m_callback = data.callback; + m_callbackFlags = data.callbackFlags; + m_mappingType = ChannelMappingType; break; } } diff --git a/src/animation/backend/handler.cpp b/src/animation/backend/handler.cpp index 071343791..ed48d281f 100644 --- a/src/animation/backend/handler.cpp +++ b/src/animation/backend/handler.cpp @@ -149,6 +149,16 @@ void Handler::setBlendedClipAnimatorRunning(const HBlendedClipAnimator &handle, // The vectors may get outdated when the application removes/deletes an // animator component in the meantime. Recognize this. This should be // relatively infrequent so in most cases the vectors will not change at all. +void Handler::cleanupHandleList(QVector<HAnimationClip> *clips) +{ + for (auto it = clips->begin(); it != clips->end(); ) { + if (!m_animationClipLoaderManager->data(*it)) + clips->erase(it); + else + ++it; + } +} + void Handler::cleanupHandleList(QVector<HClipAnimator> *animators) { for (auto it = animators->begin(); it != animators->end(); ) { @@ -182,8 +192,10 @@ QVector<Qt3DCore::QAspectJobPtr> Handler::jobsToExecute(qint64 time) // If there are any dirty animation clips that need loading, // queue up a job for them - if (!m_dirtyAnimationClips.isEmpty()) { + const bool hasLoadAnimationClipJob = !m_dirtyAnimationClips.isEmpty(); + if (hasLoadAnimationClipJob) { qCDebug(HandlerLogic) << "Added LoadAnimationClipJob"; + cleanupHandleList(&m_dirtyAnimationClips); m_loadAnimationClipJob->addDirtyAnimationClips(m_dirtyAnimationClips); jobs.push_back(m_loadAnimationClipJob); m_dirtyAnimationClips.clear(); @@ -192,19 +204,22 @@ QVector<Qt3DCore::QAspectJobPtr> Handler::jobsToExecute(qint64 time) // If there are dirty clip animators, find the set that are able to // run. I.e. are marked as running and have animation clips and // channel mappings - if (!m_dirtyClipAnimators.isEmpty()) { + + const bool hasFindRunningClipAnimatorsJob = !m_dirtyClipAnimators.isEmpty(); + if (hasFindRunningClipAnimatorsJob) { qCDebug(HandlerLogic) << "Added FindRunningClipAnimatorsJob"; m_findRunningClipAnimatorsJob->removeDependency(QWeakPointer<Qt3DCore::QAspectJob>()); cleanupHandleList(&m_dirtyClipAnimators); m_findRunningClipAnimatorsJob->setDirtyClipAnimators(m_dirtyClipAnimators); jobs.push_back(m_findRunningClipAnimatorsJob); - if (jobs.contains(m_loadAnimationClipJob)) + if (hasLoadAnimationClipJob) m_findRunningClipAnimatorsJob->addDependency(m_loadAnimationClipJob); m_dirtyClipAnimators.clear(); } // Rebuild blending trees if a blend tree is dirty - if (!m_dirtyBlendedAnimators.isEmpty()) { + const bool hasBuildBlendTreesJob = !m_dirtyBlendedAnimators.isEmpty(); + if (hasBuildBlendTreesJob) { const QVector<HBlendedClipAnimator> dirtyBlendedAnimators = std::move(m_dirtyBlendedAnimators); m_buildBlendTreesJob->setBlendedClipAnimators(dirtyBlendedAnimators); jobs.push_back(m_buildBlendTreesJob); @@ -233,9 +248,9 @@ QVector<Qt3DCore::QAspectJobPtr> Handler::jobsToExecute(qint64 time) for (int i = 0; i < newSize; ++i) { m_evaluateClipAnimatorJobs[i]->setClipAnimator(m_runningClipAnimators[i]); m_evaluateClipAnimatorJobs[i]->removeDependency(QWeakPointer<Qt3DCore::QAspectJob>()); - if (jobs.contains(m_loadAnimationClipJob)) + if (hasLoadAnimationClipJob) m_evaluateClipAnimatorJobs[i]->addDependency(m_loadAnimationClipJob); - if (jobs.contains(m_findRunningClipAnimatorsJob)) + if (hasFindRunningClipAnimatorsJob) m_evaluateClipAnimatorJobs[i]->addDependency(m_findRunningClipAnimatorsJob); jobs.push_back(m_evaluateClipAnimatorJobs[i]); } @@ -259,9 +274,9 @@ QVector<Qt3DCore::QAspectJobPtr> Handler::jobsToExecute(qint64 time) for (int i = 0; i < newSize; ++i) { m_evaluateBlendClipAnimatorJobs[i]->setBlendClipAnimator(m_runningBlendedClipAnimators[i]); m_evaluateBlendClipAnimatorJobs[i]->removeDependency(QWeakPointer<Qt3DCore::QAspectJob>()); - if (jobs.contains(m_loadAnimationClipJob)) + if (hasLoadAnimationClipJob) m_evaluateBlendClipAnimatorJobs[i]->addDependency(m_loadAnimationClipJob); - if (jobs.contains(m_buildBlendTreesJob)) + if (hasBuildBlendTreesJob) m_evaluateBlendClipAnimatorJobs[i]->addDependency(m_buildBlendTreesJob); jobs.push_back(m_evaluateBlendClipAnimatorJobs[i]); } diff --git a/src/animation/backend/handler_p.h b/src/animation/backend/handler_p.h index d35d5a132..99e2ae1f6 100644 --- a/src/animation/backend/handler_p.h +++ b/src/animation/backend/handler_p.h @@ -121,6 +121,7 @@ public: QVector<Qt3DCore::QAspectJobPtr> jobsToExecute(qint64 time); + void cleanupHandleList(QVector<HAnimationClip> *clips); void cleanupHandleList(QVector<HClipAnimator> *animators); void cleanupHandleList(QVector<HBlendedClipAnimator> *animators); diff --git a/src/animation/backend/loadanimationclipjob.cpp b/src/animation/backend/loadanimationclipjob.cpp index c0201e0e9..4584449bc 100644 --- a/src/animation/backend/loadanimationclipjob.cpp +++ b/src/animation/backend/loadanimationclipjob.cpp @@ -72,6 +72,7 @@ void LoadAnimationClipJob::run() AnimationClipLoaderManager *animationClipManager = m_handler->animationClipLoaderManager(); for (const auto animationClipHandle : qAsConst(m_animationClipHandles)) { AnimationClip *animationClip = animationClipManager->data(animationClipHandle); + Q_ASSERT(animationClip); animationClip->loadAnimation(); } diff --git a/src/animation/frontend/frontend.pri b/src/animation/frontend/frontend.pri index 48b1cb6b1..baff81dd0 100644 --- a/src/animation/frontend/frontend.pri +++ b/src/animation/frontend/frontend.pri @@ -54,7 +54,9 @@ HEADERS += \ $$PWD/qchannelmappingcreatedchange_p.h \ $$PWD/qchannelmappingcreatedchange_p_p.h \ $$PWD/qskeletonmapping.h \ - $$PWD/qskeletonmapping_p.h + $$PWD/qskeletonmapping_p.h \ + $$PWD/qcallbackmapping.h \ + $$PWD/qcallbackmapping_p.h SOURCES += \ $$PWD/qanimationaspect.cpp \ @@ -86,6 +88,7 @@ SOURCES += \ $$PWD/qclock.cpp \ $$PWD/qabstractchannelmapping.cpp \ $$PWD/qchannelmappingcreatedchange.cpp \ - $$PWD/qskeletonmapping.cpp + $$PWD/qskeletonmapping.cpp \ + $$PWD/qcallbackmapping.cpp INCLUDEPATH += $$PWD diff --git a/src/animation/frontend/qanimationcallback.h b/src/animation/frontend/qanimationcallback.h index 63e094918..1fcbd657c 100644 --- a/src/animation/frontend/qanimationcallback.h +++ b/src/animation/frontend/qanimationcallback.h @@ -48,6 +48,7 @@ class QT3DANIMATIONSHARED_EXPORT QAnimationCallback { public: enum Flag { + OnOwningThread = 0x0, OnThreadPool = 0x01 }; Q_DECLARE_FLAGS(Flags, Flag) diff --git a/src/animation/frontend/qcallbackmapping.cpp b/src/animation/frontend/qcallbackmapping.cpp new file mode 100644 index 000000000..3fcc7cf5e --- /dev/null +++ b/src/animation/frontend/qcallbackmapping.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcallbackmapping.h" +#include "qcallbackmapping_p.h" + +#include <Qt3DAnimation/private/qchannelmappingcreatedchange_p.h> +#include <Qt3DCore/qpropertyupdatedchange.h> + +#include <QtCore/qmetaobject.h> +#include <QtCore/QMetaProperty> + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +QCallbackMappingPrivate::QCallbackMappingPrivate() + : QAbstractChannelMappingPrivate() + , m_channelName() + , m_type(static_cast<int>(QVariant::Invalid)) + , m_callback(nullptr) + , m_callbackFlags(0) +{ + m_mappingType = QChannelMappingCreatedChangeBase::CallbackMapping; +} + +/*! + \class QCallbackMapping + \inherits Qt3DCore::QAbstractChannelMapping + \inmodule Qt3DAnimation + \brief Allows to map the channels within the clip onto an invocation + of a callback object. +*/ + +QCallbackMapping::QCallbackMapping(Qt3DCore::QNode *parent) + : QAbstractChannelMapping(*new QCallbackMappingPrivate, parent) +{ +} + +QCallbackMapping::QCallbackMapping(QCallbackMappingPrivate &dd, Qt3DCore::QNode *parent) + : QAbstractChannelMapping(dd, parent) +{ +} + +QCallbackMapping::~QCallbackMapping() +{ +} + +QString QCallbackMapping::channelName() const +{ + Q_D(const QCallbackMapping); + return d->m_channelName; +} + +QAnimationCallback *QCallbackMapping::callback() const +{ + Q_D(const QCallbackMapping); + return d->m_callback; +} + +void QCallbackMapping::setChannelName(const QString &channelName) +{ + Q_D(QCallbackMapping); + if (d->m_channelName == channelName) + return; + + d->m_channelName = channelName; + emit channelNameChanged(channelName); +} + +/*! + Associates a \a callback object with this channel mapping. + + Such mappings do not have to have a target object and property name. When + the \a callback object is set, every change in the animated value will lead + to invoking the callback's + \l{QAnimationCallback::onValueChanged()}{onValueChanged()} function either + on the gui/main thread, or directly on one of the thread pool's worker + thread. This is controlled by \a flags. + + \a type specifies the type (for example, QVariant::Vector3D, + QVariant::Color, or QMetaType::Float) of the animated value. When animating + node properties this does not need to be provided separately, however it + becomes important to supply this when there is only a callback. + + \note A mapping can be associated both with a node property and a + callback. It is important however that \a type matches the type of the + property in this case. Note also that for properties of type QVariant (for + example, QParameter::value), the \a type is the type of the value stored in + the QVariant. + + \note The \a callback pointer is expected to stay valid while any + associated animators are running. + */ +void QCallbackMapping::setCallback(int type, QAnimationCallback *callback, QAnimationCallback::Flags flags) +{ + Q_D(QCallbackMapping); + if (d->m_type != type) { + d->m_type = type; + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(id()); + e->setPropertyName("type"); + e->setValue(QVariant(d->m_type)); + notifyObservers(e); + } + if (d->m_callback != callback) { + d->m_callback = callback; + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(id()); + e->setPropertyName("callback"); + e->setValue(QVariant::fromValue(static_cast<void *>(d->m_callback))); + notifyObservers(e); + } + if (d->m_callbackFlags != flags) { + d->m_callbackFlags = flags; + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(id()); + e->setPropertyName("callbackFlags"); + e->setValue(QVariant::fromValue(int(d->m_callbackFlags))); + notifyObservers(e); + } +} + +Qt3DCore::QNodeCreatedChangeBasePtr QCallbackMapping::createNodeCreationChange() const +{ + auto creationChange = QChannelMappingCreatedChangePtr<QCallbackMappingData>::create(this); + auto &data = creationChange->data; + Q_D(const QCallbackMapping); + data.channelName = d->m_channelName; + data.type = d->m_type; + data.callback = d->m_callback; + data.callbackFlags = d->m_callbackFlags; + return creationChange; +} + +} // namespace Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/frontend/qcallbackmapping.h b/src/animation/frontend/qcallbackmapping.h new file mode 100644 index 000000000..c52e284ff --- /dev/null +++ b/src/animation/frontend/qcallbackmapping.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QCALLBACKMAPPING_H +#define QT3DANIMATION_QCALLBACKMAPPING_H + +#include <Qt3DAnimation/qt3danimation_global.h> +#include <Qt3DAnimation/qanimationcallback.h> +#include <Qt3DAnimation/qabstractchannelmapping.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QCallbackMappingPrivate; + +class QT3DANIMATIONSHARED_EXPORT QCallbackMapping : public QAbstractChannelMapping +{ + Q_OBJECT + Q_PROPERTY(QString channelName READ channelName WRITE setChannelName NOTIFY channelNameChanged) + +public: + explicit QCallbackMapping(Qt3DCore::QNode *parent = nullptr); + ~QCallbackMapping(); + + QString channelName() const; + QAnimationCallback *callback() const; + + void setCallback(int type, QAnimationCallback *callback, QAnimationCallback::Flags flags = QAnimationCallback::OnOwningThread); + +public Q_SLOTS: + void setChannelName(const QString &channelName); + +Q_SIGNALS: + void channelNameChanged(QString channelName); + +protected: + explicit QCallbackMapping(QCallbackMappingPrivate &dd, Qt3DCore::QNode *parent = nullptr); + +private: + Q_DECLARE_PRIVATE(QCallbackMapping) + Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE; +}; + +} // namespace Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QCALLBACKMAPPING_H diff --git a/src/animation/frontend/qcallbackmapping_p.h b/src/animation/frontend/qcallbackmapping_p.h new file mode 100644 index 000000000..c966ca552 --- /dev/null +++ b/src/animation/frontend/qcallbackmapping_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DANIMATION_QCALLBACKMAPPING_P_H +#define QT3DANIMATION_QCALLBACKMAPPING_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 <Qt3DAnimation/private/qabstractchannelmapping_p.h> +#include <Qt3DAnimation/qanimationcallback.h> +#include <Qt3DAnimation/qcallbackmapping.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { + +class QCallbackMappingPrivate : public QAbstractChannelMappingPrivate +{ +public: + QCallbackMappingPrivate(); + + Q_DECLARE_PUBLIC(QCallbackMapping) + + QString m_channelName; + int m_type; + QAnimationCallback *m_callback; + QAnimationCallback::Flags m_callbackFlags; +}; + +struct QCallbackMappingData +{ + QString channelName; + int type; + QAnimationCallback *callback; + QAnimationCallback::Flags callbackFlags; +}; + +} // namespace Qt3DAnimation + + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_QCALLBACKMAPPING_P_H diff --git a/src/animation/frontend/qchannelmapping.cpp b/src/animation/frontend/qchannelmapping.cpp index cb7b0739f..722ce24b0 100644 --- a/src/animation/frontend/qchannelmapping.cpp +++ b/src/animation/frontend/qchannelmapping.cpp @@ -54,8 +54,6 @@ QChannelMappingPrivate::QChannelMappingPrivate() , m_property() , m_propertyName(nullptr) , m_type(static_cast<int>(QVariant::Invalid)) - , m_callback(nullptr) - , m_callbackFlags(0) { m_mappingType = QChannelMappingCreatedChangeBase::ChannelMapping; } @@ -152,12 +150,6 @@ QString QChannelMapping::property() const return d->m_property; } -QAnimationCallback *QChannelMapping::callback() const -{ - Q_D(const QChannelMapping); - return d->m_callback; -} - void QChannelMapping::setChannelName(const QString &channelName) { Q_D(QChannelMapping); @@ -200,56 +192,6 @@ void QChannelMapping::setProperty(const QString &property) d->updatePropertyNameAndType(); } -/*! - Associates a \a callback object with this channel mapping. - - Such mappings do not have to have a target object and property name. When - the \a callback object is set, every change in the animated value will lead - to invoking the callback's - \l{QAnimationCallback::onValueChanged()}{onValueChanged()} function either - on the gui/main thread, or directly on one of the thread pool's worker - thread. This is controlled by \a flags. - - \a type specifies the type (for example, QVariant::Vector3D, - QVariant::Color, or QMetaType::Float) of the animated value. When animating - node properties this does not need to be provided separately, however it - becomes important to supply this when there is only a callback. - - \note A mapping can be associated both with a node property and a - callback. It is important however that \a type matches the type of the - property in this case. Note also that for properties of type QVariant (for - example, QParameter::value), the \a type is the type of the value stored in - the QVariant. - - \note The \a callback pointer is expected to stay valid while any - associated animators are running. - */ -void QChannelMapping::setCallback(int type, QAnimationCallback *callback, QAnimationCallback::Flags flags) -{ - Q_D(QChannelMapping); - if (d->m_type != type) { - d->m_type = type; - auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(id()); - e->setPropertyName("type"); - e->setValue(QVariant(d->m_type)); - notifyObservers(e); - } - if (d->m_callback != callback) { - d->m_callback = callback; - auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(id()); - e->setPropertyName("callback"); - e->setValue(QVariant::fromValue(static_cast<void *>(d->m_callback))); - notifyObservers(e); - } - if (d->m_callbackFlags != flags) { - d->m_callbackFlags = flags; - auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(id()); - e->setPropertyName("callbackFlags"); - e->setValue(QVariant::fromValue(int(d->m_callbackFlags))); - notifyObservers(e); - } -} - Qt3DCore::QNodeCreatedChangeBasePtr QChannelMapping::createNodeCreationChange() const { auto creationChange = QChannelMappingCreatedChangePtr<QChannelMappingData>::create(this); @@ -260,8 +202,6 @@ Qt3DCore::QNodeCreatedChangeBasePtr QChannelMapping::createNodeCreationChange() data.property = d->m_property; data.type = d->m_type; data.propertyName = d->m_propertyName; - data.callback = d->m_callback; - data.callbackFlags = d->m_callbackFlags; return creationChange; } diff --git a/src/animation/frontend/qchannelmapping.h b/src/animation/frontend/qchannelmapping.h index 08bda13aa..893b98e86 100644 --- a/src/animation/frontend/qchannelmapping.h +++ b/src/animation/frontend/qchannelmapping.h @@ -61,9 +61,6 @@ public: QString channelName() const; Qt3DCore::QNode *target() const; QString property() const; - QAnimationCallback *callback() const; - - void setCallback(int type, QAnimationCallback *callback, QAnimationCallback::Flags flags); public Q_SLOTS: void setChannelName(const QString &channelName); diff --git a/src/animation/frontend/qchannelmapping_p.h b/src/animation/frontend/qchannelmapping_p.h index b9f1f950c..b7de3b821 100644 --- a/src/animation/frontend/qchannelmapping_p.h +++ b/src/animation/frontend/qchannelmapping_p.h @@ -69,8 +69,6 @@ public: QString m_property; const char *m_propertyName; int m_type; - QAnimationCallback *m_callback; - QAnimationCallback::Flags m_callbackFlags; }; struct QChannelMappingData @@ -80,8 +78,6 @@ struct QChannelMappingData QString property; int type; const char *propertyName; - QAnimationCallback *callback; - QAnimationCallback::Flags callbackFlags; }; } // namespace Qt3DAnimation diff --git a/src/animation/frontend/qclipanimator.cpp b/src/animation/frontend/qclipanimator.cpp index 79125a76e..6b503e87f 100644 --- a/src/animation/frontend/qclipanimator.cpp +++ b/src/animation/frontend/qclipanimator.cpp @@ -174,8 +174,9 @@ void QClipAnimator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) QAnimationCallbackTriggerPtr callbackTrigger = qSharedPointerCast<Qt3DAnimation::QAnimationCallbackTrigger>(change); if (callbackTrigger->callback()) callbackTrigger->callback()->valueChanged(callbackTrigger->value()); + } else if (change->type() == Qt3DCore::PropertyUpdated) { + QAbstractClipAnimator::sceneChangeEvent(change); } - QAbstractClipAnimator::sceneChangeEvent(change); } } // namespace Qt3DAnimation 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/extras/defaults/defaults.pri b/src/extras/defaults/defaults.pri index 4fe79e0d9..db4db24db 100644 --- a/src/extras/defaults/defaults.pri +++ b/src/extras/defaults/defaults.pri @@ -1,6 +1,8 @@ INCLUDEPATH += $$PWD HEADERS += \ + $$PWD/qdiffusespecularmaterial.h \ + $$PWD/qdiffusespecularmaterial_p.h \ $$PWD/qphongmaterial.h \ $$PWD/qphongmaterial_p.h \ $$PWD/qdiffusemapmaterial_p.h \ @@ -47,6 +49,7 @@ HEADERS += \ $$PWD/qmorphphongmaterial_p.h SOURCES += \ + $$PWD/qdiffusespecularmaterial.cpp \ $$PWD/qphongmaterial.cpp \ $$PWD/qdiffusemapmaterial.cpp \ $$PWD/qnormaldiffusespecularmapmaterial.cpp \ diff --git a/src/extras/defaults/qdiffusemapmaterial.cpp b/src/extras/defaults/qdiffusemapmaterial.cpp index 29e8586e3..26fb99c2c 100644 --- a/src/extras/defaults/qdiffusemapmaterial.cpp +++ b/src/extras/defaults/qdiffusemapmaterial.cpp @@ -201,6 +201,9 @@ void QDiffuseMapMaterialPrivate::handleTextureScaleChanged(const QVariant &var) \since 5.7 \inherits Qt3DRender::QMaterial + \deprecated + \see Qt3DExtras::QDiffuseSpecularMaterial + The specular lighting effect is based on the combination of 3 lighting components ambient, diffuse and specular. The relative strengths of these components are controlled by means of their reflectivity coefficients which are modelled as RGB triplets: diff --git a/src/extras/defaults/qdiffusespecularmapmaterial.cpp b/src/extras/defaults/qdiffusespecularmapmaterial.cpp index cc5facd8c..727eaed27 100644 --- a/src/extras/defaults/qdiffusespecularmapmaterial.cpp +++ b/src/extras/defaults/qdiffusespecularmapmaterial.cpp @@ -208,6 +208,9 @@ void QDiffuseSpecularMapMaterialPrivate::handleTextureScaleChanged(const QVarian \since 5.7 \inherits Qt3DRender::QMaterial + \deprecated + \see Qt3DExtras::QDiffuseSpecularMaterial + The specular lighting effect is based on the combination of 3 lighting components ambient, diffuse and specular. The relative strengths of these components are controlled by means of their reflectivity coefficients which are modelled as RGB triplets: diff --git a/src/extras/defaults/qdiffusespecularmaterial.cpp b/src/extras/defaults/qdiffusespecularmaterial.cpp new file mode 100644 index 000000000..83bba9e41 --- /dev/null +++ b/src/extras/defaults/qdiffusespecularmaterial.cpp @@ -0,0 +1,496 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdiffusespecularmaterial.h" +#include "qdiffusespecularmaterial_p.h" + +#include <Qt3DRender/qfilterkey.h> +#include <Qt3DRender/qmaterial.h> +#include <Qt3DRender/qeffect.h> +#include <Qt3DRender/qtechnique.h> +#include <Qt3DRender/qtexture.h> +#include <Qt3DRender/qshaderprogram.h> +#include <Qt3DRender/qshaderprogrambuilder.h> +#include <Qt3DRender/qparameter.h> +#include <Qt3DRender/qrenderpass.h> +#include <Qt3DRender/qgraphicsapifilter.h> +#include <Qt3DRender/qblendequation.h> +#include <Qt3DRender/qblendequationarguments.h> +#include <Qt3DRender/qnodepthmask.h> +#include <QtCore/QUrl> +#include <QtGui/QVector3D> +#include <QtGui/QVector4D> + + +QT_BEGIN_NAMESPACE + +using namespace Qt3DRender; + +namespace Qt3DExtras { + +QDiffuseSpecularMaterialPrivate::QDiffuseSpecularMaterialPrivate() + : QMaterialPrivate() + , m_effect(new QEffect()) + , m_ambientParameter(new QParameter(QStringLiteral("ka"), QColor::fromRgbF(0.05f, 0.05f, 0.05f, 1.0f))) + , m_diffuseParameter(new QParameter(QStringLiteral("kd"), QColor::fromRgbF(0.7f, 0.7f, 0.7f, 1.0f))) + , m_specularParameter(new QParameter(QStringLiteral("ks"), QColor::fromRgbF(0.01f, 0.01f, 0.01f, 1.0f))) + , m_diffuseTextureParameter(new QParameter(QStringLiteral("diffuseTexture"), QVariant())) + , m_specularTextureParameter(new QParameter(QStringLiteral("specularTexture"), QVariant())) + , m_shininessParameter(new QParameter(QStringLiteral("shininess"), 150.0f)) + , m_normalTextureParameter(new QParameter(QStringLiteral("normalTexture"), QVariant())) + , m_textureScaleParameter(new QParameter(QStringLiteral("texCoordScale"), 1.0f)) + , m_gl3Technique(new QTechnique()) + , m_gl2Technique(new QTechnique()) + , m_es2Technique(new QTechnique()) + , m_gl3RenderPass(new QRenderPass()) + , m_gl2RenderPass(new QRenderPass()) + , m_es2RenderPass(new QRenderPass()) + , m_gl3Shader(new QShaderProgram()) + , m_gl3ShaderBuilder(new QShaderProgramBuilder()) + , m_gl2es2Shader(new QShaderProgram()) + , m_gl2es2ShaderBuilder(new QShaderProgramBuilder()) + , m_noDepthMask(new QNoDepthMask()) + , m_blendState(new QBlendEquationArguments()) + , m_blendEquation(new QBlendEquation()) + , m_filterKey(new QFilterKey) +{ +} + +void QDiffuseSpecularMaterialPrivate::init() +{ + Q_Q(QDiffuseSpecularMaterial); + + connect(m_ambientParameter, &Qt3DRender::QParameter::valueChanged, + this, &QDiffuseSpecularMaterialPrivate::handleAmbientChanged); + QObject::connect(m_diffuseParameter, &Qt3DRender::QParameter::valueChanged, + q, &QDiffuseSpecularMaterial::diffuseChanged); + QObject::connect(m_specularParameter, &Qt3DRender::QParameter::valueChanged, + q, &QDiffuseSpecularMaterial::specularChanged); + connect(m_shininessParameter, &Qt3DRender::QParameter::valueChanged, + this, &QDiffuseSpecularMaterialPrivate::handleShininessChanged); + QObject::connect(m_normalTextureParameter, &Qt3DRender::QParameter::valueChanged, + q, &QDiffuseSpecularMaterial::normalChanged); + connect(m_textureScaleParameter, &Qt3DRender::QParameter::valueChanged, + this, &QDiffuseSpecularMaterialPrivate::handleTextureScaleChanged); + QObject::connect(m_noDepthMask, &QNoDepthMask::enabledChanged, + q, &QDiffuseSpecularMaterial::alphaBlendingEnabledChanged); + + m_gl3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/default.vert")))); + m_gl3ShaderBuilder->setParent(q); + m_gl3ShaderBuilder->setShaderProgram(m_gl3Shader); + m_gl3ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json"))); + m_gl3ShaderBuilder->setEnabledLayers({QStringLiteral("diffuse"), + QStringLiteral("specular"), + QStringLiteral("normal")}); + + m_gl2es2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/default.vert")))); + m_gl2es2ShaderBuilder->setParent(q); + m_gl2es2ShaderBuilder->setShaderProgram(m_gl2es2Shader); + m_gl2es2ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json"))); + m_gl2es2ShaderBuilder->setEnabledLayers({QStringLiteral("diffuse"), + QStringLiteral("specular"), + QStringLiteral("normal")}); + + + m_gl3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL); + m_gl3Technique->graphicsApiFilter()->setMajorVersion(3); + m_gl3Technique->graphicsApiFilter()->setMinorVersion(1); + m_gl3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile); + + m_gl2Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL); + m_gl2Technique->graphicsApiFilter()->setMajorVersion(2); + m_gl2Technique->graphicsApiFilter()->setMinorVersion(0); + m_gl2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile); + + m_es2Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGLES); + m_es2Technique->graphicsApiFilter()->setMajorVersion(2); + m_es2Technique->graphicsApiFilter()->setMinorVersion(0); + m_es2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile); + + m_noDepthMask->setEnabled(false); + m_blendState->setEnabled(false); + m_blendState->setSourceRgb(QBlendEquationArguments::SourceAlpha); + m_blendState->setDestinationRgb(QBlendEquationArguments::OneMinusSourceAlpha); + m_blendEquation->setEnabled(false); + m_blendEquation->setBlendFunction(QBlendEquation::Add); + + m_gl3RenderPass->setShaderProgram(m_gl3Shader); + m_gl2RenderPass->setShaderProgram(m_gl2es2Shader); + m_es2RenderPass->setShaderProgram(m_gl2es2Shader); + + m_gl3RenderPass->addRenderState(m_noDepthMask); + m_gl3RenderPass->addRenderState(m_blendState); + m_gl3RenderPass->addRenderState(m_blendEquation); + + m_gl2RenderPass->addRenderState(m_noDepthMask); + m_gl2RenderPass->addRenderState(m_blendState); + m_gl2RenderPass->addRenderState(m_blendEquation); + + m_es2RenderPass->addRenderState(m_noDepthMask); + m_es2RenderPass->addRenderState(m_blendState); + m_es2RenderPass->addRenderState(m_blendEquation); + + m_gl3Technique->addRenderPass(m_gl3RenderPass); + m_gl2Technique->addRenderPass(m_gl2RenderPass); + m_es2Technique->addRenderPass(m_es2RenderPass); + + m_filterKey->setParent(q); + m_filterKey->setName(QStringLiteral("renderingStyle")); + m_filterKey->setValue(QStringLiteral("forward")); + + m_gl3Technique->addFilterKey(m_filterKey); + m_gl2Technique->addFilterKey(m_filterKey); + m_es2Technique->addFilterKey(m_filterKey); + + m_effect->addTechnique(m_gl3Technique); + m_effect->addTechnique(m_gl2Technique); + m_effect->addTechnique(m_es2Technique); + + m_effect->addParameter(m_ambientParameter); + m_effect->addParameter(m_diffuseParameter); + m_effect->addParameter(m_specularParameter); + m_effect->addParameter(m_shininessParameter); + m_effect->addParameter(m_textureScaleParameter); + + q->setEffect(m_effect); +} + +void QDiffuseSpecularMaterialPrivate::handleAmbientChanged(const QVariant &var) +{ + Q_Q(QDiffuseSpecularMaterial); + emit q->ambientChanged(var.value<QColor>()); +} + +void QDiffuseSpecularMaterialPrivate::handleShininessChanged(const QVariant &var) +{ + Q_Q(QDiffuseSpecularMaterial); + emit q->shininessChanged(var.toFloat()); +} + +void QDiffuseSpecularMaterialPrivate::handleTextureScaleChanged(const QVariant &var) +{ + Q_Q(QDiffuseSpecularMaterial); + emit q->textureScaleChanged(var.toFloat()); +} + +/*! + \class Qt3DExtras::QDiffuseSpecularMaterial + \brief The QDiffuseSpecularMaterial class provides a default implementation + of the phong lighting effect. + \inmodule Qt3DExtras + \since 5.10 + \inherits Qt3DRender::QMaterial + + The phong lighting effect is based on the combination of 3 lighting + components ambient, diffuse and specular. The relative strengths of these + components are controlled by means of their reflectivity coefficients which + are modelled as RGB triplets: + + \list + \li Ambient is the color that is emitted by an object without any other + light source. + \li Diffuse is the color that is emitted for rought surface reflections + with the lights. + \li Specular is the color emitted for shiny surface reflections with the + lights. + \li The shininess of a surface is controlled by a float property. + \endlist + + This material uses an effect with a single render pass approach and + performs per fragment lighting. Techniques are provided for OpenGL 2, + OpenGL 3 or above as well as OpenGL ES 2. +*/ +/*! + \qmltype DiffuseSpecularMaterial + \brief The DiffuseSpecularMaterial class provides a default implementation + of the phong lighting effect. + \since 5.10 + \inqmlmodule Qt3D.Extras + \instantiates Qt3DExtras::QDiffuseSpecularMaterial + + The phong lighting effect is based on the combination of 3 lighting + components ambient, diffuse and specular. The relative strengths of these + components are controlled by means of their reflectivity coefficients which + are modelled as RGB triplets: + + \list + \li Ambient is the color that is emitted by an object without any other + light source. + \li Diffuse is the color that is emitted for rought surface reflections + with the lights. + \li Specular is the color emitted for shiny surface reflections with the + lights. + \li The shininess of a surface is controlled by a float property. + \endlist + + This material uses an effect with a single render pass approach and + performs per fragment lighting. Techniques are provided for OpenGL 2, + OpenGL 3 or above as well as OpenGL ES 2. + */ + +/*! + Constructs a new QDiffuseSpecularMaterial instance with parent object \a parent. +*/ +QDiffuseSpecularMaterial::QDiffuseSpecularMaterial(QNode *parent) + : QMaterial(*new QDiffuseSpecularMaterialPrivate, parent) +{ + Q_D(QDiffuseSpecularMaterial); + d->init(); +} + +/*! + Destroys the QDiffuseSpecularMaterial. +*/ +QDiffuseSpecularMaterial::~QDiffuseSpecularMaterial() +{ +} + +/*! + \property QDiffuseSpecularMaterial::ambient + + Holds the ambient color. +*/ +/*! + \qmlproperty color DiffuseSpecularMaterial::ambient + + Holds the ambient color. +*/ +QColor QDiffuseSpecularMaterial::ambient() const +{ + Q_D(const QDiffuseSpecularMaterial); + return d->m_ambientParameter->value().value<QColor>(); +} + +/*! + \property QDiffuseSpecularMaterial::diffuse + + Holds the diffuse color of the material. This can be either a plain color + value or a texture. +*/ +/*! + \qmlproperty var DiffuseSpecularMaterial::diffuse + + Holds the diffuse color of the material. This can be either a plain color + value or a texture. +*/ +QVariant QDiffuseSpecularMaterial::diffuse() const +{ + Q_D(const QDiffuseSpecularMaterial); + return d->m_diffuseParameter->value(); +} + +/*! + \property QDiffuseSpecularMaterial::specular + + Holds the specular color of the material. This can be either a plain color + value or a texture. +*/ +/*! + \qmlproperty var DiffuseSpecularMaterial::specular + + Holds the specular color of the material. This can be either a plain color + value or a texture. +*/ +QVariant QDiffuseSpecularMaterial::specular() const +{ + Q_D(const QDiffuseSpecularMaterial); + return d->m_specularParameter->value(); +} + +/*! + \property QDiffuseSpecularMaterial::shininess + + Holds the shininess exponent. +*/ +/*! + \qmlproperty real DiffuseSpecularMaterial::shininess + + Holds the shininess exponent. +*/ +float QDiffuseSpecularMaterial::shininess() const +{ + Q_D(const QDiffuseSpecularMaterial); + return d->m_shininessParameter->value().toFloat(); +} + +/*! + \property QDiffuseSpecularMaterial::normal + + Holds the current normal map texture of the material. This can only be a + texture, otherwise it is ignored. By default this map is not set. +*/ +/*! + \qmlproperty var DiffuseSpecularMaterial::normal + + Holds the current normal map texture of the material. This can only be a + texture, otherwise it is ignored. By default this map is not set. +*/ +QVariant QDiffuseSpecularMaterial::normal() const +{ + Q_D(const QDiffuseSpecularMaterial); + return d->m_normalTextureParameter->value(); +} + +/*! + \property QDiffuseSpecularMaterial::textureScale + + Holds the current texture scale. It is applied as a multiplier to texture + coordinates at render time. Defaults to 1.0. +*/ +/*! + \qmlproperty real DiffuseSpecularMaterial::textureScale + + Holds the current texture scale. It is applied as a multiplier to texture + coordinates at render time. Defaults to 1.0. +*/ +float QDiffuseSpecularMaterial::textureScale() const +{ + Q_D(const QDiffuseSpecularMaterial); + return d->m_textureScaleParameter->value().toFloat(); +} + +/*! + \property QDiffuseSpecularMaterial::alphaBlending + + Indicates if the alpha information coming from the diffuse property will + be taken into account during rendering. Defaults to false. +*/ +/*! + \qmlproperty bool DiffuseSpecularMaterial::alphaBlending + + Indicates if the alpha information coming from the diffuse property will + be taken into account during rendering. Defaults to false. +*/ +bool QDiffuseSpecularMaterial::isAlphaBlendingEnabled() const +{ + Q_D(const QDiffuseSpecularMaterial); + return d->m_noDepthMask->isEnabled(); +} + +void QDiffuseSpecularMaterial::setAmbient(const QColor &ambient) +{ + Q_D(QDiffuseSpecularMaterial); + d->m_ambientParameter->setValue(ambient); +} + +void QDiffuseSpecularMaterial::setDiffuse(const QVariant &diffuse) +{ + Q_D(QDiffuseSpecularMaterial); + d->m_diffuseParameter->setValue(diffuse); + d->m_diffuseTextureParameter->setValue(diffuse); + + auto layers = d->m_gl3ShaderBuilder->enabledLayers(); + if (diffuse.value<QAbstractTexture *>()) { + layers.removeAll(QStringLiteral("diffuse")); + layers.append(QStringLiteral("diffuseTexture")); + d->m_effect->addParameter(d->m_diffuseTextureParameter); + d->m_effect->removeParameter(d->m_diffuseParameter); + } else { + layers.removeAll(QStringLiteral("diffuseTexture")); + layers.append(QStringLiteral("diffuse")); + d->m_effect->removeParameter(d->m_diffuseTextureParameter); + d->m_effect->addParameter(d->m_diffuseParameter); + } + d->m_gl3ShaderBuilder->setEnabledLayers(layers); + d->m_gl2es2ShaderBuilder->setEnabledLayers(layers); +} + +void QDiffuseSpecularMaterial::setSpecular(const QVariant &specular) +{ + Q_D(QDiffuseSpecularMaterial); + d->m_specularParameter->setValue(specular); + d->m_specularTextureParameter->setValue(specular); + + auto layers = d->m_gl3ShaderBuilder->enabledLayers(); + if (specular.value<QAbstractTexture *>()) { + layers.removeAll(QStringLiteral("specular")); + layers.append(QStringLiteral("specularTexture")); + d->m_effect->addParameter(d->m_specularTextureParameter); + d->m_effect->removeParameter(d->m_specularParameter); + } else { + layers.removeAll(QStringLiteral("specularTexture")); + layers.append(QStringLiteral("specular")); + d->m_effect->removeParameter(d->m_specularTextureParameter); + d->m_effect->addParameter(d->m_specularParameter); + } + d->m_gl3ShaderBuilder->setEnabledLayers(layers); + d->m_gl2es2ShaderBuilder->setEnabledLayers(layers); +} + +void QDiffuseSpecularMaterial::setShininess(float shininess) +{ + Q_D(QDiffuseSpecularMaterial); + d->m_shininessParameter->setValue(shininess); +} + +void QDiffuseSpecularMaterial::setNormal(const QVariant &normal) +{ + Q_D(QDiffuseSpecularMaterial); + d->m_normalTextureParameter->setValue(normal); + + auto layers = d->m_gl3ShaderBuilder->enabledLayers(); + if (normal.value<QAbstractTexture *>()) { + layers.removeAll(QStringLiteral("normal")); + layers.append(QStringLiteral("normalTexture")); + d->m_effect->addParameter(d->m_normalTextureParameter); + } else { + layers.removeAll(QStringLiteral("normalTexture")); + layers.append(QStringLiteral("normal")); + d->m_effect->removeParameter(d->m_normalTextureParameter); + } + d->m_gl3ShaderBuilder->setEnabledLayers(layers); +} + +void QDiffuseSpecularMaterial::setTextureScale(float textureScale) +{ + Q_D(QDiffuseSpecularMaterial); + d->m_textureScaleParameter->setValue(textureScale); +} + +void QDiffuseSpecularMaterial::setAlphaBlendingEnabled(bool enabled) +{ + Q_D(QDiffuseSpecularMaterial); + d->m_noDepthMask->setEnabled(enabled); + d->m_blendState->setEnabled(enabled); + d->m_blendEquation->setEnabled(enabled); +} + +} // namespace Qt3DExtras + +QT_END_NAMESPACE diff --git a/src/extras/defaults/qdiffusespecularmaterial.h b/src/extras/defaults/qdiffusespecularmaterial.h new file mode 100644 index 000000000..5f21da093 --- /dev/null +++ b/src/extras/defaults/qdiffusespecularmaterial.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QDIFFUSESPECULARMATERIAL_H +#define QT3DEXTRAS_QDIFFUSESPECULARMATERIAL_H + +#include <Qt3DExtras/qt3dextras_global.h> +#include <Qt3DRender/qmaterial.h> +#include <QtGui/QColor> + +QT_BEGIN_NAMESPACE + +namespace Qt3DExtras { + +class QDiffuseSpecularMaterialPrivate; + +class QT3DEXTRASSHARED_EXPORT QDiffuseSpecularMaterial : public Qt3DRender::QMaterial +{ + Q_OBJECT + Q_PROPERTY(QColor ambient READ ambient WRITE setAmbient NOTIFY ambientChanged) + Q_PROPERTY(QVariant diffuse READ diffuse WRITE setDiffuse NOTIFY diffuseChanged) + Q_PROPERTY(QVariant specular READ specular WRITE setSpecular NOTIFY specularChanged) + Q_PROPERTY(float shininess READ shininess WRITE setShininess NOTIFY shininessChanged) + Q_PROPERTY(QVariant normal READ normal WRITE setNormal NOTIFY normalChanged) + Q_PROPERTY(float textureScale READ textureScale WRITE setTextureScale NOTIFY textureScaleChanged) + Q_PROPERTY(bool alphaBlending READ isAlphaBlendingEnabled WRITE setAlphaBlendingEnabled NOTIFY alphaBlendingEnabledChanged) + +public: + explicit QDiffuseSpecularMaterial(Qt3DCore::QNode *parent = nullptr); + ~QDiffuseSpecularMaterial(); + + QColor ambient() const; + QVariant diffuse() const; + QVariant specular() const; + float shininess() const; + QVariant normal() const; + float textureScale() const; + bool isAlphaBlendingEnabled() const; + +public Q_SLOTS: + void setAmbient(const QColor &ambient); + void setDiffuse(const QVariant &diffuse); + void setSpecular(const QVariant &specular); + void setShininess(float shininess); + void setNormal(const QVariant &normal); + void setTextureScale(float textureScale); + void setAlphaBlendingEnabled(bool enabled); + +Q_SIGNALS: + void ambientChanged(const QColor &ambient); + void diffuseChanged(const QVariant &diffuse); + void specularChanged(const QVariant &specular); + void shininessChanged(float shininess); + void normalChanged(const QVariant &normal); + void textureScaleChanged(float textureScale); + void alphaBlendingEnabledChanged(bool enabled); + +private: + Q_DECLARE_PRIVATE(QDiffuseSpecularMaterial) +}; + +} // namespace Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QDIFFUSESPECULARMATERIAL_H diff --git a/src/extras/defaults/qdiffusespecularmaterial_p.h b/src/extras/defaults/qdiffusespecularmaterial_p.h new file mode 100644 index 000000000..2b0b2184f --- /dev/null +++ b/src/extras/defaults/qdiffusespecularmaterial_p.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DEXTRAS_QDIFFUSESPECULARMATERIAL_P_H +#define QT3DEXTRAS_QDIFFUSESPECULARMATERIAL_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/private/qmaterial_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QFilterKey; +class QEffect; +class QTechnique; +class QParameter; +class QShaderProgram; +class QShaderProgramBuilder; +class QRenderPass; +class QNoDepthMask; +class QBlendEquationArguments; +class QBlendEquation; + +} // namespace Qt3DRender + +namespace Qt3DExtras { + +class QDiffuseSpecularMaterial; + +class QDiffuseSpecularMaterialPrivate : public Qt3DRender::QMaterialPrivate +{ +public: + QDiffuseSpecularMaterialPrivate(); + + void init(); + + void handleAmbientChanged(const QVariant &var); + void handleShininessChanged(const QVariant &var); + void handleTextureScaleChanged(const QVariant &var); + + Qt3DRender::QEffect *m_effect; + Qt3DRender::QParameter *m_ambientParameter; + Qt3DRender::QParameter *m_diffuseParameter; + Qt3DRender::QParameter *m_specularParameter; + Qt3DRender::QParameter *m_diffuseTextureParameter; + Qt3DRender::QParameter *m_specularTextureParameter; + Qt3DRender::QParameter *m_shininessParameter; + Qt3DRender::QParameter *m_normalTextureParameter; + Qt3DRender::QParameter *m_textureScaleParameter; + Qt3DRender::QTechnique *m_gl3Technique; + Qt3DRender::QTechnique *m_gl2Technique; + Qt3DRender::QTechnique *m_es2Technique; + Qt3DRender::QRenderPass *m_gl3RenderPass; + Qt3DRender::QRenderPass *m_gl2RenderPass; + Qt3DRender::QRenderPass *m_es2RenderPass; + Qt3DRender::QShaderProgram *m_gl3Shader; + Qt3DRender::QShaderProgramBuilder *m_gl3ShaderBuilder; + Qt3DRender::QShaderProgram *m_gl2es2Shader; + Qt3DRender::QShaderProgramBuilder *m_gl2es2ShaderBuilder; + Qt3DRender::QNoDepthMask *m_noDepthMask; + Qt3DRender::QBlendEquationArguments *m_blendState; + Qt3DRender::QBlendEquation *m_blendEquation; + Qt3DRender::QFilterKey *m_filterKey; + + Q_DECLARE_PUBLIC(QDiffuseSpecularMaterial) +}; + +} // Qt3DExtras + +QT_END_NAMESPACE + +#endif // QT3DEXTRAS_QDIFFUSESPECULARMATERIAL_P_H + diff --git a/src/extras/defaults/qnormaldiffusemapalphamaterial.cpp b/src/extras/defaults/qnormaldiffusemapalphamaterial.cpp index c276c9717..9b2a64520 100644 --- a/src/extras/defaults/qnormaldiffusemapalphamaterial.cpp +++ b/src/extras/defaults/qnormaldiffusemapalphamaterial.cpp @@ -165,6 +165,9 @@ void QNormalDiffuseMapAlphaMaterialPrivate::init() \since 5.7 \inherits Qt3DExtras::QNormalDiffuseMapMaterial + \deprecated + \see Qt3DExtras::QDiffuseSpecularMaterial + The specular lighting effect is based on the combination of 3 lighting components ambient, diffuse and specular. The relative strengths of these components are controlled by means of their reflectivity coefficients which are modelled as RGB triplets: diff --git a/src/extras/defaults/qnormaldiffusemapmaterial.cpp b/src/extras/defaults/qnormaldiffusemapmaterial.cpp index 687e59751..beed4085e 100644 --- a/src/extras/defaults/qnormaldiffusemapmaterial.cpp +++ b/src/extras/defaults/qnormaldiffusemapmaterial.cpp @@ -218,6 +218,9 @@ void QNormalDiffuseMapMaterialPrivate::handleTextureScaleChanged(const QVariant \since 5.7 \inherits Qt3DRender::QMaterial + \deprecated + \see Qt3DExtras::QDiffuseSpecularMaterial + The specular lighting effect is based on the combination of 3 lighting components ambient, diffuse and specular. The relative strengths of these components are controlled by means of their reflectivity coefficients which are modelled as RGB triplets: diff --git a/src/extras/defaults/qnormaldiffusespecularmapmaterial.cpp b/src/extras/defaults/qnormaldiffusespecularmapmaterial.cpp index 7665c07a7..028fd14e7 100644 --- a/src/extras/defaults/qnormaldiffusespecularmapmaterial.cpp +++ b/src/extras/defaults/qnormaldiffusespecularmapmaterial.cpp @@ -226,6 +226,9 @@ void QNormalDiffuseSpecularMapMaterialPrivate::handleTextureScaleChanged(const Q \since 5.7 \inherits Qt3DRender::QMaterial + \deprecated + \see Qt3DExtras::QDiffuseSpecularMaterial + The specular lighting effect is based on the combination of 3 lighting components ambient, diffuse and specular. The relative strengths of these components are controlled by means of their reflectivity coefficients which are modelled as RGB triplets: diff --git a/src/extras/defaults/qphongalphamaterial.cpp b/src/extras/defaults/qphongalphamaterial.cpp index fb0871ee4..24cff94e9 100644 --- a/src/extras/defaults/qphongalphamaterial.cpp +++ b/src/extras/defaults/qphongalphamaterial.cpp @@ -209,6 +209,9 @@ void QPhongAlphaMaterialPrivate::handleShininessChanged(const QVariant &var) \since 5.7 \inherits Qt3DRender::QMaterial + \deprecated + \see Qt3DExtras::QDiffuseSpecularMaterial + The phong lighting effect is based on the combination of 3 lighting components ambient, diffuse and specular. The relative strengths of these components are controlled by means of their reflectivity coefficients which are modelled as RGB triplets: diff --git a/src/extras/defaults/qphongmaterial.cpp b/src/extras/defaults/qphongmaterial.cpp index c76e3a6ef..17d837568 100644 --- a/src/extras/defaults/qphongmaterial.cpp +++ b/src/extras/defaults/qphongmaterial.cpp @@ -184,6 +184,9 @@ void QPhongMaterialPrivate::handleShininessChanged(const QVariant &var) \since 5.7 \inherits Qt3DRender::QMaterial + \deprecated + \see Qt3DExtras::QDiffuseSpecularMaterial + The phong lighting effect is based on the combination of 3 lighting components ambient, diffuse and specular. The relative strengths of these components are controlled by means of their reflectivity coefficients which are modelled as RGB triplets: 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/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp index 61d27444a..e893696ec 100644 --- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp +++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp @@ -53,6 +53,7 @@ #include <Qt3DExtras/qforwardrenderer.h> #include <Qt3DExtras/qgoochmaterial.h> #include <Qt3DExtras/qmetalroughmaterial.h> +#include <Qt3DExtras/qdiffusespecularmaterial.h> #include <Qt3DExtras/qmorphphongmaterial.h> #include <Qt3DExtras/qnormaldiffusemapalphamaterial.h> #include <Qt3DExtras/qnormaldiffusemapmaterial.h> @@ -108,6 +109,7 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri) qmlRegisterType<Qt3DExtras::QGoochMaterial>(uri, 2, 0, "GoochMaterial"); qmlRegisterType<Qt3DExtras::QTextureMaterial>(uri, 2, 0, "TextureMaterial"); qmlRegisterRevision<Qt3DExtras::QTextureMaterial, 10>(uri, 2, 10); + qmlRegisterType<Qt3DExtras::QDiffuseSpecularMaterial>(uri, 2, 10, "DiffuseSpecularMaterial"); qmlRegisterType<Qt3DExtras::QMetalRoughMaterial>(uri, 2, 9, "MetalRoughMaterial"); qmlRegisterRevision<Qt3DExtras::QMetalRoughMaterial, 10>(uri, 2, 10); qmlRegisterType<Qt3DExtras::QTexturedMetalRoughMaterial>(uri, 2, 9, "TexturedMetalRoughMaterial"); 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/attachmentpack.cpp b/src/render/backend/attachmentpack.cpp index 6dee7587b..9a08fdde4 100644 --- a/src/render/backend/attachmentpack.cpp +++ b/src/render/backend/attachmentpack.cpp @@ -67,11 +67,13 @@ AttachmentPack::AttachmentPack(const RenderTargetSelector *selector, const Rende // If nothing is specified, use all the attachments as draw buffers if (selectedAttachmentPoints.isEmpty()) { + m_drawBuffers.reserve(m_attachments.size()); for (const Attachment &attachment : qAsConst(m_attachments)) // only consider Color Attachments if (attachment.m_point <= QRenderTargetOutput::Color15) m_drawBuffers.push_back((int) attachment.m_point); } else { + m_drawBuffers.reserve(selectedAttachmentPoints.size()); for (QRenderTargetOutput::AttachmentPoint drawBuffer : selectedAttachmentPoints) if (drawBuffer <= QRenderTargetOutput::Color15) m_drawBuffers.push_back((int) drawBuffer); 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..7830faaa9 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -1484,25 +1484,28 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() m_updateLevelOfDetailJob->setFrameGraphRoot(frameGraphRoot()); + BackendNodeDirtySet changesToUnset = dirtyBits(); + // Add jobs - if (dirtyBits() & AbstractRenderer::EntityEnabledDirty) { + const bool entitiesEnabledDirty = changesToUnset & AbstractRenderer::EntityEnabledDirty; + if (entitiesEnabledDirty) { renderBinJobs.push_back(m_updateTreeEnabledJob); m_calculateBoundingVolumeJob->addDependency(m_updateTreeEnabledJob); } - if (dirtyBits() & AbstractRenderer::TransformDirty) { + if (changesToUnset & AbstractRenderer::TransformDirty) { renderBinJobs.push_back(m_worldTransformJob); renderBinJobs.push_back(m_updateWorldBoundingVolumeJob); renderBinJobs.push_back(m_updateShaderDataTransformJob); } - if (dirtyBits() & AbstractRenderer::GeometryDirty) { + if (changesToUnset & AbstractRenderer::GeometryDirty) { renderBinJobs.push_back(m_calculateBoundingVolumeJob); renderBinJobs.push_back(m_updateMeshTriangleListJob); } - if (dirtyBits() & AbstractRenderer::GeometryDirty || - dirtyBits() & AbstractRenderer::TransformDirty) { + if (changesToUnset & AbstractRenderer::GeometryDirty || + changesToUnset & AbstractRenderer::TransformDirty) { renderBinJobs.push_back(m_expandBoundingVolumeJob); } @@ -1518,17 +1521,24 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() // Jobs to prepare GL Resource upload renderBinJobs.push_back(m_vaoGathererJob); - if (dirtyBits() & AbstractRenderer::BuffersDirty) + if (changesToUnset & AbstractRenderer::BuffersDirty) renderBinJobs.push_back(m_bufferGathererJob); - if (dirtyBits() & AbstractRenderer::ShadersDirty) + if (changesToUnset & AbstractRenderer::ShadersDirty) renderBinJobs.push_back(m_shaderGathererJob); - if (dirtyBits() & AbstractRenderer::TexturesDirty) { + if (changesToUnset & AbstractRenderer::TexturesDirty) { renderBinJobs.push_back(m_syncTextureLoadingJob); renderBinJobs.push_back(m_textureGathererJob); } + + // Layer cache is dependent on layers, layer filters and the enabled flag + // on entities + const bool layersDirty = changesToUnset & AbstractRenderer::LayersDirty; + const bool layersCacheNeedsToBeRebuilt = layersDirty || entitiesEnabledDirty; + bool layersCacheRebuilt = false; + QMutexLocker lock(m_renderQueue->mutex()); if (m_renderQueue->wasReset()) { // Have we rendered yet? (Scene3D case) // Traverse the current framegraph. For each leaf node create a @@ -1539,18 +1549,33 @@ 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 QList<FrameGraphNode *> keys = m_cache.leafNodeCache.keys(); + for (FrameGraphNode *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); + builder.setLayerCacheNeedsToBeRebuilt(layersCacheNeedsToBeRebuilt); + builder.prepareJobs(); renderBinJobs.append(builder.buildJobHierachy()); } + layersCacheRebuilt = true; // Set target number of RenderViews m_renderQueue->setTargetRenderViewCount(fgBranchCount); } + // Only reset LayersDirty flag once we have really rebuilt the caches + if (layersDirty && !layersCacheRebuilt) + changesToUnset.setFlag(AbstractRenderer::LayersDirty, false); + if (entitiesEnabledDirty && !layersCacheRebuilt) + changesToUnset.setFlag(AbstractRenderer::EntityEnabledDirty, false); + // Clear dirty bits - BackendNodeDirtySet changesToUnset = dirtyBits(); // TO DO: When secondary GL thread is integrated, the following line can be removed changesToUnset.setFlag(AbstractRenderer::ShadersDirty, false); diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h index 3cf99ec81..28e8711a8 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,8 @@ public: ViewSubmissionResultData submitRenderViews(const QVector<Render::RenderView *> &renderViews); + RendererCache *cache() { return &m_cache; } + #ifdef QT3D_RENDER_UNIT_TESTS public: #else @@ -368,6 +371,7 @@ private: #endif QMetaObject::Connection m_contextConnection; + RendererCache m_cache; }; } // namespace Render diff --git a/src/render/backend/renderercache_p.h b/src/render/backend/renderercache_p.h new file mode 100644 index 000000000..f14b965ee --- /dev/null +++ b/src/render/backend/renderercache_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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 +{ + struct LeafNodeData + { + QVector<Entity *> filterEntitiesByLayer; + }; + + QHash<FrameGraphNode *, LeafNodeData> leafNodeCache; + + QMutex *mutex() { return &m_mutex; } + +private: + QMutex m_mutex; +}; + +} // 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..769eee29f 100644 --- a/src/render/backend/renderviewbuilder.cpp +++ b/src/render/backend/renderviewbuilder.cpp @@ -139,7 +139,8 @@ public: RenderView *rv = m_renderViewJob->renderView(); // Layer filtering - m_filterEntityByLayerJob->setLayerFilters(rv->layerFilters()); + if (!m_filterEntityByLayerJob.isNull()) + m_filterEntityByLayerJob->setLayerFilters(rv->layerFilters()); // Proximity filtering m_filterProximityJob->setProximityFilterIds(rv->proximityFilterIds()); @@ -172,22 +173,24 @@ class SyncRenderCommandBuilding public: explicit SyncRenderCommandBuilding(const RenderViewInitializerJobPtr &renderViewJob, const FrustumCullingJobPtr &frustumCullingJob, - const FilterLayerEntityJobPtr &filterEntityByLayerJob, const FilterProximityDistanceJobPtr &filterProximityJob, const LightGathererPtr &lightGathererJob, 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) , m_filterProximityJob(filterProximityJob) , m_lightGathererJob(lightGathererJob) , m_renderableEntityFilterJob(renderableEntityFilterJob) , m_computableEntityFilterJob(computableEntityFilterJob) , m_materialGathererJobs(materialGathererJobs) , m_renderViewBuilderJobs(renderViewBuilderJobs) + , m_renderer(renderer) + , m_leafNode(leafNode) {} void operator()() @@ -211,8 +214,10 @@ public: // Filter out entities that weren't selected by the layer filters std::sort(renderableEntities.begin(), renderableEntities.end()); + QMutexLocker lock(m_renderer->cache()->mutex()); + const QVector<Entity *> filteredEntities = m_renderer->cache()->leafNodeCache.value(m_leafNode).filterEntitiesByLayer; + lock.unlock(); // 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); // Set the light sources, with layer filters applied. @@ -254,13 +259,14 @@ public: private: RenderViewInitializerJobPtr m_renderViewJob; FrustumCullingJobPtr m_frustumCullingJob; - FilterLayerEntityJobPtr m_filterEntityByLayerJob; FilterProximityDistanceJobPtr m_filterProximityJob; LightGathererPtr m_lightGathererJob; RenderableEntityFilterPtr m_renderableEntityFilterJob; ComputableEntityFilterPtr m_computableEntityFilterJob; QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs; QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs; + Renderer *m_renderer; + FrameGraphNode *m_leafNode; }; class SetClearDrawBufferIndex @@ -284,82 +290,51 @@ private: RenderViewInitializerJobPtr m_renderViewJob; }; +class SyncFilterEntityByLayer +{ +public: + explicit SyncFilterEntityByLayer(const FilterLayerEntityJobPtr &filterEntityByLayerJob, + Renderer *renderer, + FrameGraphNode *leafNode) + : m_filterEntityByLayerJob(filterEntityByLayerJob) + , m_renderer(renderer) + , m_leafNode(leafNode) + { + } + + void operator()() + { + QMutexLocker lock(m_renderer->cache()->mutex()); + // Save the filtered by layer subset into the cache + const QVector<Entity *> filteredEntities = m_filterEntityByLayerJob->filteredEntities(); + RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode]; + dataCacheForLeaf.filterEntitiesByLayer = filteredEntities; + } + +private: + FilterLayerEntityJobPtr m_filterEntityByLayerJob; + Renderer *m_renderer; + FrameGraphNode *m_leafNode; +}; + } // anonymous RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int renderViewIndex, Renderer *renderer) - : m_renderViewIndex(renderViewIndex) + : m_leafNode(leafNode) + , m_renderViewIndex(renderViewIndex) , m_renderer(renderer) + , m_layerCacheNeedsToBeRebuilt(false) , m_renderViewJob(RenderViewInitializerJobPtr::create()) - , m_filterEntityByLayerJob(Render::FilterLayerEntityJobPtr::create()) + , m_filterEntityByLayerJob() , m_lightGathererJob(Render::LightGathererPtr::create()) , m_renderableEntityFilterJob(RenderableEntityFilterPtr::create()) , m_computableEntityFilterJob(ComputableEntityFilterPtr::create()) , m_frustumCullingJob(Render::FrustumCullingJobPtr::create()) , m_syncFrustumCullingJob(SynchronizerJobPtr::create(SyncFrustumCulling(m_renderViewJob, m_frustumCullingJob), JobTypes::SyncFrustumCulling)) , m_setClearDrawBufferIndexJob(SynchronizerJobPtr::create(SetClearDrawBufferIndex(m_renderViewJob), JobTypes::ClearBufferDrawIndex)) + , m_syncFilterEntityByLayerJob() , m_filterProximityJob(Render::FilterProximityDistanceJobPtr::create()) { - // Init what we can here - EntityManager *entityManager = m_renderer->nodeManagers()->renderNodesManager(); - m_filterEntityByLayerJob->setManager(m_renderer->nodeManagers()); - m_filterProximityJob->setManager(m_renderer->nodeManagers()); - m_renderableEntityFilterJob->setManager(entityManager); - m_computableEntityFilterJob->setManager(entityManager); - m_frustumCullingJob->setRoot(m_renderer->sceneRoot()); - m_lightGathererJob->setManager(entityManager); - m_renderViewJob->setRenderer(m_renderer); - m_renderViewJob->setFrameGraphLeafNode(leafNode); - m_renderViewJob->setSubmitOrderIndex(m_renderViewIndex); - - // RenderCommand building is the most consuming task -> split it - // Estimate the number of jobs to create based on the number of entities - m_renderViewBuilderJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount); - for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) { - auto renderViewCommandBuilder = Render::RenderViewBuilderJobPtr::create(); - renderViewCommandBuilder->setIndex(m_renderViewIndex); - renderViewCommandBuilder->setRenderer(m_renderer); - m_renderViewBuilderJobs.push_back(renderViewCommandBuilder); - } - - // Since Material gathering is an heavy task, we split it - const QVector<HMaterial> materialHandles = m_renderer->nodeManagers()->materialManager()->activeHandles(); - const int elementsPerJob = materialHandles.size() / RenderViewBuilder::m_optimalParallelJobCount; - const int lastRemaingElements = materialHandles.size() % RenderViewBuilder::m_optimalParallelJobCount; - m_materialGathererJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount); - for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) { - auto materialGatherer = Render::MaterialParameterGathererJobPtr::create(); - materialGatherer->setNodeManagers(m_renderer->nodeManagers()); - materialGatherer->setRenderer(m_renderer); - if (i == RenderViewBuilder::m_optimalParallelJobCount - 1) - materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob + lastRemaingElements)); - else - materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob)); - m_materialGathererJobs.push_back(materialGatherer); - } - - m_syncRenderViewInitializationJob = SynchronizerJobPtr::create(SyncRenderViewInitialization(m_renderViewJob, - m_frustumCullingJob, - m_filterEntityByLayerJob, - m_filterProximityJob, - m_materialGathererJobs, - m_renderViewBuilderJobs), - JobTypes::SyncRenderViewInitialization); - - m_syncRenderCommandBuildingJob = SynchronizerJobPtr::create(SyncRenderCommandBuilding(m_renderViewJob, - m_frustumCullingJob, - m_filterEntityByLayerJob, - m_filterProximityJob, - m_lightGathererJob, - m_renderableEntityFilterJob, - m_computableEntityFilterJob, - m_materialGathererJobs, - m_renderViewBuilderJobs), - JobTypes::SyncRenderViewCommandBuilding); - - m_syncRenderViewCommandBuildersJob = SynchronizerJobPtr::create(SyncRenderViewCommandBuilders(m_renderViewJob, - m_renderViewBuilderJobs, - m_renderer), - JobTypes::SyncRenderViewCommandBuilder); } RenderViewInitializerJobPtr RenderViewBuilder::renderViewJob() const @@ -427,11 +402,91 @@ SynchronizerJobPtr RenderViewBuilder::setClearDrawBufferIndexJob() const return m_setClearDrawBufferIndexJob; } +SynchronizerJobPtr RenderViewBuilder::syncFilterEntityByLayerJob() const +{ + return m_syncFilterEntityByLayerJob; +} + FilterProximityDistanceJobPtr RenderViewBuilder::filterProximityJob() const { return m_filterProximityJob; } +void RenderViewBuilder::prepareJobs() +{ + // Init what we can here + EntityManager *entityManager = m_renderer->nodeManagers()->renderNodesManager(); + m_filterProximityJob->setManager(m_renderer->nodeManagers()); + m_renderableEntityFilterJob->setManager(entityManager); + m_computableEntityFilterJob->setManager(entityManager); + m_frustumCullingJob->setRoot(m_renderer->sceneRoot()); + m_lightGathererJob->setManager(entityManager); + m_renderViewJob->setRenderer(m_renderer); + m_renderViewJob->setFrameGraphLeafNode(m_leafNode); + m_renderViewJob->setSubmitOrderIndex(m_renderViewIndex); + + // RenderCommand building is the most consuming task -> split it + // Estimate the number of jobs to create based on the number of entities + m_renderViewBuilderJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount); + for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) { + auto renderViewCommandBuilder = Render::RenderViewBuilderJobPtr::create(); + renderViewCommandBuilder->setIndex(m_renderViewIndex); + renderViewCommandBuilder->setRenderer(m_renderer); + m_renderViewBuilderJobs.push_back(renderViewCommandBuilder); + } + + // Since Material gathering is an heavy task, we split it + const QVector<HMaterial> materialHandles = m_renderer->nodeManagers()->materialManager()->activeHandles(); + const int elementsPerJob = materialHandles.size() / RenderViewBuilder::m_optimalParallelJobCount; + const int lastRemaingElements = materialHandles.size() % RenderViewBuilder::m_optimalParallelJobCount; + m_materialGathererJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount); + for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) { + auto materialGatherer = Render::MaterialParameterGathererJobPtr::create(); + materialGatherer->setNodeManagers(m_renderer->nodeManagers()); + materialGatherer->setRenderer(m_renderer); + if (i == RenderViewBuilder::m_optimalParallelJobCount - 1) + materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob + lastRemaingElements)); + else + materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob)); + m_materialGathererJobs.push_back(materialGatherer); + } + + if (m_layerCacheNeedsToBeRebuilt) { + m_filterEntityByLayerJob = Render::FilterLayerEntityJobPtr::create(); + m_filterEntityByLayerJob->setManager(m_renderer->nodeManagers()); + m_syncFilterEntityByLayerJob = SynchronizerJobPtr::create(SyncFilterEntityByLayer(m_filterEntityByLayerJob, + m_renderer, + m_leafNode), + JobTypes::SyncFilterEntityByLayer); + } + + m_syncRenderCommandBuildingJob = SynchronizerJobPtr::create(SyncRenderCommandBuilding(m_renderViewJob, + m_frustumCullingJob, + m_filterProximityJob, + m_lightGathererJob, + m_renderableEntityFilterJob, + m_computableEntityFilterJob, + m_materialGathererJobs, + m_renderViewBuilderJobs, + m_renderer, + m_leafNode), + JobTypes::SyncRenderViewCommandBuilding); + + m_syncRenderViewCommandBuildersJob = SynchronizerJobPtr::create(SyncRenderViewCommandBuilders(m_renderViewJob, + m_renderViewBuilderJobs, + m_renderer), + JobTypes::SyncRenderViewCommandBuilder); + + m_syncRenderViewInitializationJob = SynchronizerJobPtr::create(SyncRenderViewInitialization(m_renderViewJob, + m_frustumCullingJob, + m_filterEntityByLayerJob, + m_filterProximityJob, + m_materialGathererJobs, + m_renderViewBuilderJobs), + JobTypes::SyncRenderViewInitialization); + +} + QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const { QVector<Qt3DCore::QAspectJobPtr> jobs; @@ -455,9 +510,6 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const m_syncRenderViewInitializationJob->addDependency(m_renderViewJob); - m_filterEntityByLayerJob->addDependency(m_syncRenderViewInitializationJob); - m_filterEntityByLayerJob->addDependency(m_renderer->updateTreeEnabledJob()); - m_filterProximityJob->addDependency(m_renderer->expandBoundingVolumeJob()); m_filterProximityJob->addDependency(m_syncRenderViewInitializationJob); @@ -469,7 +521,6 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const } m_syncRenderCommandBuildingJob->addDependency(m_renderableEntityFilterJob); m_syncRenderCommandBuildingJob->addDependency(m_computableEntityFilterJob); - m_syncRenderCommandBuildingJob->addDependency(m_filterEntityByLayerJob); m_syncRenderCommandBuildingJob->addDependency(m_filterProximityJob); m_syncRenderCommandBuildingJob->addDependency(m_lightGathererJob); m_syncRenderCommandBuildingJob->addDependency(m_frustumCullingJob); @@ -492,8 +543,17 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const jobs.push_back(m_syncRenderViewInitializationJob); // Step 2 + if (m_layerCacheNeedsToBeRebuilt) { + m_filterEntityByLayerJob->addDependency(m_syncRenderViewInitializationJob); + m_filterEntityByLayerJob->addDependency(m_renderer->updateTreeEnabledJob()); + + m_syncFilterEntityByLayerJob->addDependency(m_filterEntityByLayerJob); + m_syncRenderCommandBuildingJob->addDependency(m_syncFilterEntityByLayerJob); + + jobs.push_back(m_filterEntityByLayerJob); // Step 3 + jobs.push_back(m_syncFilterEntityByLayerJob); // Step 4 + } jobs.push_back(m_syncFrustumCullingJob); // Step 3 - jobs.push_back(m_filterEntityByLayerJob); // Step 3 jobs.push_back(m_filterProximityJob); // Step 3 jobs.push_back(m_setClearDrawBufferIndexJob); // Step 3 @@ -501,12 +561,12 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const jobs.push_back(materialGatherer); jobs.push_back(m_frustumCullingJob); // Step 4 - jobs.push_back(m_syncRenderCommandBuildingJob); // Step 4 + jobs.push_back(m_syncRenderCommandBuildingJob); // Step 5 - for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) // Step 5 + for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) // Step 6 jobs.push_back(renderViewCommandBuilder); - jobs.push_back(m_syncRenderViewCommandBuildersJob); // Step 6 + jobs.push_back(m_syncRenderViewCommandBuildersJob); // Step 7 return jobs; } @@ -521,6 +581,16 @@ int RenderViewBuilder::renderViewIndex() const return m_renderViewIndex; } +void RenderViewBuilder::setLayerCacheNeedsToBeRebuilt(bool needsToBeRebuilt) +{ + m_layerCacheNeedsToBeRebuilt = needsToBeRebuilt; +} + +bool RenderViewBuilder::layerCacheNeedsToBeRebuilt() const +{ + return m_layerCacheNeedsToBeRebuilt; +} + int RenderViewBuilder::optimalJobCount() { return RenderViewBuilder::m_optimalParallelJobCount; diff --git a/src/render/backend/renderviewbuilder_p.h b/src/render/backend/renderviewbuilder_p.h index 0aa2e035a..a1fb4eb8b 100644 --- a/src/render/backend/renderviewbuilder_p.h +++ b/src/render/backend/renderviewbuilder_p.h @@ -94,19 +94,26 @@ public: SynchronizerJobPtr syncRenderCommandBuildingJob() const; SynchronizerJobPtr syncRenderViewCommandBuildersJob() const; SynchronizerJobPtr setClearDrawBufferIndexJob() const; + SynchronizerJobPtr syncFilterEntityByLayerJob() const; FilterProximityDistanceJobPtr filterProximityJob() const; + void prepareJobs(); QVector<Qt3DCore::QAspectJobPtr> buildJobHierachy() const; Renderer *renderer() const; int renderViewIndex() const; + void setLayerCacheNeedsToBeRebuilt(bool needsToBeRebuilt); + bool layerCacheNeedsToBeRebuilt() const; + static int optimalJobCount(); static void removeEntitiesNotInSubset(QVector<Entity *> &entities, QVector<Entity *> subset); private: + Render::FrameGraphNode *m_leafNode; const int m_renderViewIndex; Renderer *m_renderer; + bool m_layerCacheNeedsToBeRebuilt; RenderViewInitializerJobPtr m_renderViewJob; FilterLayerEntityJobPtr m_filterEntityByLayerJob; @@ -122,6 +129,7 @@ private: SynchronizerJobPtr m_syncRenderCommandBuildingJob; SynchronizerJobPtr m_syncRenderViewCommandBuildersJob; SynchronizerJobPtr m_setClearDrawBufferIndexJob; + SynchronizerJobPtr m_syncFilterEntityByLayerJob; FilterProximityDistanceJobPtr m_filterProximityJob; static const int m_optimalParallelJobCount; 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/src/render/geometry/buffermanager.cpp b/src/render/geometry/buffermanager.cpp index 5bd44f80f..25f95189e 100644 --- a/src/render/geometry/buffermanager.cpp +++ b/src/render/geometry/buffermanager.cpp @@ -60,9 +60,7 @@ void BufferManager::addDirtyBuffer(Qt3DCore::QNodeId bufferId) QVector<Qt3DCore::QNodeId> BufferManager::dirtyBuffers() { - QVector<Qt3DCore::QNodeId> vector(m_dirtyBuffers); - m_dirtyBuffers.clear(); - return vector; + return qMove(m_dirtyBuffers); } // Called in QAspectThread::syncChanges diff --git a/src/render/graphicshelpers/graphicshelperes2.cpp b/src/render/graphicshelpers/graphicshelperes2.cpp index a22d8752a..676363b73 100644 --- a/src/render/graphicshelpers/graphicshelperes2.cpp +++ b/src/render/graphicshelpers/graphicshelperes2.cpp @@ -209,6 +209,9 @@ QVector<ShaderUniform> GraphicsHelperES2::programUniformsAndLocations(GLuint pro uniformName[sizeof(uniformName) - 1] = '\0'; uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName); uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength); + // Work around for uniform array names that aren't returned with [0] by some drivers + if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]"))) + uniform.m_name.append(QLatin1String("[0]")); uniforms.append(uniform); } return uniforms; diff --git a/src/render/graphicshelpers/graphicshelpergl2.cpp b/src/render/graphicshelpers/graphicshelpergl2.cpp index 60d3b49ba..6da8a9b6f 100644 --- a/src/render/graphicshelpers/graphicshelpergl2.cpp +++ b/src/render/graphicshelpers/graphicshelpergl2.cpp @@ -178,6 +178,9 @@ QVector<ShaderUniform> GraphicsHelperGL2::programUniformsAndLocations(GLuint pro uniformName[sizeof(uniformName) - 1] = '\0'; uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName); uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength); + // Work around for uniform array names that aren't returned with [0] by some drivers + if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]"))) + uniform.m_name.append(QLatin1String("[0]")); uniform.m_rawByteSize = uniformByteSize(uniform); uniforms.append(uniform); } diff --git a/src/render/graphicshelpers/graphicshelpergl3_2.cpp b/src/render/graphicshelpers/graphicshelpergl3_2.cpp index 289ae18be..a35c4e37f 100644 --- a/src/render/graphicshelpers/graphicshelpergl3_2.cpp +++ b/src/render/graphicshelpers/graphicshelpergl3_2.cpp @@ -207,6 +207,9 @@ QVector<ShaderUniform> GraphicsHelperGL3_2::programUniformsAndLocations(GLuint p uniformName[sizeof(uniformName) - 1] = '\0'; uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName); uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength); + // Work around for uniform array names that aren't returned with [0] by some drivers + if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]"))) + uniform.m_name.append(QLatin1String("[0]")); m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &uniform.m_blockIndex); m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_OFFSET, &uniform.m_offset); m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_ARRAY_STRIDE, &uniform.m_arrayStride); diff --git a/src/render/graphicshelpers/graphicshelpergl3_3.cpp b/src/render/graphicshelpers/graphicshelpergl3_3.cpp index 40f8076bb..40c2bafeb 100644 --- a/src/render/graphicshelpers/graphicshelpergl3_3.cpp +++ b/src/render/graphicshelpers/graphicshelpergl3_3.cpp @@ -206,6 +206,9 @@ QVector<ShaderUniform> GraphicsHelperGL3_3::programUniformsAndLocations(GLuint p uniformName[sizeof(uniformName) - 1] = '\0'; uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName); uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength); + // Work around for uniform array names that aren't returned with [0] by some drivers + if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]"))) + uniform.m_name.append(QLatin1String("[0]")); m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &uniform.m_blockIndex); m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_OFFSET, &uniform.m_offset); m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_ARRAY_STRIDE, &uniform.m_arrayStride); diff --git a/src/render/graphicshelpers/graphicshelpergl4.cpp b/src/render/graphicshelpers/graphicshelpergl4.cpp index 284970873..ce1b8ac2b 100644 --- a/src/render/graphicshelpers/graphicshelpergl4.cpp +++ b/src/render/graphicshelpers/graphicshelpergl4.cpp @@ -249,6 +249,9 @@ QVector<ShaderUniform> GraphicsHelperGL4::programUniformsAndLocations(GLuint pro uniformName[sizeof(uniformName) - 1] = '\0'; uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName); uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength); + // Work around for uniform array names that aren't returned with [0] by some drivers + if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]"))) + uniform.m_name.append(QLatin1String("[0]")); m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &uniform.m_blockIndex); m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_OFFSET, &uniform.m_offset); m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_ARRAY_STRIDE, &uniform.m_arrayStride); diff --git a/src/render/jobs/job_common_p.h b/src/render/jobs/job_common_p.h index aa9828193..56c4346ed 100644 --- a/src/render/jobs/job_common_p.h +++ b/src/render/jobs/job_common_p.h @@ -102,7 +102,8 @@ namespace JobTypes { SyncTextureLoading, LoadSkeleton, UpdateSkinningPalette, - ProximityFiltering + ProximityFiltering, + SyncFilterEntityByLayer }; } // JobTypes diff --git a/src/render/materialsystem/parameter.cpp b/src/render/materialsystem/parameter.cpp index 6671e4943..f00df3c90 100644 --- a/src/render/materialsystem/parameter.cpp +++ b/src/render/materialsystem/parameter.cpp @@ -87,10 +87,13 @@ void Parameter::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) if (propertyChange->propertyName() == QByteArrayLiteral("name")) { m_name = propertyChange->value().toString(); m_nameId = StringToInt::lookupId(m_name); + markDirty(AbstractRenderer::MaterialDirty | AbstractRenderer::ParameterDirty); } else if (propertyChange->propertyName() == QByteArrayLiteral("value")) { m_uniformValue = UniformValue::fromVariant(propertyChange->value()); + markDirty(AbstractRenderer::ParameterDirty); + } else if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) { + markDirty(AbstractRenderer::MaterialDirty | AbstractRenderer::ParameterDirty); } - markDirty(AbstractRenderer::AllDirty); } BackendNode::sceneChangeEvent(e); diff --git a/src/render/materialsystem/prototypes/default.json b/src/render/materialsystem/prototypes/default.json index 9f16b0f53..535f144d7 100644 --- a/src/render/materialsystem/prototypes/default.json +++ b/src/render/materialsystem/prototypes/default.json @@ -91,7 +91,7 @@ "major": 3, "minor": 0 }, - "substitution": "vec4 $color = texture2D($name, $coord);", + "substitution": "vec4 $color = texture($name, $coord);", "headerSnippets": [ "uniform sampler2D $name;" ] } ] diff --git a/tests/auto/animation/animation.pro b/tests/auto/animation/animation.pro index c97b07923..1226f9498 100644 --- a/tests/auto/animation/animation.pro +++ b/tests/auto/animation/animation.pro @@ -15,7 +15,8 @@ SUBDIRS += \ qmorphtarget \ qvertexblendanimation \ qclock \ - qskeletonmapping + qskeletonmapping \ + qcallbackmapping qtConfig(private_tests) { SUBDIRS += \ diff --git a/tests/auto/animation/channelmapping/tst_channelmapping.cpp b/tests/auto/animation/channelmapping/tst_channelmapping.cpp index 8f276f0bd..a947d4a2d 100644 --- a/tests/auto/animation/channelmapping/tst_channelmapping.cpp +++ b/tests/auto/animation/channelmapping/tst_channelmapping.cpp @@ -68,6 +68,7 @@ private Q_SLOTS: QCOMPARE(backendMapping.channelName(), mapping.channelName()); QCOMPARE(backendMapping.targetId(), mapping.target()->id()); QCOMPARE(backendMapping.property(), mapping.property()); + QCOMPARE(backendMapping.mappingType(), Qt3DAnimation::Animation::ChannelMapping::ChannelMappingType); // GIVEN Qt3DAnimation::Animation::ChannelMapping backendSkeletonMapping; @@ -83,6 +84,7 @@ private Q_SLOTS: QCOMPARE(backendSkeletonMapping.peerId(), skeletonMapping.id()); QCOMPARE(backendSkeletonMapping.isEnabled(), skeletonMapping.isEnabled()); QCOMPARE(backendSkeletonMapping.skeletonId(), skeletonMapping.skeleton()->id()); + QCOMPARE(backendSkeletonMapping.mappingType(), Qt3DAnimation::Animation::ChannelMapping::SkeletonMappingType); } void checkInitialAndCleanedUpState() @@ -99,6 +101,7 @@ private Q_SLOTS: QCOMPARE(backendMapping.targetId(), Qt3DCore::QNodeId()); QCOMPARE(backendMapping.property(), QString()); QCOMPARE(backendMapping.skeletonId(), Qt3DCore::QNodeId()); + QCOMPARE(backendMapping.mappingType(), Qt3DAnimation::Animation::ChannelMapping::ChannelMappingType); // GIVEN Qt3DAnimation::QChannelMapping mapping; @@ -118,6 +121,7 @@ private Q_SLOTS: QCOMPARE(backendMapping.targetId(), Qt3DCore::QNodeId()); QCOMPARE(backendMapping.property(), QString()); QCOMPARE(backendMapping.skeletonId(), Qt3DCore::QNodeId()); + QCOMPARE(backendMapping.mappingType(), Qt3DAnimation::Animation::ChannelMapping::ChannelMappingType); } void checkPropertyChanges() diff --git a/tests/auto/animation/findrunningclipanimatorsjob/tst_findrunningclipanimatorsjob.cpp b/tests/auto/animation/findrunningclipanimatorsjob/tst_findrunningclipanimatorsjob.cpp index 79d18b7cf..ce37ffc76 100644 --- a/tests/auto/animation/findrunningclipanimatorsjob/tst_findrunningclipanimatorsjob.cpp +++ b/tests/auto/animation/findrunningclipanimatorsjob/tst_findrunningclipanimatorsjob.cpp @@ -72,6 +72,7 @@ public: channelMapping->setPropertyName(propertyName); channelMapping->setChannelName(channelName); channelMapping->setType(type); + channelMapping->setMappingType(ChannelMapping::ChannelMappingType); return channelMapping; } diff --git a/tests/auto/animation/qcallbackmapping/qcallbackmapping.pro b/tests/auto/animation/qcallbackmapping/qcallbackmapping.pro new file mode 100644 index 000000000..2ec002878 --- /dev/null +++ b/tests/auto/animation/qcallbackmapping/qcallbackmapping.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_qcallbackmapping + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_qcallbackmapping.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/qcallbackmapping/tst_qcallbackmapping.cpp b/tests/auto/animation/qcallbackmapping/tst_qcallbackmapping.cpp new file mode 100644 index 000000000..6a1c8da8c --- /dev/null +++ b/tests/auto/animation/qcallbackmapping/tst_qcallbackmapping.cpp @@ -0,0 +1,223 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QTest> +#include <Qt3DAnimation/qcallbackmapping.h> +#include <Qt3DAnimation/private/qcallbackmapping_p.h> +#include <Qt3DAnimation/private/qchannelmappingcreatedchange_p.h> +#include <Qt3DCore/qpropertyupdatedchange.h> +#include <Qt3DCore/qentity.h> +#include <Qt3DCore/qnodecreatedchange.h> +#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h> +#include <QObject> +#include <QSignalSpy> +#include <testpostmanarbiter.h> + +class DummyCallback : public Qt3DAnimation::QAnimationCallback +{ +public: + void valueChanged(const QVariant &) override { } +}; + +class tst_QCallbackMapping : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QCallbackMapping mapping; + + // THEN + QCOMPARE(mapping.channelName(), QString()); + QCOMPARE(mapping.callback(), static_cast<Qt3DAnimation::QAnimationCallback *>(nullptr)); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QCallbackMapping mapping; + + { + // WHEN + QSignalSpy spy(&mapping, SIGNAL(channelNameChanged(QString))); + const QString newValue(QStringLiteral("Rotation")); + mapping.setChannelName(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(mapping.channelName(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + mapping.setChannelName(newValue); + + // THEN + QCOMPARE(mapping.channelName(), newValue); + QCOMPARE(spy.count(), 0); + } + + { + // WHEN + auto newValue = new DummyCallback(); + mapping.setCallback(QVariant::Quaternion, newValue); + + // THEN - no signals for callback + QCOMPARE(mapping.callback(), newValue); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DAnimation::QCallbackMapping mapping; + auto callback = new DummyCallback(); + + mapping.setChannelName(QStringLiteral("Location")); + mapping.setCallback(QVariant::Vector3D, callback); + + // WHEN + QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&mapping); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 1); + + const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QChannelMappingCreatedChange<Qt3DAnimation::QCallbackMappingData>>(creationChanges.first()); + const Qt3DAnimation::QCallbackMappingData data = creationChangeData->data; + + QCOMPARE(mapping.id(), creationChangeData->subjectId()); + QCOMPARE(mapping.isEnabled(), true); + QCOMPARE(mapping.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(mapping.metaObject(), creationChangeData->metaObject()); + QCOMPARE(creationChangeData->type(), Qt3DAnimation::QChannelMappingCreatedChangeBase::CallbackMapping); + QCOMPARE(mapping.channelName(), data.channelName); + QCOMPARE(mapping.callback(), data.callback); + QCOMPARE(QVariant::Vector3D, data.type); + } + + // WHEN + mapping.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&mapping); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 1); + + const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QChannelMappingCreatedChange<Qt3DAnimation::QCallbackMappingData>>(creationChanges.first()); + const Qt3DAnimation::QCallbackMappingData data = creationChangeData->data; + + QCOMPARE(mapping.id(), creationChangeData->subjectId()); + QCOMPARE(mapping.isEnabled(), false); + QCOMPARE(mapping.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(mapping.metaObject(), creationChangeData->metaObject()); + QCOMPARE(creationChangeData->type(), Qt3DAnimation::QChannelMappingCreatedChangeBase::CallbackMapping); + QCOMPARE(mapping.channelName(), data.channelName); + QCOMPARE(mapping.callback(), data.callback); + QCOMPARE(QVariant::Vector3D, data.type); + } + } + + void checkPropertyUpdateChanges() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QCallbackMapping mapping; + arbiter.setArbiterOnNode(&mapping); + + { + // WHEN + mapping.setChannelName(QStringLiteral("Scale")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); + QCOMPARE(change->propertyName(), "channelName"); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + QCOMPARE(change->value().toString(), mapping.channelName()); + + arbiter.events.clear(); + + // WHEN + mapping.setChannelName(QStringLiteral("Scale")); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + { + // WHEN + auto callback = new DummyCallback(); + mapping.setCallback(QVariant::Vector3D, callback, Qt3DAnimation::QAnimationCallback::OnThreadPool); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 3); + auto change = arbiter.events.at(0).staticCast<Qt3DCore::QPropertyUpdatedChange>(); + QCOMPARE(change->propertyName(), "type"); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + QCOMPARE(change->value().toInt(), QVariant::Vector3D); + + change = arbiter.events.at(1).staticCast<Qt3DCore::QPropertyUpdatedChange>(); + QCOMPARE(change->propertyName(), "callback"); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + QCOMPARE(reinterpret_cast<DummyCallback *>(change->value().value<void *>()), callback); + + change = arbiter.events.at(2).staticCast<Qt3DCore::QPropertyUpdatedChange>(); + QCOMPARE(change->propertyName(), "callbackFlags"); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + QCOMPARE(change->value().toInt(), static_cast<int>(Qt3DAnimation::QAnimationCallback::OnThreadPool)); + + arbiter.events.clear(); + + // WHEN + mapping.setCallback(QVariant::Vector3D, callback, Qt3DAnimation::QAnimationCallback::OnThreadPool); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + } +}; + +QTEST_MAIN(tst_QCallbackMapping) + +#include "tst_qcallbackmapping.moc" 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/filtercompatibletechniquejob/BLACKLIST b/tests/auto/render/filtercompatibletechniquejob/BLACKLIST index c9313fd62..22cb59fab 100644 --- a/tests/auto/render/filtercompatibletechniquejob/BLACKLIST +++ b/tests/auto/render/filtercompatibletechniquejob/BLACKLIST @@ -1,4 +1,5 @@ -[checkRunRendererNotRunning] -windows -[checkRunRendererRunning] +#[checkRunRendererNotRunning] +#windows +#[checkRunRendererRunning] +#QTBUG-64271 windows 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..23861f3a9 100644 --- a/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp +++ b/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp @@ -179,27 +179,60 @@ private Q_SLOTS: Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(clearBuffer->id()); QVERIFY(leafNode != nullptr); - // WHEN - Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); + { + // WHEN + Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); + + // THEN + QCOMPARE(renderViewBuilder.renderViewIndex(), 0); + QCOMPARE(renderViewBuilder.renderer(), testAspect.renderer()); + QCOMPARE(renderViewBuilder.layerCacheNeedsToBeRebuilt(), false); + QVERIFY(!renderViewBuilder.renderViewJob().isNull()); + QVERIFY(!renderViewBuilder.lightGathererJob().isNull()); + QVERIFY(!renderViewBuilder.renderableEntityFilterJob().isNull()); + QVERIFY(!renderViewBuilder.computableEntityFilterJob().isNull()); + QVERIFY(!renderViewBuilder.frustumCullingJob().isNull()); + QVERIFY(!renderViewBuilder.syncFrustumCullingJob().isNull()); + QVERIFY(!renderViewBuilder.setClearDrawBufferIndexJob().isNull()); + + QVERIFY(renderViewBuilder.filterEntityByLayerJob().isNull()); + QVERIFY(renderViewBuilder.syncFilterEntityByLayerJob().isNull()); + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob().isNull()); + QVERIFY(renderViewBuilder.syncRenderViewCommandBuildersJob().isNull()); + QVERIFY(renderViewBuilder.syncRenderViewInitializationJob().isNull()); + + QCOMPARE(renderViewBuilder.renderViewBuilderJobs().size(), 0); + QCOMPARE(renderViewBuilder.materialGathererJobs().size(), 0); + + // WHEN + renderViewBuilder.prepareJobs(); + + // THEN + QVERIFY(!renderViewBuilder.syncRenderCommandBuildingJob().isNull()); + QVERIFY(!renderViewBuilder.syncRenderViewCommandBuildersJob().isNull()); + QVERIFY(!renderViewBuilder.syncRenderViewInitializationJob().isNull()); + QVERIFY(renderViewBuilder.filterEntityByLayerJob().isNull()); + QVERIFY(renderViewBuilder.syncFilterEntityByLayerJob().isNull()); + + 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()); + } - // THEN - QCOMPARE(renderViewBuilder.renderViewIndex(), 0); - QCOMPARE(renderViewBuilder.renderer(), testAspect.renderer()); - QVERIFY(!renderViewBuilder.renderViewJob().isNull()); - QVERIFY(!renderViewBuilder.filterEntityByLayerJob().isNull()); - QVERIFY(!renderViewBuilder.lightGathererJob().isNull()); - QVERIFY(!renderViewBuilder.renderableEntityFilterJob().isNull()); - QVERIFY(!renderViewBuilder.computableEntityFilterJob().isNull()); - QVERIFY(!renderViewBuilder.frustumCullingJob().isNull()); - QVERIFY(!renderViewBuilder.syncRenderViewInitializationJob().isNull()); - QVERIFY(!renderViewBuilder.syncFrustumCullingJob().isNull()); - QVERIFY(!renderViewBuilder.syncRenderCommandBuildingJob().isNull()); - QVERIFY(!renderViewBuilder.syncRenderViewCommandBuildersJob().isNull()); - QVERIFY(!renderViewBuilder.setClearDrawBufferIndexJob().isNull()); - QCOMPARE(renderViewBuilder.renderViewBuilderJobs().size(), Qt3DRender::Render::RenderViewBuilder::optimalJobCount()); - QCOMPARE(renderViewBuilder.materialGathererJobs().size(), Qt3DRender::Render::RenderViewBuilder::optimalJobCount()); - - QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 12 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount()); + { + // WHEN + Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); + renderViewBuilder.setLayerCacheNeedsToBeRebuilt(true); + renderViewBuilder.prepareJobs(); + + // THEN + QCOMPARE(renderViewBuilder.layerCacheNeedsToBeRebuilt(), true); + QVERIFY(!renderViewBuilder.filterEntityByLayerJob().isNull()); + QVERIFY(!renderViewBuilder.syncFilterEntityByLayerJob().isNull()); + + // mark jobs dirty and recheck + QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 13 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount()); + } } void checkCheckJobDependencies() @@ -213,70 +246,145 @@ private Q_SLOTS: Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(clearBuffer->id()); QVERIFY(leafNode != nullptr); - // WHEN - Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); - renderViewBuilder.buildJobHierachy(); - - // THEN - // Step 1 - QCOMPARE(renderViewBuilder.renderViewJob()->dependencies().size(), 1); // Depends upon skinning palette update - QCOMPARE(renderViewBuilder.lightGathererJob()->dependencies().size(), 0); - QCOMPARE(renderViewBuilder.renderableEntityFilterJob()->dependencies().size(),0); - QCOMPARE(renderViewBuilder.computableEntityFilterJob()->dependencies().size(), 0); - - // Step 2 - QCOMPARE(renderViewBuilder.syncRenderViewInitializationJob()->dependencies().size(), 1); - QCOMPARE(renderViewBuilder.syncRenderViewInitializationJob()->dependencies().first().data(), renderViewBuilder.renderViewJob().data()); - - // Step 3 - QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->dependencies().size(), 2); - QVERIFY(renderViewBuilder.filterEntityByLayerJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob())); - QVERIFY(renderViewBuilder.filterEntityByLayerJob()->dependencies().contains(testAspect.renderer()->updateTreeEnabledJob())); - - QCOMPARE(renderViewBuilder.filterProximityJob()->dependencies().size(), 2); - QVERIFY(renderViewBuilder.filterProximityJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob())); - QVERIFY(renderViewBuilder.filterProximityJob()->dependencies().contains(testAspect.renderer()->expandBoundingVolumeJob())); - - QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().size(), 1); - QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().first().data(), renderViewBuilder.syncRenderViewInitializationJob().data()); - - QCOMPARE(renderViewBuilder.syncFrustumCullingJob()->dependencies().size(), 3); - QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob())); - QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateWorldTransformJob())); - QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateShaderDataTransformJob())); - - for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) { - QCOMPARE(materialGatherer->dependencies().size(), 2); - QVERIFY(materialGatherer->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob())); - QVERIFY(materialGatherer->dependencies().contains(testAspect.renderer()->filterCompatibleTechniqueJob())); - } - - // Step 4 - QCOMPARE(renderViewBuilder.frustumCullingJob()->dependencies().size(), 2); - QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(renderViewBuilder.syncFrustumCullingJob())); - QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(testAspect.renderer()->expandBoundingVolumeJob())); - - QCOMPARE(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().size(), renderViewBuilder.materialGathererJobs().size() + 7); - QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob())); - QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.renderableEntityFilterJob())); - QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.computableEntityFilterJob())); - QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.filterEntityByLayerJob())); - QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.lightGathererJob())); - QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.frustumCullingJob())); - for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) { - QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(materialGatherer)); + { + // WHEN + Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); + renderViewBuilder.prepareJobs(); + renderViewBuilder.buildJobHierachy(); + + // THEN + // Step 1 + QCOMPARE(renderViewBuilder.renderViewJob()->dependencies().size(), 1); // Depends upon skinning palette update + QCOMPARE(renderViewBuilder.lightGathererJob()->dependencies().size(), 0); + QCOMPARE(renderViewBuilder.renderableEntityFilterJob()->dependencies().size(),0); + QCOMPARE(renderViewBuilder.computableEntityFilterJob()->dependencies().size(), 0); + + // Step 2 + QCOMPARE(renderViewBuilder.syncRenderViewInitializationJob()->dependencies().size(), 1); + QCOMPARE(renderViewBuilder.syncRenderViewInitializationJob()->dependencies().first().data(), renderViewBuilder.renderViewJob().data()); + + // Step 3 + QVERIFY(renderViewBuilder.filterEntityByLayerJob().isNull()); + QVERIFY(renderViewBuilder.syncFilterEntityByLayerJob().isNull()); + + QCOMPARE(renderViewBuilder.filterProximityJob()->dependencies().size(), 2); + QVERIFY(renderViewBuilder.filterProximityJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob())); + QVERIFY(renderViewBuilder.filterProximityJob()->dependencies().contains(testAspect.renderer()->expandBoundingVolumeJob())); + + QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().size(), 1); + QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().first().data(), renderViewBuilder.syncRenderViewInitializationJob().data()); + + QCOMPARE(renderViewBuilder.syncFrustumCullingJob()->dependencies().size(), 3); + QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob())); + QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateWorldTransformJob())); + QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateShaderDataTransformJob())); + + for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) { + QCOMPARE(materialGatherer->dependencies().size(), 2); + QVERIFY(materialGatherer->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob())); + QVERIFY(materialGatherer->dependencies().contains(testAspect.renderer()->filterCompatibleTechniqueJob())); + } + + // Step 4 + QCOMPARE(renderViewBuilder.frustumCullingJob()->dependencies().size(), 2); + QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(renderViewBuilder.syncFrustumCullingJob())); + QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(testAspect.renderer()->expandBoundingVolumeJob())); + + QCOMPARE(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().size(), renderViewBuilder.materialGathererJobs().size() + 6); + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob())); + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.renderableEntityFilterJob())); + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.computableEntityFilterJob())); + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.filterProximityJob())); + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.lightGathererJob())); + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.frustumCullingJob())); + for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) { + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(materialGatherer)); + } + + // Step 5 + for (const auto renderViewBuilderJob : renderViewBuilder.renderViewBuilderJobs()) { + QCOMPARE(renderViewBuilderJob->dependencies().size(), 1); + QCOMPARE(renderViewBuilderJob->dependencies().first().data(), renderViewBuilder.syncRenderCommandBuildingJob().data()); + } + + // Step 6 + QCOMPARE(renderViewBuilder.syncRenderViewCommandBuildersJob()->dependencies().size(), renderViewBuilder.renderViewBuilderJobs().size()); + for (const auto renderViewBuilderJob : renderViewBuilder.renderViewBuilderJobs()) { + QVERIFY(renderViewBuilder.syncRenderViewCommandBuildersJob()->dependencies().contains(renderViewBuilderJob)); + } } - - // Step 5 - for (const auto renderViewBuilderJob : renderViewBuilder.renderViewBuilderJobs()) { - QCOMPARE(renderViewBuilderJob->dependencies().size(), 1); - QCOMPARE(renderViewBuilderJob->dependencies().first().data(), renderViewBuilder.syncRenderCommandBuildingJob().data()); - } - - // Step 6 - QCOMPARE(renderViewBuilder.syncRenderViewCommandBuildersJob()->dependencies().size(), renderViewBuilder.renderViewBuilderJobs().size()); - for (const auto renderViewBuilderJob : renderViewBuilder.renderViewBuilderJobs()) { - QVERIFY(renderViewBuilder.syncRenderViewCommandBuildersJob()->dependencies().contains(renderViewBuilderJob)); + { + // WHEN + Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); + renderViewBuilder.setLayerCacheNeedsToBeRebuilt(true); + renderViewBuilder.prepareJobs(); + renderViewBuilder.buildJobHierachy(); + + // THEN + // Step 1 + QCOMPARE(renderViewBuilder.renderViewJob()->dependencies().size(), 1); // Depends upon skinning palette update + QCOMPARE(renderViewBuilder.lightGathererJob()->dependencies().size(), 0); + QCOMPARE(renderViewBuilder.renderableEntityFilterJob()->dependencies().size(),0); + QCOMPARE(renderViewBuilder.computableEntityFilterJob()->dependencies().size(), 0); + + // Step 2 + QCOMPARE(renderViewBuilder.syncRenderViewInitializationJob()->dependencies().size(), 1); + QCOMPARE(renderViewBuilder.syncRenderViewInitializationJob()->dependencies().first().data(), renderViewBuilder.renderViewJob().data()); + + // Step 3 + QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->dependencies().size(), 2); + QVERIFY(renderViewBuilder.filterEntityByLayerJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob())); + QVERIFY(renderViewBuilder.filterEntityByLayerJob()->dependencies().contains(testAspect.renderer()->updateTreeEnabledJob())); + + QCOMPARE(renderViewBuilder.syncFilterEntityByLayerJob()->dependencies().size(), 1); + QVERIFY(renderViewBuilder.syncFilterEntityByLayerJob()->dependencies().contains(renderViewBuilder.filterEntityByLayerJob())); + + QCOMPARE(renderViewBuilder.filterProximityJob()->dependencies().size(), 2); + QVERIFY(renderViewBuilder.filterProximityJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob())); + QVERIFY(renderViewBuilder.filterProximityJob()->dependencies().contains(testAspect.renderer()->expandBoundingVolumeJob())); + + QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().size(), 1); + QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().first().data(), renderViewBuilder.syncRenderViewInitializationJob().data()); + + QCOMPARE(renderViewBuilder.syncFrustumCullingJob()->dependencies().size(), 3); + QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob())); + QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateWorldTransformJob())); + QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateShaderDataTransformJob())); + + for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) { + QCOMPARE(materialGatherer->dependencies().size(), 2); + QVERIFY(materialGatherer->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob())); + QVERIFY(materialGatherer->dependencies().contains(testAspect.renderer()->filterCompatibleTechniqueJob())); + } + + // Step 4 + QCOMPARE(renderViewBuilder.frustumCullingJob()->dependencies().size(), 2); + QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(renderViewBuilder.syncFrustumCullingJob())); + QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(testAspect.renderer()->expandBoundingVolumeJob())); + + QCOMPARE(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().size(), renderViewBuilder.materialGathererJobs().size() + 7); + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob())); + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.renderableEntityFilterJob())); + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.computableEntityFilterJob())); + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.syncFilterEntityByLayerJob())); + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.lightGathererJob())); + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.frustumCullingJob())); + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.filterProximityJob())); + for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) { + QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(materialGatherer)); + } + + // Step 5 + for (const auto renderViewBuilderJob : renderViewBuilder.renderViewBuilderJobs()) { + QCOMPARE(renderViewBuilderJob->dependencies().size(), 1); + QCOMPARE(renderViewBuilderJob->dependencies().first().data(), renderViewBuilder.syncRenderCommandBuildingJob().data()); + } + + // Step 6 + QCOMPARE(renderViewBuilder.syncRenderViewCommandBuildersJob()->dependencies().size(), renderViewBuilder.renderViewBuilderJobs().size()); + for (const auto renderViewBuilderJob : renderViewBuilder.renderViewBuilderJobs()) { + QVERIFY(renderViewBuilder.syncRenderViewCommandBuildersJob()->dependencies().contains(renderViewBuilderJob)); + } } } @@ -293,6 +401,7 @@ private Q_SLOTS: // WHEN Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); + renderViewBuilder.prepareJobs(); renderViewBuilder.buildJobHierachy(); renderViewBuilder.renderViewJob()->run(); @@ -313,6 +422,7 @@ private Q_SLOTS: // WHEN Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); + renderViewBuilder.prepareJobs(); renderViewBuilder.buildJobHierachy(); renderViewBuilder.renderableEntityFilterJob()->run(); @@ -333,6 +443,7 @@ private Q_SLOTS: // WHEN Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); + renderViewBuilder.prepareJobs(); renderViewBuilder.buildJobHierachy(); renderViewBuilder.computableEntityFilterJob()->run(); @@ -358,30 +469,58 @@ private Q_SLOTS: Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(renderPassFilter->id()); QVERIFY(leafNode != nullptr); - // WHEN - Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); - renderViewBuilder.buildJobHierachy(); - - // THEN - QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), false); - QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->hasLayerFilter(), false); - QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->layerFilters().size(), 0); - for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) { - QVERIFY(materialGatherer->techniqueFilter() == nullptr); - QVERIFY(materialGatherer->renderPassFilter() == nullptr); + { + // WHEN + Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); + renderViewBuilder.prepareJobs(); + renderViewBuilder.buildJobHierachy(); + + // THEN + QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), false); + for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) { + QVERIFY(materialGatherer->techniqueFilter() == nullptr); + QVERIFY(materialGatherer->renderPassFilter() == nullptr); + } + + // WHEN + renderViewBuilder.renderViewJob()->run(); + renderViewBuilder.syncRenderViewInitializationJob()->run(); + + // THEN + QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), true); + for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) { + QVERIFY(materialGatherer->techniqueFilter() != nullptr); + QVERIFY(materialGatherer->renderPassFilter() != nullptr); + } } - - // WHEN - renderViewBuilder.renderViewJob()->run(); - renderViewBuilder.syncRenderViewInitializationJob()->run(); - - // THEN - QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), true); - QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->hasLayerFilter(), true); - QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->layerFilters().size(), 1); - for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) { - QVERIFY(materialGatherer->techniqueFilter() != nullptr); - QVERIFY(materialGatherer->renderPassFilter() != nullptr); + { + // WHEN + Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); + renderViewBuilder.setLayerCacheNeedsToBeRebuilt(true); + renderViewBuilder.prepareJobs(); + renderViewBuilder.buildJobHierachy(); + + // THEN + QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), false); + QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->hasLayerFilter(), false); + QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->layerFilters().size(), 0); + for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) { + QVERIFY(materialGatherer->techniqueFilter() == nullptr); + QVERIFY(materialGatherer->renderPassFilter() == nullptr); + } + + // WHEN + renderViewBuilder.renderViewJob()->run(); + renderViewBuilder.syncRenderViewInitializationJob()->run(); + + // THEN + QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), true); + QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->hasLayerFilter(), true); + QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->layerFilters().size(), 1); + for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) { + QVERIFY(materialGatherer->techniqueFilter() != nullptr); + QVERIFY(materialGatherer->renderPassFilter() != nullptr); + } } } @@ -403,6 +542,7 @@ private Q_SLOTS: // WHEN Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); + renderViewBuilder.prepareJobs(); renderViewBuilder.buildJobHierachy(); // THEN @@ -432,6 +572,8 @@ private Q_SLOTS: // WHEN Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); + renderViewBuilder.setLayerCacheNeedsToBeRebuilt(true); + renderViewBuilder.prepareJobs(); renderViewBuilder.buildJobHierachy(); renderViewBuilder.renderViewJob()->run(); 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(); } } diff --git a/tests/manual/layerfilter-qml/main.qml b/tests/manual/layerfilter-qml/main.qml index 8a5977faa..00b1cffa0 100644 --- a/tests/manual/layerfilter-qml/main.qml +++ b/tests/manual/layerfilter-qml/main.qml @@ -49,7 +49,7 @@ ****************************************************************************/ import Qt3D.Core 2.0 -import Qt3D.Render 2.0 +import Qt3D.Render 2.10 import Qt3D.Input 2.0 import Qt3D.Extras 2.0 @@ -127,7 +127,7 @@ Entity { layers: [ backgroundLayer, ] - discard: true + filterMode: LayerFilter.DiscardAnyMatchingLayers CameraSelector { camera: camera |