summaryrefslogtreecommitdiffstats
path: root/src/render/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/render/backend')
-rw-r--r--src/render/backend/abstractrenderer_p.h20
-rw-r--r--src/render/backend/attachmentpack.cpp2
-rw-r--r--src/render/backend/cameralens.cpp132
-rw-r--r--src/render/backend/cameralens_p.h30
-rw-r--r--src/render/backend/commandexecuter.cpp5
-rw-r--r--src/render/backend/commandexecuter_p.h2
-rw-r--r--src/render/backend/entity.cpp297
-rw-r--r--src/render/backend/entity_p.h201
-rw-r--r--src/render/backend/frameprofiler_p.h13
-rw-r--r--src/render/backend/handle_types_p.h8
-rw-r--r--src/render/backend/layer.cpp33
-rw-r--r--src/render/backend/layer_p.h11
-rw-r--r--src/render/backend/managers.cpp36
-rw-r--r--src/render/backend/managers_p.h59
-rw-r--r--src/render/backend/nodemanagers.cpp34
-rw-r--r--src/render/backend/nodemanagers_p.h28
-rw-r--r--src/render/backend/pointsvisitor.cpp188
-rw-r--r--src/render/backend/pointsvisitor_p.h92
-rw-r--r--src/render/backend/render-backend.pri13
-rw-r--r--src/render/backend/renderer.cpp243
-rw-r--r--src/render/backend/renderer_p.h22
-rw-r--r--src/render/backend/renderercache_p.h86
-rw-r--r--src/render/backend/renderqueue_p.h4
-rw-r--r--src/render/backend/rendersettings.cpp4
-rw-r--r--src/render/backend/rendersettings_p.h5
-rw-r--r--src/render/backend/renderthread.cpp11
-rw-r--r--src/render/backend/renderview.cpp78
-rw-r--r--src/render/backend/renderview_p.h62
-rw-r--r--src/render/backend/renderviewbuilder.cpp257
-rw-r--r--src/render/backend/renderviewbuilder_p.h11
-rw-r--r--src/render/backend/segmentsvisitor.cpp369
-rw-r--r--src/render/backend/segmentsvisitor_p.h93
-rw-r--r--src/render/backend/trianglesvisitor.cpp155
-rw-r--r--src/render/backend/uniform.cpp24
-rw-r--r--src/render/backend/uniform_p.h26
-rw-r--r--src/render/backend/visitorutils_p.h179
36 files changed, 2165 insertions, 668 deletions
diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h
index f8d9850e7..4d80ec87d 100644
--- a/src/render/backend/abstractrenderer_p.h
+++ b/src/render/backend/abstractrenderer_p.h
@@ -95,11 +95,20 @@ public:
// Changes made to backend nodes are reported to the Renderer
enum BackendNodeDirtyFlag {
- TransformDirty = 1 << 0,
- MaterialDirty = 1 << 1,
- GeometryDirty = 1 << 2,
- ComputeDirty = 1 << 3,
- AllDirty = 1 << 15
+ TransformDirty = 1 << 0,
+ MaterialDirty = 1 << 1,
+ GeometryDirty = 1 << 2,
+ ComputeDirty = 1 << 3,
+ ParameterDirty = 1 << 4,
+ FrameGraphDirty = 1 << 5,
+ EntityEnabledDirty = 1 << 6,
+ BuffersDirty = 1 << 7,
+ TexturesDirty = 1 << 8,
+ ShadersDirty = 1 << 9,
+ SkeletonDataDirty = 1 << 10,
+ JointDirty = 1 << 11,
+ LayersDirty = 1 << 12,
+ AllDirty = 0xffffff
};
Q_DECLARE_FLAGS(BackendNodeDirtySet, BackendNodeDirtyFlag)
@@ -139,6 +148,7 @@ public:
virtual QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() = 0;
virtual Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() = 0;
virtual Qt3DCore::QAspectJobPtr syncTextureLoadingJob() = 0;
+ virtual Qt3DCore::QAspectJobPtr expandBoundingVolumeJob() = 0;
virtual void setSceneRoot(Qt3DCore::QBackendNodeFactory *factory, Entity *root) = 0;
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/cameralens.cpp b/src/render/backend/cameralens.cpp
index 3d0e7fdaf..cf1f17d32 100644
--- a/src/render/backend/cameralens.cpp
+++ b/src/render/backend/cameralens.cpp
@@ -39,8 +39,14 @@
#include "cameralens_p.h"
#include <Qt3DRender/qcameralens.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/qcameralens_p.h>
#include <Qt3DRender/private/renderlogging_p.h>
+#include <Qt3DRender/private/renderer_p.h>
+#include <Qt3DRender/private/entity_p.h>
+#include <Qt3DRender/private/sphere_p.h>
+#include <Qt3DRender/private/computefilteredboundingvolumejob_p.h>
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/qtransform.h>
@@ -52,8 +58,34 @@ using namespace Qt3DCore;
namespace Qt3DRender {
namespace Render {
+
+namespace {
+
+class GetBoundingVolumeWithoutCameraJob : public ComputeFilteredBoundingVolumeJob
+{
+public:
+ GetBoundingVolumeWithoutCameraJob(CameraLens *lens,
+ QNodeCommand::CommandId commandId)
+ : m_lens(lens), m_commandId(commandId)
+ {
+ }
+
+protected:
+ void finished(const Sphere &sphere) override
+ {
+ m_lens->notifySceneBoundingVolume(sphere, m_commandId);
+ }
+
+private:
+ CameraLens *m_lens;
+ QNodeCommand::CommandId m_commandId;
+};
+
+} // namespace
+
CameraLens::CameraLens()
- : BackendNode()
+ : BackendNode(QBackendNode::ReadWrite)
+ , m_renderAspect(nullptr)
, m_exposure(0.0f)
{
}
@@ -68,6 +100,11 @@ void CameraLens::cleanup()
QBackendNode::setEnabled(false);
}
+void CameraLens::setRenderAspect(QRenderAspect *renderAspect)
+{
+ m_renderAspect = renderAspect;
+}
+
void CameraLens::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
{
const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QCameraLensData>>(change);
@@ -76,6 +113,41 @@ void CameraLens::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &c
m_exposure = data.exposure;
}
+void CameraLens::computeSceneBoundingVolume(QNodeId entityId,
+ QNodeId cameraId,
+ QNodeCommand::CommandId commandId)
+{
+ if (!m_renderer || !m_renderAspect)
+ return;
+ NodeManagers *nodeManagers = m_renderer->nodeManagers();
+
+ Entity *root = m_renderer->sceneRoot();
+ if (!entityId.isNull())
+ root = nodeManagers->renderNodesManager()->lookupResource(entityId);
+ if (!root)
+ return;
+
+ Entity *camNode = nodeManagers->renderNodesManager()->lookupResource(cameraId);
+ ComputeFilteredBoundingVolumeJobPtr job(new GetBoundingVolumeWithoutCameraJob(this, commandId));
+ job->addDependency(m_renderer->expandBoundingVolumeJob());
+ job->setRoot(root);
+ job->ignoreSubTree(camNode);
+ m_renderAspect->scheduleSingleShotJob(job);
+}
+
+void CameraLens::notifySceneBoundingVolume(const Sphere &sphere, QNodeCommand::CommandId commandId)
+{
+ if (m_pendingViewAllCommand != commandId)
+ return;
+ if (sphere.radius() > 0.f) {
+ QVector<float> data = { sphere.center().x(), sphere.center().y(), sphere.center().z(),
+ sphere.radius() };
+ QVariant v;
+ v.setValue(data);
+ sendCommand(QLatin1Literal("ViewAll"), v, m_pendingViewAllCommand);
+ }
+}
+
void CameraLens::setProjection(const QMatrix4x4 &projection)
{
m_projection = projection;
@@ -103,12 +175,70 @@ void CameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
}
break;
+ case CommandRequested: {
+ QNodeCommandPtr command = qSharedPointerCast<QNodeCommand>(e);
+
+ if (command->name() == QLatin1Literal("QueryRootBoundingVolume")) {
+ m_pendingViewAllCommand = command->commandId();
+ QVariant v = command->data();
+ QNodeId id = v.value<QNodeId>();
+ computeSceneBoundingVolume({}, id, command->commandId());
+ } else if (command->name() == QLatin1Literal("QueryEntityBoundingVolume")) {
+ m_pendingViewAllCommand = command->commandId();
+ QVariant v = command->data();
+ QVector<QNodeId> ids = v.value<QVector<QNodeId>>();
+ if (ids.size() == 2)
+ computeSceneBoundingVolume(ids[0], ids[1], command->commandId());
+ }
+ }
+ break;
+
default:
break;
}
BackendNode::sceneChangeEvent(e);
}
+bool CameraLens::viewMatrixForCamera(EntityManager* manager, Qt3DCore::QNodeId cameraId,
+ QMatrix4x4 &viewMatrix, QMatrix4x4 &projectionMatrix)
+{
+ Entity *camNode = manager->lookupResource(cameraId);
+ if (!camNode)
+ return false;
+ Render::CameraLens *lens = camNode->renderComponent<CameraLens>();
+ if (!lens || !lens->isEnabled())
+ return false;
+
+ viewMatrix = *camNode->worldTransform();
+ projectionMatrix = lens->projection();
+ return true;
+}
+
+CameraLensFunctor::CameraLensFunctor(AbstractRenderer *renderer, QRenderAspect *renderAspect)
+ : m_manager(renderer->nodeManagers()->manager<CameraLens, CameraManager>())
+ , m_renderer(renderer)
+ , m_renderAspect(renderAspect)
+{
+}
+
+QBackendNode *CameraLensFunctor::create(const QNodeCreatedChangeBasePtr &change) const
+{
+ CameraLens *backend = m_manager->getOrCreateResource(change->subjectId());
+ backend->setRenderer(m_renderer);
+ backend->setRenderAspect(m_renderAspect);
+ return backend;
+}
+
+QBackendNode *CameraLensFunctor::get(QNodeId id) const
+{
+ return m_manager->lookupResource(id);
+}
+
+void CameraLensFunctor::destroy(QNodeId id) const
+{
+ m_manager->releaseResource(id);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/cameralens_p.h b/src/render/backend/cameralens_p.h
index 72282a88b..d071619d8 100644
--- a/src/render/backend/cameralens_p.h
+++ b/src/render/backend/cameralens_p.h
@@ -52,6 +52,7 @@
//
#include <Qt3DRender/private/backendnode_p.h>
+#include <Qt3DCore/private/qnodecommand_p.h>
#include <QMatrix4x4>
#include <QRectF>
@@ -61,15 +62,33 @@ namespace Qt3DRender {
namespace Render {
+class EntityManager;
class CameraManager;
+class Sphere;
-class CameraLens : public BackendNode
+class CameraLensFunctor : public Qt3DCore::QBackendNodeMapper
+{
+public:
+ explicit CameraLensFunctor(AbstractRenderer *renderer, QRenderAspect *renderAspect);
+ Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const Q_DECL_OVERRIDE;
+ Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const Q_DECL_OVERRIDE;
+ void destroy(Qt3DCore::QNodeId id) const Q_DECL_OVERRIDE;
+
+private:
+ CameraManager *m_manager;
+ AbstractRenderer *m_renderer;
+ QRenderAspect *m_renderAspect;
+};
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT CameraLens : public BackendNode
{
public:
CameraLens();
~CameraLens();
void cleanup();
+ void setRenderAspect(QRenderAspect* renderAspect);
+
void setProjection(const QMatrix4x4 &projection);
inline QMatrix4x4 projection() const { return m_projection; }
@@ -77,11 +96,20 @@ public:
inline float exposure() const { return m_exposure; }
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
+ void notifySceneBoundingVolume(const Sphere &sphere, Qt3DCore::QNodeCommand::CommandId commandId);
+
+ static bool viewMatrixForCamera(EntityManager *manager, Qt3DCore::QNodeId cameraId,
+ QMatrix4x4 &viewMatrix, QMatrix4x4 &projectionMatrix);
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+ void computeSceneBoundingVolume(Qt3DCore::QNodeId entityId,
+ Qt3DCore::QNodeId cameraId,
+ Qt3DCore::QNodeCommand::CommandId commandId);
+ QRenderAspect *m_renderAspect;
QMatrix4x4 m_projection;
+ Qt3DCore::QNodeCommand::CommandId m_pendingViewAllCommand;
float m_exposure;
};
diff --git a/src/render/backend/commandexecuter.cpp b/src/render/backend/commandexecuter.cpp
index 84bf7455a..cd1ec0e2b 100644
--- a/src/render/backend/commandexecuter.cpp
+++ b/src/render/backend/commandexecuter.cpp
@@ -303,8 +303,9 @@ CommandExecuter::CommandExecuter(Render::Renderer *renderer)
// Render thread
void CommandExecuter::performAsynchronousCommandExecution(const QVector<Render::RenderView *> &views)
{
- // The renderer's mutex is already locked
+ QMutexLocker lock(&m_pendingCommandsMutex);
const QVector<Qt3DCore::Debug::AsynchronousCommandReply *> shellCommands = std::move(m_pendingCommands);
+ lock.unlock();
for (auto *reply : shellCommands) {
if (reply->commandName() == QLatin1String("glinfo")) {
@@ -375,7 +376,7 @@ QVariant CommandExecuter::executeCommand(const QStringList &args)
(args.first() == QLatin1String("glinfo") ||
args.first() == QLatin1String("rendercommands"))) {
auto reply = new Qt3DCore::Debug::AsynchronousCommandReply(args.first());
- QMutexLocker lock(m_renderer->mutex());
+ QMutexLocker lock(&m_pendingCommandsMutex);
m_pendingCommands.push_back(reply);
return QVariant::fromValue(reply);
}
diff --git a/src/render/backend/commandexecuter_p.h b/src/render/backend/commandexecuter_p.h
index 896164543..2d90bf4d6 100644
--- a/src/render/backend/commandexecuter_p.h
+++ b/src/render/backend/commandexecuter_p.h
@@ -50,6 +50,7 @@
#include <QVector>
#include <QVariant>
+#include <QMutex>
QT_BEGIN_NAMESPACE
@@ -82,6 +83,7 @@ public:
private:
Render::Renderer *m_renderer;
QVector<Qt3DCore::Debug::AsynchronousCommandReply *> m_pendingCommands;
+ QMutex m_pendingCommandsMutex;
};
} // Debug
diff --git a/src/render/backend/entity.cpp b/src/render/backend/entity.cpp
index 8a97eed81..95304007a 100644
--- a/src/render/backend/entity.cpp
+++ b/src/render/backend/entity.cpp
@@ -53,8 +53,10 @@
#include <Qt3DRender/qobjectpicker.h>
#include <Qt3DRender/qcomputecommand.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
+#include <Qt3DRender/private/armature_p.h>
#include <Qt3DRender/qcameralens.h>
+#include <Qt3DCore/qarmature.h>
#include <Qt3DCore/qcomponentaddedchange.h>
#include <Qt3DCore/qcomponentremovedchange.h>
#include <Qt3DCore/qentity.h>
@@ -114,6 +116,7 @@ void Entity::cleanup()
m_objectPickerComponent = QNodeId();
m_boundingVolumeDebugComponent = QNodeId();
m_computeComponent = QNodeId();
+ m_armatureComponent = QNodeId();
m_childrenHandles.clear();
m_layerComponents.clear();
m_levelOfDetailComponents.clear();
@@ -199,6 +202,7 @@ void Entity::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
const auto componentIdAndType = QNodeIdTypePair(change->componentId(), change->componentMetaObject());
addComponent(componentIdAndType);
qCDebug(Render::RenderNodes) << Q_FUNC_INFO << "Component Added. Id =" << change->componentId();
+ markDirty(AbstractRenderer::AllDirty);
break;
}
@@ -206,28 +210,42 @@ void Entity::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
QComponentRemovedChangePtr change = qSharedPointerCast<QComponentRemovedChange>(e);
removeComponent(change->componentId());
qCDebug(Render::RenderNodes) << Q_FUNC_INFO << "Component Removed. Id =" << change->componentId();
+ markDirty(AbstractRenderer::AllDirty);
break;
}
case PropertyValueAdded: {
QPropertyNodeAddedChangePtr change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->metaObject()->inherits(&QEntity::staticMetaObject))
+ if (change->metaObject()->inherits(&QEntity::staticMetaObject)) {
appendChildHandle(m_nodeManagers->renderNodesManager()->lookupHandle(change->addedNodeId()));
+ markDirty(AbstractRenderer::AllDirty);
+ }
break;
}
case PropertyValueRemoved: {
QPropertyNodeRemovedChangePtr change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (change->metaObject()->inherits(&QEntity::staticMetaObject))
+ if (change->metaObject()->inherits(&QEntity::staticMetaObject)) {
removeChildHandle(m_nodeManagers->renderNodesManager()->lookupHandle(change->removedNodeId()));
+ markDirty(AbstractRenderer::AllDirty);
+ }
break;
}
+ case PropertyUpdated: {
+ QPropertyUpdatedChangePtr change = qSharedPointerCast<QPropertyUpdatedChange>(e);
+ if (change->propertyName() == QByteArrayLiteral("enabled")) {
+ // We only mark as dirty the renderer
+ markDirty(AbstractRenderer::EntityEnabledDirty);
+ // We let QBackendNode::sceneChangeEvent change the enabled property
+ }
+
+ break;
+ }
default:
break;
}
- markDirty(AbstractRenderer::AllDirty);
BackendNode::sceneChangeEvent(e);
}
@@ -279,39 +297,6 @@ const QMatrix4x4 *Entity::worldTransform() const
return m_nodeManagers->worldMatrixManager()->data(m_worldTransform);
}
-void Entity::addComponent(Qt3DCore::QComponent *component)
-{
- // The backend element is always created when this method is called
- // If that's not the case something has gone wrong
-
- if (qobject_cast<Qt3DCore::QTransform*>(component) != nullptr) {
- m_transformComponent = component->id();
- } else if (qobject_cast<QCameraLens *>(component) != nullptr) {
- m_cameraComponent = component->id();
- } else if (qobject_cast<QLayer *>(component) != nullptr) {
- m_layerComponents.append(component->id());
- } else if (qobject_cast<QLevelOfDetail *>(component) != nullptr) {
- m_levelOfDetailComponents.append(component->id());
- } else if (qobject_cast<QMaterial *>(component) != nullptr) {
- m_materialComponent = component->id();
- } else if (qobject_cast<QAbstractLight *>(component) != nullptr) {
- m_lightComponents.append(component->id());
- } else if (qobject_cast<QEnvironmentLight *>(component) != nullptr) {
- m_environmentLightComponents.append(component->id());
- } else if (qobject_cast<QShaderData *>(component) != nullptr) {
- m_shaderDataComponents.append(component->id());
- } else if (qobject_cast<QGeometryRenderer *>(component) != nullptr) {
- m_geometryRendererComponent = component->id();
- m_boundingDirty = true;
- } else if (qobject_cast<QObjectPicker *>(component) != nullptr) {
- m_objectPickerComponent = component->id();
-// } else if (qobject_cast<QBoundingVolumeDebug *>(component) != nullptr) {
-// m_boundingVolumeDebugComponent = component->id();
- } else if (qobject_cast<QComputeCommand *>(component) != nullptr) {
- m_computeComponent = component->id();
- }
-}
-
void Entity::addComponent(Qt3DCore::QNodeIdTypePair idAndType)
{
// The backend element is always created when this method is called
@@ -344,6 +329,8 @@ void Entity::addComponent(Qt3DCore::QNodeIdTypePair idAndType)
// m_boundingVolumeDebugComponent = id;
} else if (type->inherits(&QComputeCommand::staticMetaObject)) {
m_computeComponent = id;
+ } else if (type->inherits(&QArmature::staticMetaObject)) {
+ m_armatureComponent = id;
}
}
@@ -374,6 +361,8 @@ void Entity::removeComponent(Qt3DCore::QNodeId nodeId)
m_environmentLightComponents.removeAll(nodeId);
} else if (m_computeComponent == nodeId) {
m_computeComponent = QNodeId();
+ } else if (m_armatureComponent == nodeId) {
+ m_armatureComponent = QNodeId();
}
}
@@ -387,231 +376,29 @@ void Entity::unsetBoundingVolumeDirty()
m_boundingDirty = false;
}
-// Handles
-
-template<>
-HMaterial Entity::componentHandle<Material>() const
-{
- return m_nodeManagers->materialManager()->lookupHandle(m_materialComponent);
-}
-
-template<>
-HCamera Entity::componentHandle<CameraLens>() const
-{
- return m_nodeManagers->cameraManager()->lookupHandle(m_cameraComponent);
-}
-
-template<>
-HTransform Entity::componentHandle<Transform>() const
-{
- return m_nodeManagers->transformManager()->lookupHandle(m_transformComponent);
-}
-
-template<>
-HGeometryRenderer Entity::componentHandle<GeometryRenderer>() const
-{
- return m_nodeManagers->geometryRendererManager()->lookupHandle(m_geometryRendererComponent);
-}
-
-template<>
-HObjectPicker Entity::componentHandle<ObjectPicker>() const
-{
- return m_nodeManagers->objectPickerManager()->lookupHandle(m_objectPickerComponent);
-}
-
-template<>
-QVector<HLayer> Entity::componentsHandle<Layer>() const
-{
- QVector<HLayer> layerHandles;
- layerHandles.reserve(m_layerComponents.size());
- for (QNodeId id : m_layerComponents)
- layerHandles.append(m_nodeManagers->layerManager()->lookupHandle(id));
- return layerHandles;
-}
-
-template<>
-QVector<HLevelOfDetail> Entity::componentsHandle<LevelOfDetail>() const
-{
- QVector<HLevelOfDetail> lodHandles;
- lodHandles.reserve(m_levelOfDetailComponents.size());
- for (QNodeId id : m_levelOfDetailComponents)
- lodHandles.append(m_nodeManagers->levelOfDetailManager()->lookupHandle(id));
- return lodHandles;
-}
-
-template<>
-QVector<HShaderData> Entity::componentsHandle<ShaderData>() const
+void Entity::addRecursiveLayerId(const QNodeId layerId)
{
- QVector<HShaderData> shaderDataHandles;
- shaderDataHandles.reserve(m_shaderDataComponents.size());
- for (QNodeId id : m_shaderDataComponents)
- shaderDataHandles.append(m_nodeManagers->shaderDataManager()->lookupHandle(id));
- return shaderDataHandles;
+ if (!m_recursiveLayerComponents.contains(layerId) && !m_layerComponents.contains(layerId))
+ m_recursiveLayerComponents.push_back(layerId);
}
-//template<>
-//HBoundingVolumeDebug Entity::componentHandle<BoundingVolumeDebug>() const
-//{
-// return m_nodeManagers->boundingVolumeDebugManager()->lookupHandle(m_boundingVolumeDebugComponent);
-//}
-
-template<>
-QVector<HLight> Entity::componentsHandle<Light>() const
-{
- QVector<HLight> lightHandles;
- lightHandles.reserve(m_lightComponents.size());
- for (QNodeId id : m_lightComponents)
- lightHandles.append(m_nodeManagers->lightManager()->lookupHandle(id));
- return lightHandles;
-}
-
-template<>
-QVector<HEnvironmentLight> Entity::componentsHandle<EnvironmentLight>() const
-{
- QVector<HEnvironmentLight> lightHandles;
- lightHandles.reserve(m_environmentLightComponents.size());
- for (QNodeId id : m_environmentLightComponents)
- lightHandles.append(m_nodeManagers->environmentLightManager()->lookupHandle(id));
- return lightHandles;
-}
-
-template<>
-HComputeCommand Entity::componentHandle<ComputeCommand>() const
-{
- return m_nodeManagers->computeJobManager()->lookupHandle(m_computeComponent);
-}
-
-// Render components
-
-template<>
-Material *Entity::renderComponent<Material>() const
+void Entity::removeRecursiveLayerId(const QNodeId layerId)
{
- return m_nodeManagers->materialManager()->lookupResource(m_materialComponent);
+ m_recursiveLayerComponents.removeOne(layerId);
}
-template<>
-CameraLens *Entity::renderComponent<CameraLens>() const
-{
- return m_nodeManagers->cameraManager()->lookupResource(m_cameraComponent);
-}
-
-template<>
-Transform *Entity::renderComponent<Transform>() const
-{
- return m_nodeManagers->transformManager()->lookupResource(m_transformComponent);
-}
-
-template<>
-GeometryRenderer *Entity::renderComponent<GeometryRenderer>() const
-{
- return m_nodeManagers->geometryRendererManager()->lookupResource(m_geometryRendererComponent);
-}
-
-template<>
-ObjectPicker *Entity::renderComponent<ObjectPicker>() const
-{
- return m_nodeManagers->objectPickerManager()->lookupResource(m_objectPickerComponent);
-}
-
-template<>
-QVector<Layer *> Entity::renderComponents<Layer>() const
-{
- QVector<Layer *> layers;
- layers.reserve(m_layerComponents.size());
- for (QNodeId id : m_layerComponents)
- layers.append(m_nodeManagers->layerManager()->lookupResource(id));
- return layers;
-}
-
-template<>
-QVector<LevelOfDetail *> Entity::renderComponents<LevelOfDetail>() const
-{
- QVector<LevelOfDetail *> lods;
- lods.reserve(m_levelOfDetailComponents.size());
- for (QNodeId id : m_levelOfDetailComponents)
- lods.append(m_nodeManagers->levelOfDetailManager()->lookupResource(id));
- return lods;
-}
-
-template<>
-QVector<ShaderData *> Entity::renderComponents<ShaderData>() const
-{
- QVector<ShaderData *> shaderDatas;
- shaderDatas.reserve(m_shaderDataComponents.size());
- for (QNodeId id : m_shaderDataComponents)
- shaderDatas.append(m_nodeManagers->shaderDataManager()->lookupResource(id));
- return shaderDatas;
-}
-
-template<>
-QVector<Light *> Entity::renderComponents<Light>() const
-{
- QVector<Light *> lights;
- lights.reserve(m_lightComponents.size());
- for (QNodeId id : m_lightComponents)
- lights.append(m_nodeManagers->lightManager()->lookupResource(id));
- return lights;
-}
-
-template<>
-QVector<EnvironmentLight *> Entity::renderComponents<EnvironmentLight>() const
-{
- QVector<EnvironmentLight *> lights;
- lights.reserve(m_environmentLightComponents.size());
- for (QNodeId id : m_environmentLightComponents)
- lights.append(m_nodeManagers->environmentLightManager()->lookupResource(id));
- return lights;
-}
-
-//template<>
-//BoundingVolumeDebug *Entity::renderComponent<BoundingVolumeDebug>() const
-//{
-// return m_nodeManagers->boundingVolumeDebugManager()->lookupResource(m_boundingVolumeDebugComponent);
-//}
-
-template<>
-ComputeCommand *Entity::renderComponent<ComputeCommand>() const
-{
- return m_nodeManagers->computeJobManager()->lookupResource(m_computeComponent);
-}
-
-// Uuid
-
-template<>
-Qt3DCore::QNodeId Entity::componentUuid<Transform>() const { return m_transformComponent; }
-
-template<>
-Qt3DCore::QNodeId Entity::componentUuid<CameraLens>() const { return m_cameraComponent; }
-
-template<>
-Qt3DCore::QNodeId Entity::componentUuid<Material>() const { return m_materialComponent; }
-
-template<>
-QVector<Qt3DCore::QNodeId> Entity::componentsUuid<Layer>() const { return m_layerComponents; }
-
-template<>
-QVector<Qt3DCore::QNodeId> Entity::componentsUuid<LevelOfDetail>() const { return m_levelOfDetailComponents; }
-
-template<>
-QVector<Qt3DCore::QNodeId> Entity::componentsUuid<ShaderData>() const { return m_shaderDataComponents; }
-
-template<>
-Qt3DCore::QNodeId Entity::componentUuid<GeometryRenderer>() const { return m_geometryRendererComponent; }
-
-template<>
-QNodeId Entity::componentUuid<ObjectPicker>() const { return m_objectPickerComponent; }
-
-template<>
-QNodeId Entity::componentUuid<BoundingVolumeDebug>() const { return m_boundingVolumeDebugComponent; }
-
-template<>
-QNodeId Entity::componentUuid<ComputeCommand>() const { return m_computeComponent; }
-
-template<>
-QVector<Qt3DCore::QNodeId> Entity::componentsUuid<Light>() const { return m_lightComponents; }
-
-template<>
-QVector<Qt3DCore::QNodeId> Entity::componentsUuid<EnvironmentLight>() const { return m_environmentLightComponents; }
+ENTITY_COMPONENT_TEMPLATE_IMPL(Material, HMaterial, MaterialManager, m_materialComponent)
+ENTITY_COMPONENT_TEMPLATE_IMPL(CameraLens, HCamera, CameraManager, m_cameraComponent)
+ENTITY_COMPONENT_TEMPLATE_IMPL(Transform, HTransform, TransformManager, m_transformComponent)
+ENTITY_COMPONENT_TEMPLATE_IMPL(GeometryRenderer, HGeometryRenderer, GeometryRendererManager, m_geometryRendererComponent)
+ENTITY_COMPONENT_TEMPLATE_IMPL(ObjectPicker, HObjectPicker, ObjectPickerManager, m_objectPickerComponent)
+ENTITY_COMPONENT_TEMPLATE_IMPL(ComputeCommand, HComputeCommand, ComputeCommandManager, m_computeComponent)
+ENTITY_COMPONENT_TEMPLATE_IMPL(Armature, HArmature, ArmatureManager, m_armatureComponent)
+ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(Layer, HLayer, LayerManager, m_layerComponents)
+ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(LevelOfDetail, HLevelOfDetail, LevelOfDetailManager, m_levelOfDetailComponents)
+ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(ShaderData, HShaderData, ShaderDataManager, m_shaderDataComponents)
+ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(Light, HLight, LightManager, m_lightComponents)
+ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(EnvironmentLight, HEnvironmentLight, EnvironmentLightManager, m_environmentLightComponents)
RenderEntityFunctor::RenderEntityFunctor(AbstractRenderer *renderer, NodeManagers *manager)
: m_nodeManagers(manager)
diff --git a/src/render/backend/entity_p.h b/src/render/backend/entity_p.h
index 4619314ad..52ad85281 100644
--- a/src/render/backend/entity_p.h
+++ b/src/render/backend/entity_p.h
@@ -110,7 +110,6 @@ public:
Sphere *worldBoundingVolume() const { return m_worldBoundingVolume.data(); }
Sphere *worldBoundingVolumeWithChildren() const { return m_worldBoundingVolumeWithChildren.data(); }
- void addComponent(Qt3DCore::QComponent *component);
void addComponent(Qt3DCore::QNodeIdTypePair idAndType);
void removeComponent(Qt3DCore::QNodeId nodeId);
@@ -120,6 +119,11 @@ public:
void setTreeEnabled(bool enabled) { m_treeEnabled = enabled; }
bool isTreeEnabled() const { return m_treeEnabled; }
+ Qt3DCore::QNodeIdVector layerIds() const { return m_layerComponents + m_recursiveLayerComponents; }
+ void addRecursiveLayerId(const Qt3DCore::QNodeId layerId);
+ void removeRecursiveLayerId(const Qt3DCore::QNodeId layerId);
+ void clearRecursiveLayerIds() { m_recursiveLayerComponents.clear(); }
+
template<class Backend, uint INDEXBITS>
Qt3DCore::QHandle<Backend, INDEXBITS> componentHandle() const
{
@@ -195,6 +199,10 @@ private:
Qt3DCore::QNodeId m_objectPickerComponent;
Qt3DCore::QNodeId m_boundingVolumeDebugComponent;
Qt3DCore::QNodeId m_computeComponent;
+ Qt3DCore::QNodeId m_armatureComponent;
+
+ // Includes recursive layers
+ Qt3DCore::QNodeIdVector m_recursiveLayerComponents;
QString m_objectName;
bool m_boundingDirty;
@@ -202,116 +210,91 @@ private:
bool m_treeEnabled;
};
-// Handles
-template<>
-HMaterial Entity::componentHandle<Material>() const;
-
-template<>
-HCamera Entity::componentHandle<CameraLens>() const;
-
-template<>
-HTransform Entity::componentHandle<Transform>() const;
-
-template<>
-Q_AUTOTEST_EXPORT HGeometryRenderer Entity::componentHandle<GeometryRenderer>() const;
-
-template<>
-Q_AUTOTEST_EXPORT HObjectPicker Entity::componentHandle<ObjectPicker>() const;
-
-template<>
-QVector<HLayer> Entity::componentsHandle<Layer>() const;
-
-template<>
-QVector<HLevelOfDetail> Entity::componentsHandle<LevelOfDetail>() const;
-
-template<>
-QVector<HShaderData> Entity::componentsHandle<ShaderData>() const;
-
-//template<>
-//Q_AUTOTEST_EXPORT HBoundingVolumeDebug Entity::componentHandle<BoundingVolumeDebug>() const;
-
-template<>
-QVector<HLight> Entity::componentsHandle<Light>() const;
-
-template<>
-QVector<HEnvironmentLight> Entity::componentsHandle<EnvironmentLight>() const;
-
-template<>
-Q_AUTOTEST_EXPORT HComputeCommand Entity::componentHandle<ComputeCommand>() const;
-
-// Render components
-template<>
-Material *Entity::renderComponent<Material>() const;
-
-template<>
-CameraLens *Entity::renderComponent<CameraLens>() const;
-
-template<>
-Transform *Entity::renderComponent<Transform>() const;
-
-template<>
-QT3DRENDERSHARED_PRIVATE_EXPORT GeometryRenderer *Entity::renderComponent<GeometryRenderer>() const;
-
-template<>
-QT3DRENDERSHARED_PRIVATE_EXPORT ObjectPicker *Entity::renderComponent<ObjectPicker>() const;
-
-template<>
-QVector<Layer *> Entity::renderComponents<Layer>() const;
-
-template<>
-QVector<LevelOfDetail *> Entity::renderComponents<LevelOfDetail>() const;
-
-template<>
-QVector<ShaderData *> Entity::renderComponents<ShaderData>() const;
-
-//template<>
-//Q_AUTOTEST_EXPORT BoundingVolumeDebug *Entity::renderComponent<BoundingVolumeDebug>() const;
-
-template<>
-QVector<Light *> Entity::renderComponents<Light>() const;
-
-template<>
-QVector<EnvironmentLight *> Entity::renderComponents<EnvironmentLight>() const;
-
-template<>
-Q_AUTOTEST_EXPORT ComputeCommand *Entity::renderComponent<ComputeCommand>() const;
-
-// UUid
-template<>
-Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<Transform>() const;
-
-template<>
-Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<CameraLens>() const;
-
-template<>
-Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<Material>() const;
-
-template<>
-Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<Layer>() const;
-
-template<>
-Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<LevelOfDetail>() const;
-
-template<>
-Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<ShaderData>() const;
-
-template<>
-QT3DRENDERSHARED_PRIVATE_EXPORT Qt3DCore::QNodeId Entity::componentUuid<GeometryRenderer>() const;
-
-template<>
-QT3DRENDERSHARED_PRIVATE_EXPORT Qt3DCore::QNodeId Entity::componentUuid<ObjectPicker>() const;
-
-//template<>
-//Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<BoundingVolumeDebug>() const;
-
-template<>
-Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<ComputeCommand>() const;
+#define ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(Type, Handle) \
+ /* Handle */ \
+ template<> \
+ QT3DRENDERSHARED_PRIVATE_EXPORT Handle Entity::componentHandle<Type>() const; \
+ /* Component */ \
+ template<> \
+ QT3DRENDERSHARED_PRIVATE_EXPORT Type *Entity::renderComponent<Type>() const; \
+ /* Uuid */ \
+ template<> \
+ QT3DRENDERSHARED_PRIVATE_EXPORT Qt3DCore::QNodeId Entity::componentUuid<Type>() const;
+
+
+#define ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(Type, Handle) \
+ /* Handle */ \
+ template<> \
+ QT3DRENDERSHARED_PRIVATE_EXPORT QVector<Handle> Entity::componentsHandle<Type>() const; \
+ /* Component */ \
+ template<> \
+ QT3DRENDERSHARED_PRIVATE_EXPORT QVector<Type *> Entity::renderComponents<Type>() const; \
+ /* Uuid */ \
+ template<> \
+ QT3DRENDERSHARED_PRIVATE_EXPORT Qt3DCore::QNodeIdVector Entity::componentsUuid<Type>() const;
+
+#define ENTITY_COMPONENT_TEMPLATE_IMPL(Type, Handle, Manager, variable) \
+ /* Handle */ \
+ template<> \
+ Handle Entity::componentHandle<Type>() const \
+ { \
+ return m_nodeManagers->lookupHandle<Type, Manager, Handle>(variable); \
+ } \
+ /* Component */ \
+ template<> \
+ Type *Entity::renderComponent<Type>() const \
+ { \
+ return m_nodeManagers->lookupResource<Type, Manager>(variable); \
+ } \
+ /* Uuid */ \
+ template<> \
+ Qt3DCore::QNodeId Entity::componentUuid<Type>() const \
+ { \
+ return variable; \
+ }
-template<>
-Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<Light>() const;
+#define ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(Type, Handle, Manager, variable) \
+ /* Handle */ \
+ template<> \
+ QVector<Handle> Entity::componentsHandle<Type>() const \
+ { \
+ Manager *manager = m_nodeManagers->manager<Type, Manager>(); \
+ QVector<Handle> entries; \
+ entries.reserve(variable.size()); \
+ for (const QNodeId id : variable) \
+ entries.push_back(manager->lookupHandle(id)); \
+ return entries; \
+ } \
+ /* Component */ \
+ template<> \
+ QVector<Type *> Entity::renderComponents<Type>() const \
+ { \
+ Manager *manager = m_nodeManagers->manager<Type, Manager>(); \
+ QVector<Type *> entries; \
+ entries.reserve(variable.size()); \
+ for (const QNodeId id : variable) \
+ entries.push_back(manager->lookupResource(id)); \
+ return entries; \
+ } \
+ /* Uuid */ \
+ template<> \
+ Qt3DCore::QNodeIdVector Entity::componentsUuid<Type>() const \
+ { \
+ return variable; \
+ }
-template<>
-Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<EnvironmentLight>() const;
+ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(Material, HMaterial)
+ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(CameraLens, HCamera)
+ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(Transform, HTransform)
+ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(GeometryRenderer, HGeometryRenderer)
+ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(ObjectPicker, HObjectPicker)
+ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(ComputeCommand, HComputeCommand)
+ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(Armature, HArmature)
+ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(Layer, HLayer)
+ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(LevelOfDetail, HLevelOfDetail)
+ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(ShaderData, HShaderData)
+ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(Light, HLight)
+ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(EnvironmentLight, HEnvironmentLight)
class RenderEntityFunctor : public Qt3DCore::QBackendNodeMapper
{
diff --git a/src/render/backend/frameprofiler_p.h b/src/render/backend/frameprofiler_p.h
index 9e7bcd038..06204a760 100644
--- a/src/render/backend/frameprofiler_p.h
+++ b/src/render/backend/frameprofiler_p.h
@@ -42,6 +42,7 @@
#include <QOpenGLTimeMonitor>
#include <Qt3DCore/private/qthreadpooler_p.h>
+#include <Qt3DCore/private/qt3dcore_global_p.h>
#include <memory>
QT_BEGIN_NAMESPACE
@@ -69,7 +70,7 @@ enum RecordingType
RenderTargetUpdate
};
-#ifdef QT3D_OPENGL_RUN_STATS
+#if QT_CONFIG(qt3d_profile_gl)
class FrameTimeRecorder
{
@@ -218,14 +219,14 @@ public:
explicit GLTimeRecorder(RecordingType type)
: m_type(type)
{
-#ifdef QT3D_OPENGL_RUN_STATS
+#if QT_CONFIG(qt3d_profile_gl)
frameProfiler.startRecordEvent();
#endif
}
~GLTimeRecorder()
{
-#ifdef QT3D_OPENGL_RUN_STATS
+#if QT_CONFIG(qt3d_profile_gl)
frameProfiler.recordEvent(m_type);
#else
Q_UNUSED(m_type);
@@ -234,19 +235,19 @@ public:
static void writeResults()
{
-#ifdef QT3D_OPENGL_RUN_STATS
+#if QT_CONFIG(qt3d_profile_gl)
frameProfiler.writeResults();
#endif
}
private:
-#ifdef QT3D_OPENGL_RUN_STATS
+#if QT_CONFIG(qt3d_profile_gl)
static FrameProfiler frameProfiler;
#endif
RecordingType m_type;
};
-#ifdef QT3D_OPENGL_RUN_STATS
+#if QT_CONFIG(qt3d_profile_gl)
FrameProfiler GLTimeRecorder::frameProfiler;
#endif
diff --git a/src/render/backend/handle_types_p.h b/src/render/backend/handle_types_p.h
index 352519e75..bb5836ab4 100644
--- a/src/render/backend/handle_types_p.h
+++ b/src/render/backend/handle_types_p.h
@@ -70,6 +70,7 @@ class FilterKey;
class Effect;
class Entity;
class Shader;
+class ShaderBuilder;
class FrameGraphNode;
class Layer;
class LevelOfDetail;
@@ -94,6 +95,9 @@ class EnvironmentLight;
class ComputeCommand;
class GLBuffer;
class RenderStateNode;
+class Armature;
+class Skeleton;
+class Joint;
typedef Qt3DCore::QHandle<RenderTargetOutput, 16> HAttachment;
typedef Qt3DCore::QHandle<CameraLens, 8> HCamera;
@@ -107,6 +111,7 @@ typedef Qt3DCore::QHandle<Material, 16> HMaterial;
typedef Qt3DCore::QHandle<QMatrix4x4, 16> HMatrix;
typedef Qt3DCore::QHandle<OpenGLVertexArrayObject, 16> HVao;
typedef Qt3DCore::QHandle<Shader, 16> HShader;
+typedef Qt3DCore::QHandle<ShaderBuilder, 16> HShaderBuilder;
typedef Qt3DCore::QHandle<Technique, 16> HTechnique;
typedef Qt3DCore::QHandle<Texture, 16> HTexture;
typedef Qt3DCore::QHandle<Transform, 16> HTransform;
@@ -127,6 +132,9 @@ typedef Qt3DCore::QHandle<EnvironmentLight, 16> HEnvironmentLight;
typedef Qt3DCore::QHandle<ComputeCommand, 16> HComputeCommand;
typedef Qt3DCore::QHandle<GLBuffer, 16> HGLBuffer;
typedef Qt3DCore::QHandle<RenderStateNode, 16> HRenderState;
+typedef Qt3DCore::QHandle<Armature, 16> HArmature;
+typedef Qt3DCore::QHandle<Skeleton, 16> HSkeleton;
+typedef Qt3DCore::QHandle<Joint, 16> HJoint;
} // namespace Render
diff --git a/src/render/backend/layer.cpp b/src/render/backend/layer.cpp
index 14c0317f8..976c35fd5 100644
--- a/src/render/backend/layer.cpp
+++ b/src/render/backend/layer.cpp
@@ -53,6 +53,7 @@ namespace Render {
Layer::Layer()
: BackendNode()
+ , m_recursive(false)
{
}
@@ -66,6 +67,38 @@ void Layer::cleanup()
QBackendNode::setEnabled(false);
}
+void Layer::sceneChangeEvent(const QSceneChangePtr &e)
+{
+ if (e->type() == PropertyUpdated) {
+ QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
+ QByteArray propertyName = propertyChange->propertyName();
+ if (propertyName == QByteArrayLiteral("recursive")) {
+ m_recursive = propertyChange->value().toBool();
+ markDirty(AbstractRenderer::LayersDirty);
+ }
+ if (propertyName == QByteArrayLiteral("enabled"))
+ markDirty(AbstractRenderer::LayersDirty);
+ }
+ BackendNode::sceneChangeEvent(e);
+}
+
+void Layer::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
+{
+ const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QLayerData>>(change);
+ const auto &data = typedChange->data;
+ m_recursive = data.m_recursive;
+}
+
+bool Layer::recursive() const
+{
+ return m_recursive;
+}
+
+void Layer::setRecursive(bool recursive)
+{
+ m_recursive = recursive;
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/layer_p.h b/src/render/backend/layer_p.h
index b6a78a1cf..d01d190e9 100644
--- a/src/render/backend/layer_p.h
+++ b/src/render/backend/layer_p.h
@@ -71,6 +71,17 @@ public:
Layer();
~Layer();
void cleanup();
+
+ // QBackendNode interface
+ bool recursive() const;
+ void setRecursive(bool recursive);
+
+protected:
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change);
+ bool m_recursive;
};
} // namespace Render
diff --git a/src/render/backend/managers.cpp b/src/render/backend/managers.cpp
index 844a44286..6e8c1376d 100644
--- a/src/render/backend/managers.cpp
+++ b/src/render/backend/managers.cpp
@@ -75,6 +75,42 @@ void FrameGraphManager::releaseNode(Qt3DCore::QNodeId id)
delete m_nodes.take(id);
}
+void SkeletonManager::addDirtySkeleton(DirtyFlag dirtyFlag, HSkeleton skeletonHandle)
+{
+ switch (dirtyFlag) {
+ case SkeletonDataDirty:
+ m_dirtyDataSkeletons.push_back(skeletonHandle);
+ break;
+
+ case SkeletonTransformsDirty:
+ m_dirtyTransformSkeletons.push_back(skeletonHandle);
+ break;
+ }
+}
+
+QVector<HSkeleton> SkeletonManager::dirtySkeletons(DirtyFlag dirtyFlag)
+{
+ switch (dirtyFlag) {
+ case SkeletonDataDirty:
+ return std::move(m_dirtyDataSkeletons);
+
+ case SkeletonTransformsDirty:
+ return std::move(m_dirtyTransformSkeletons);
+ }
+ return QVector<HSkeleton>();
+}
+
+void JointManager::addDirtyJoint(Qt3DCore::QNodeId jointId)
+{
+ const HJoint jointHandle = lookupHandle(jointId);
+ m_dirtyJoints.push_back(jointHandle);
+}
+
+QVector<HJoint> JointManager::dirtyJoints()
+{
+ return std::move(m_dirtyJoints);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h
index c5af93b8d..f19b9261a 100644
--- a/src/render/backend/managers_p.h
+++ b/src/render/backend/managers_p.h
@@ -61,6 +61,7 @@
#include <Qt3DRender/private/levelofdetail_p.h>
#include <Qt3DRender/private/material_p.h>
#include <Qt3DRender/private/shader_p.h>
+#include <Qt3DRender/private/shaderbuilder_p.h>
#include <Qt3DRender/private/texture_p.h>
#include <Qt3DRender/private/transform_p.h>
#include <Qt3DRender/private/rendertarget_p.h>
@@ -79,6 +80,9 @@
#include <Qt3DRender/private/light_p.h>
#include <Qt3DRender/private/environmentlight_p.h>
#include <Qt3DRender/private/computecommand_p.h>
+#include <Qt3DRender/private/armature_p.h>
+#include <Qt3DRender/private/skeleton_p.h>
+#include <Qt3DRender/private/joint_p.h>
QT_BEGIN_NAMESPACE
@@ -211,6 +215,16 @@ public:
ShaderManager() {}
};
+class ShaderBuilderManager : public Qt3DCore::QResourceManager<
+ ShaderBuilder,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::NonLockingPolicy>
+{
+public:
+ ShaderBuilderManager() {}
+};
+
class TextureManager : public Qt3DCore::QResourceManager<
Texture,
Qt3DCore::QNodeId,
@@ -385,6 +399,48 @@ class RenderStateManager : public Qt3DCore::QResourceManager<
{
};
+class ArmatureManager : public Qt3DCore::QResourceManager<
+ Armature,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::NonLockingPolicy>
+{
+};
+
+class SkeletonManager : public Qt3DCore::QResourceManager<
+ Skeleton,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::NonLockingPolicy>
+{
+public:
+ enum DirtyFlag {
+ SkeletonDataDirty,
+ SkeletonTransformsDirty
+ };
+
+ void addDirtySkeleton(DirtyFlag dirtyFlag, HSkeleton skeletonHandle);
+ QVector<HSkeleton> dirtySkeletons(DirtyFlag dirtyFlag);
+
+private:
+ QVector<HSkeleton> m_dirtyDataSkeletons;
+ QVector<HSkeleton> m_dirtyTransformSkeletons;
+};
+
+class JointManager : public Qt3DCore::QResourceManager<
+ Joint,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::NonLockingPolicy>
+{
+public:
+ void addDirtyJoint(Qt3DCore::QNodeId jointId);
+ QVector<HJoint> dirtyJoints();
+
+private:
+ QVector<HJoint> m_dirtyJoints;
+};
+
} // namespace Render
} // namespace Qt3DRender
@@ -406,6 +462,9 @@ Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::ComputeCommand, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Parameter, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Transform, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::OpenGLVertexArrayObject, Q_REQUIRES_CLEANUP)
+Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Armature, Q_REQUIRES_CLEANUP)
+Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Skeleton, Q_REQUIRES_CLEANUP)
+Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Joint, Q_REQUIRES_CLEANUP)
QT_END_NAMESPACE
diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp
index 80d0562b0..f5de64dae 100644
--- a/src/render/backend/nodemanagers.cpp
+++ b/src/render/backend/nodemanagers.cpp
@@ -46,6 +46,8 @@
#include <Qt3DRender/private/texturedatamanager_p.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
#include <Qt3DRender/private/techniquemanager_p.h>
+#include <Qt3DRender/private/armature_p.h>
+#include <Qt3DRender/private/skeleton_p.h>
#include <private/resourceaccessor_p.h>
#include <QOpenGLVertexArrayObject>
@@ -63,6 +65,7 @@ NodeManagers::NodeManagers()
, m_worldMatrixManager(new MatrixManager())
, m_vaoManager(new VAOManager())
, m_shaderManager(new ShaderManager())
+ , m_shaderBuilderManager(new ShaderBuilderManager())
, m_techniqueManager(new TechniqueManager())
, m_effectManager(new EffectManager())
, m_renderPassManager(new RenderPassManager())
@@ -92,6 +95,9 @@ NodeManagers::NodeManagers()
, m_environmentLightManager(new EnvironmentLightManager())
, m_computeJobManager(new ComputeCommandManager())
, m_renderStateManager(new RenderStateManager())
+ , m_armatureManager(new ArmatureManager())
+ , m_skeletonManager(new SkeletonManager())
+ , m_jointManager(new JointManager())
, m_resourceAccessor(new ResourceAccessor(this))
{
}
@@ -103,6 +109,7 @@ NodeManagers::~NodeManagers()
delete m_worldMatrixManager;
delete m_vaoManager;
delete m_shaderManager;
+ delete m_shaderBuilderManager;
delete m_techniqueManager;
delete m_effectManager;
delete m_renderPassManager;
@@ -136,6 +143,9 @@ NodeManagers::~NodeManagers()
delete m_computeJobManager;
delete m_renderStateManager;
delete m_renderNodesManager;
+ delete m_armatureManager;
+ delete m_skeletonManager;
+ delete m_jointManager;
}
QSharedPointer<ResourceAccessor> NodeManagers::resourceAccessor()
@@ -180,6 +190,12 @@ ShaderManager *NodeManagers::manager<Shader>() const Q_DECL_NOTHROW
}
template<>
+ShaderBuilderManager *NodeManagers::manager<ShaderBuilder>() const Q_DECL_NOTHROW
+{
+ return m_shaderBuilderManager;
+}
+
+template<>
TechniqueManager *NodeManagers::manager<Technique>() const Q_DECL_NOTHROW
{
return m_techniqueManager;
@@ -341,6 +357,24 @@ RenderStateManager *NodeManagers::manager<RenderStateNode>() const Q_DECL_NOTHRO
return m_renderStateManager;
}
+template<>
+ArmatureManager *NodeManagers::manager<Armature>() const Q_DECL_NOTHROW
+{
+ return m_armatureManager;
+}
+
+template<>
+SkeletonManager *NodeManagers::manager<Skeleton>() const Q_DECL_NOTHROW
+{
+ return m_skeletonManager;
+}
+
+template<>
+JointManager *NodeManagers::manager<Joint>() const Q_DECL_NOTHROW
+{
+ return m_jointManager;
+}
+
} // Render
} // Qt3DRender
diff --git a/src/render/backend/nodemanagers_p.h b/src/render/backend/nodemanagers_p.h
index 9e913eec4..6052c82d0 100644
--- a/src/render/backend/nodemanagers_p.h
+++ b/src/render/backend/nodemanagers_p.h
@@ -76,6 +76,7 @@ class MaterialManager;
class MatrixManager;
class VAOManager;
class ShaderManager;
+class ShaderBuilderManager;
class TechniqueManager;
class EffectManager;
class RenderPassManager;
@@ -99,12 +100,16 @@ class LightManager;
class EnvironmentLightManager;
class ComputeCommandManager;
class RenderStateManager;
+class ArmatureManager;
+class SkeletonManager;
+class JointManager;
class FrameGraphNode;
class Entity;
class CameraLens;
class Material;
class Shader;
+class ShaderBuilder;
class Technique;
class Effect;
class RenderPass;
@@ -131,6 +136,9 @@ class Light;
class EnvironmentLight;
class ComputeCommand;
class RenderStateNode;
+class Armature;
+class Skeleton;
+class Joint;
class OpenGLVertexArrayObject;
class ResourceAccessor;
@@ -181,6 +189,7 @@ public:
inline MatrixManager *worldMatrixManager() const Q_DECL_NOEXCEPT { return m_worldMatrixManager; }
inline VAOManager *vaoManager() const Q_DECL_NOEXCEPT { return m_vaoManager; }
inline ShaderManager *shaderManager() const Q_DECL_NOEXCEPT { return m_shaderManager; }
+ inline ShaderBuilderManager *shaderBuilderManager() const Q_DECL_NOEXCEPT { return m_shaderBuilderManager; }
inline TechniqueManager *techniqueManager() const Q_DECL_NOEXCEPT { return m_techniqueManager; }
inline EffectManager *effectManager() const Q_DECL_NOEXCEPT { return m_effectManager; }
inline RenderPassManager *renderPassManager() const Q_DECL_NOEXCEPT { return m_renderPassManager; }
@@ -210,6 +219,9 @@ public:
inline EnvironmentLightManager *environmentLightManager() const Q_DECL_NOEXCEPT { return m_environmentLightManager; }
inline ComputeCommandManager *computeJobManager() const Q_DECL_NOEXCEPT { return m_computeJobManager; }
inline RenderStateManager *renderStateManager() const Q_DECL_NOEXCEPT { return m_renderStateManager; }
+ inline ArmatureManager *armatureManager() const Q_DECL_NOEXCEPT { return m_armatureManager; }
+ inline SkeletonManager *skeletonManager() const Q_DECL_NOEXCEPT { return m_skeletonManager; }
+ inline JointManager *jointManager() const Q_DECL_NOEXCEPT { return m_jointManager; }
QSharedPointer<ResourceAccessor> resourceAccessor();
@@ -220,6 +232,7 @@ private:
MatrixManager *m_worldMatrixManager;
VAOManager *m_vaoManager;
ShaderManager *m_shaderManager;
+ ShaderBuilderManager *m_shaderBuilderManager;
TechniqueManager *m_techniqueManager;
EffectManager *m_effectManager;
RenderPassManager *m_renderPassManager;
@@ -249,6 +262,9 @@ private:
EnvironmentLightManager *m_environmentLightManager;
ComputeCommandManager *m_computeJobManager;
RenderStateManager *m_renderStateManager;
+ ArmatureManager *m_armatureManager;
+ SkeletonManager *m_skeletonManager;
+ JointManager *m_jointManager;
QSharedPointer<ResourceAccessor> m_resourceAccessor;
};
@@ -274,6 +290,9 @@ template<>
QT3DRENDERSHARED_PRIVATE_EXPORT ShaderManager *NodeManagers::manager<Shader>() const Q_DECL_NOEXCEPT;
template<>
+QT3DRENDERSHARED_PRIVATE_EXPORT ShaderBuilderManager *NodeManagers::manager<ShaderBuilder>() const Q_DECL_NOEXCEPT;
+
+template<>
QT3DRENDERSHARED_PRIVATE_EXPORT TechniqueManager *NodeManagers::manager<Technique>() const Q_DECL_NOEXCEPT;
template<>
@@ -354,6 +373,15 @@ QT3DRENDERSHARED_PRIVATE_EXPORT ComputeCommandManager *NodeManagers::manager<Com
template<>
QT3DRENDERSHARED_PRIVATE_EXPORT RenderStateManager *NodeManagers::manager<RenderStateNode>() const Q_DECL_NOEXCEPT;
+template<>
+QT3DRENDERSHARED_PRIVATE_EXPORT ArmatureManager *NodeManagers::manager<Armature>() const Q_DECL_NOEXCEPT;
+
+template<>
+QT3DRENDERSHARED_PRIVATE_EXPORT SkeletonManager *NodeManagers::manager<Skeleton>() const Q_DECL_NOEXCEPT;
+
+template<>
+QT3DRENDERSHARED_PRIVATE_EXPORT JointManager *NodeManagers::manager<Joint>() const Q_DECL_NOEXCEPT;
+
} // Render
} // Qt3DRender
diff --git a/src/render/backend/pointsvisitor.cpp b/src/render/backend/pointsvisitor.cpp
new file mode 100644
index 000000000..663488357
--- /dev/null
+++ b/src/render/backend/pointsvisitor.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** 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 "pointsvisitor_p.h"
+#include <Qt3DCore/qentity.h>
+#include <Qt3DRender/qgeometryrenderer.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/buffermanager_p.h>
+#include <Qt3DRender/private/geometryrenderer_p.h>
+#include <Qt3DRender/private/geometryrenderermanager_p.h>
+#include <Qt3DRender/private/geometry_p.h>
+#include <Qt3DRender/private/attribute_p.h>
+#include <Qt3DRender/private/buffer_p.h>
+#include <Qt3DRender/private/trianglesvisitor_p.h>
+#include <Qt3DRender/private/visitorutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+namespace {
+
+// indices, vertices are already offset
+template<typename Index, typename Vertex>
+void traverseCoordinatesIndexed(Index *indices,
+ Vertex *vertices,
+ const BufferInfo &indexInfo,
+ const BufferInfo &vertexInfo,
+ PointsVisitor *visitor)
+{
+ uint i = 0;
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx;
+ QVector3D abc;
+ while (i < indexInfo.count) {
+ ndx = indices[i];
+ const uint idx = ndx * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[j] = vertices[idx + j];
+ }
+ visitor->visit(ndx, abc);
+ ++i;
+ }
+}
+
+// vertices are already offset
+template<typename Vertex>
+void traverseCoordinates(Vertex *vertices,
+ const BufferInfo &vertexInfo,
+ PointsVisitor *visitor)
+{
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx = 0;
+ QVector3D abc;
+ while (ndx < vertexInfo.count) {
+ const uint idx = ndx * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[j] = vertices[idx + j];
+ visitor->visit(ndx, abc);
+ ++ndx;
+ }
+}
+
+template<typename Index, typename Visitor>
+struct IndexedVertexExecutor
+{
+ template<typename Vertex>
+ void operator ()(const BufferInfo &vertexInfo, Vertex * vertices)
+ {
+ traverseCoordinatesIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
+ }
+
+ BufferInfo m_indexBufferInfo;
+ Index *m_indices;
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
+};
+
+template<typename Visitor>
+struct IndexExecutor
+{
+ template<typename Index>
+ void operator ()( const BufferInfo &indexInfo, Index *indices)
+ {
+ IndexedVertexExecutor<Index, Visitor> exec;
+ exec.m_primitiveType = m_primitiveType;
+ exec.m_indices = indices;
+ exec.m_indexBufferInfo = indexInfo;
+ exec.m_visitor = m_visitor;
+ Qt3DRender::Render::Visitor::processBuffer(m_vertexBufferInfo, exec);
+ }
+
+ BufferInfo m_vertexBufferInfo;
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
+};
+
+template<typename Visitor>
+struct VertexExecutor
+{
+ template<typename Vertex>
+ void operator ()(const BufferInfo &vertexInfo, Vertex *vertices)
+ {
+ switch (m_primitiveType) {
+ case Qt3DRender::QGeometryRenderer::Points:
+ traverseCoordinates(vertices, vertexInfo, m_visitor);
+ return;
+ default:
+ Q_UNREACHABLE();
+ return;
+ }
+ }
+
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
+};
+
+} // anonymous
+
+
+PointsVisitor::~PointsVisitor()
+{
+
+}
+
+void PointsVisitor::apply(const Qt3DCore::QEntity *entity)
+{
+ GeometryRenderer *renderer = m_manager->geometryRendererManager()->lookupResource(entity->id());
+ apply(renderer, entity->id());
+}
+
+void PointsVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id)
+{
+ m_nodeId = id;
+ if (renderer && renderer->instanceCount() == 1) {
+ Visitor::visitPrimitives<VertexExecutor<PointsVisitor>,
+ IndexExecutor<PointsVisitor>, PointsVisitor>(m_manager, renderer, this);
+ }
+}
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/pointsvisitor_p.h b/src/render/backend/pointsvisitor_p.h
new file mode 100644
index 000000000..9d44ffec5
--- /dev/null
+++ b/src/render/backend/pointsvisitor_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** 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 QT3DRENDER_RENDER_COORDINATESVISITOR_P_H
+#define QT3DRENDER_RENDER_COORDINATESVISITOR_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 <Qt3DCore/qnodeid.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+class QEntity;
+}
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class GeometryRenderer;
+class NodeManagers;
+
+class Q_AUTOTEST_EXPORT PointsVisitor
+{
+public:
+ explicit PointsVisitor(NodeManagers *manager) : m_manager(manager) { }
+ virtual ~PointsVisitor();
+
+ void apply(const Qt3DCore::QEntity *entity);
+ void apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id);
+
+ virtual void visit(uint ndx, const QVector3D &c) = 0;
+
+protected:
+ NodeManagers *m_manager;
+ Qt3DCore::QNodeId m_nodeId;
+};
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+
+#endif // QT3DRENDER_RENDER_COORDINATESVISITOR_P_H
diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri
index 5d515a173..f7f30b5c9 100644
--- a/src/render/backend/render-backend.pri
+++ b/src/render/backend/render-backend.pri
@@ -41,7 +41,11 @@ HEADERS += \
$$PWD/frameprofiler_p.h \
$$PWD/offscreensurfacehelper_p.h \
$$PWD/resourceaccessor_p.h \
- $$PWD/commandthread_p.h
+ $$PWD/commandthread_p.h \
+ $$PWD/visitorutils_p.h \
+ $$PWD/segmentsvisitor_p.h \
+ $$PWD/pointsvisitor_p.h \
+ $$PWD/renderercache_p.h
SOURCES += \
$$PWD/renderthread.cpp \
@@ -76,12 +80,13 @@ SOURCES += \
$$PWD/renderviewbuilder.cpp \
$$PWD/offscreensurfacehelper.cpp \
$$PWD/resourceaccessor.cpp \
- $$PWD/commandthread.cpp
+ $$PWD/segmentsvisitor.cpp \
+ $$PWD/commandthread.cpp \
+ $$PWD/pointsvisitor.cpp
-include($$OUT_PWD/../core/qt3dcore-config.pri)
+include($$QT3D_BUILD_ROOT/src/core/qt3dcore-config.pri)
QT_FOR_CONFIG += 3dcore-private
qtConfig(qt3d-profile-jobs): {
HEADERS += $$PWD/commandexecuter_p.h
SOURCES += $$PWD/commandexecuter.cpp
}
-
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp
index 19cc97dc5..7830faaa9 100644
--- a/src/render/backend/renderer.cpp
+++ b/src/render/backend/renderer.cpp
@@ -64,10 +64,12 @@
#include <Qt3DRender/private/renderqueue_p.h>
#include <Qt3DRender/private/shader_p.h>
#include <Qt3DRender/private/buffer_p.h>
+#include <Qt3DRender/private/glbuffer_p.h>
#include <Qt3DRender/private/renderstateset_p.h>
#include <Qt3DRender/private/technique_p.h>
#include <Qt3DRender/private/renderthread_p.h>
#include <Qt3DRender/private/renderview_p.h>
+#include <Qt3DRender/private/scenemanager_p.h>
#include <Qt3DRender/private/techniquefilternode_p.h>
#include <Qt3DRender/private/viewportnode_p.h>
#include <Qt3DRender/private/vsyncframeadvanceservice_p.h>
@@ -89,12 +91,11 @@
#include <Qt3DRender/private/renderviewbuilder_p.h>
#include <Qt3DRender/qcameralens.h>
-#include <Qt3DCore/qt3dcore-config.h>
#include <Qt3DCore/private/qeventfilterservice_p.h>
#include <Qt3DCore/private/qabstractaspectjobmanager_p.h>
#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
-#if defined(QT3D_JOBS_RUN_STATS)
+#if QT_CONFIG(qt3d_profile_jobs)
#include <Qt3DCore/private/aspectcommanddebugger_p.h>
#endif
@@ -115,7 +116,7 @@
#include <QThread>
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
#include <Qt3DCore/private/qthreadpooler_p.h>
#include <Qt3DRender/private/job_common_p.h>
#include <Qt3DRender/private/commandexecuter_p.h>
@@ -177,6 +178,7 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_updateTreeEnabledJob(Render::UpdateTreeEnabledJobPtr::create())
, m_sendRenderCaptureJob(Render::SendRenderCaptureJobPtr::create(this))
, m_sendBufferCaptureJob(Render::SendBufferCaptureJobPtr::create())
+ , m_updateSkinningPaletteJob(Render::UpdateSkinningPaletteJobPtr::create())
, m_updateLevelOfDetailJob(Render::UpdateLevelOfDetailJobPtr::create())
, m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create())
, m_filterCompatibleTechniqueJob(Render::FilterCompatibleTechniqueJobPtr::create())
@@ -187,7 +189,7 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_syncTextureLoadingJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([] {}, JobTypes::SyncTextureLoading))
, m_ownedContext(false)
, m_offscreenHelper(nullptr)
- #ifdef QT3D_JOBS_RUN_STATS
+ #if QT_CONFIG(qt3d_profile_jobs)
, m_commandExecuter(new Qt3DRender::Debug::CommandExecuter(this))
#endif
{
@@ -209,6 +211,9 @@ Renderer::Renderer(QRenderAspect::RenderType type)
// m_syncTextureLoadingJob will depend on the texture loading jobs
m_textureGathererJob->addDependency(m_syncTextureLoadingJob);
+ // Ensures all skeletons are loaded before we try to update them
+ m_updateSkinningPaletteJob->addDependency(m_syncTextureLoadingJob);
+
// All world stuff depends on the RenderEntity's localBoundingVolume
m_updateLevelOfDetailJob->addDependency(m_updateMeshTriangleListJob);
m_pickBoundingVolumeJob->addDependency(m_updateMeshTriangleListJob);
@@ -275,10 +280,18 @@ void Renderer::setNodeManagers(NodeManagers *managers)
m_sendRenderCaptureJob->setManagers(m_nodesManager);
m_sendBufferCaptureJob->setManagers(m_nodesManager);
m_updateLevelOfDetailJob->setManagers(m_nodesManager);
+ m_updateSkinningPaletteJob->setManagers(m_nodesManager);
m_updateMeshTriangleListJob->setManagers(m_nodesManager);
m_filterCompatibleTechniqueJob->setManager(m_nodesManager->techniqueManager());
}
+void Renderer::setServices(QServiceLocator *services)
+{
+ m_services = services;
+
+ m_nodesManager->sceneManager()->setDownloadService(m_services->downloadHelperService());
+}
+
NodeManagers *Renderer::nodeManagers() const
{
return m_nodesManager;
@@ -497,7 +510,11 @@ void Renderer::setSceneRoot(QBackendNodeFactory *factory, Entity *sgRoot)
m_cleanupJob->setRoot(m_renderSceneRoot);
m_pickBoundingVolumeJob->setRoot(m_renderSceneRoot);
m_updateLevelOfDetailJob->setRoot(m_renderSceneRoot);
+ m_updateSkinningPaletteJob->setRoot(m_renderSceneRoot);
m_updateTreeEnabledJob->setRoot(m_renderSceneRoot);
+
+ // Set all flags to dirty
+ m_changeSet |= AbstractRenderer::AllDirty;
}
void Renderer::registerEventFilter(QEventFilterService *service)
@@ -548,7 +565,7 @@ void Renderer::doRender()
const bool canSubmit = isReadyToSubmit();
// Lock the mutex to protect access to the renderQueue while we look for its state
- QMutexLocker locker(&m_renderQueueMutex);
+ QMutexLocker locker(m_renderQueue->mutex());
const bool queueIsComplete = m_renderQueue->isFrameQueueComplete();
const bool queueIsEmpty = m_renderQueue->targetRenderViewCount() == 0;
@@ -563,7 +580,7 @@ void Renderer::doRender()
if (canSubmit && (queueIsComplete && !queueIsEmpty)) {
const QVector<Render::RenderView *> renderViews = m_renderQueue->nextFrameQueue();
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
// Save start of frame
JobRunStats submissionStatsPart1;
JobRunStats submissionStatsPart2;
@@ -575,14 +592,8 @@ void Renderer::doRender()
submissionStatsPart2.jobId.typeAndInstance[1] = 0;
submissionStatsPart2.threadId = reinterpret_cast<quint64>(QThread::currentThreadId());
#endif
- if (canRender()) {
- // Clear all dirty flags but Compute so that
- // we still render every frame when a compute shader is used in a scene
- BackendNodeDirtySet changesToUnset = m_changeSet;
- if (changesToUnset.testFlag(Renderer::ComputeDirty))
- changesToUnset.setFlag(Renderer::ComputeDirty, false);
- clearDirtyBits(changesToUnset);
+ if (canRender()) {
{ // Scoped to destroy surfaceLock
QSurface *surface = nullptr;
for (const Render::RenderView *rv: renderViews) {
@@ -613,7 +624,7 @@ void Renderer::doRender()
m_vsyncFrameAdvanceService->proceedToNextFrame();
hasCleanedQueueAndProceeded = true;
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
if (preprocessingComplete) {
submissionStatsPart2.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
submissionStatsPart1.endTime = submissionStatsPart2.startTime;
@@ -631,7 +642,7 @@ void Renderer::doRender()
}
}
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
// Execute the pending shell commands
m_commandExecuter->performAsynchronousCommandExecution(renderViews);
#endif
@@ -640,7 +651,7 @@ void Renderer::doRender()
// that were used for their allocation
qDeleteAll(renderViews);
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
if (preprocessingComplete) {
// Save submission elapsed time
submissionStatsPart2.endTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
@@ -694,7 +705,7 @@ void Renderer::doRender()
// we allow the render thread to proceed
void Renderer::enqueueRenderView(Render::RenderView *renderView, int submitOrder)
{
- QMutexLocker locker(&m_renderQueueMutex); // Prevent out of order execution
+ QMutexLocker locker(m_renderQueue->mutex()); // Prevent out of order execution
// We cannot use a lock free primitive here because:
// - QVector is not thread safe
// - Even if the insert is made correctly, the isFrameComplete call
@@ -712,8 +723,7 @@ void Renderer::enqueueRenderView(Render::RenderView *renderView, int submitOrder
bool Renderer::canRender() const
{
- // Make sure that we've not been told to terminate whilst waiting on
- // the above wait condition
+ // Make sure that we've not been told to terminate
if (m_renderThread && !m_running.load()) {
qCDebug(Rendering) << "RenderThread termination requested whilst waiting";
return false;
@@ -749,7 +759,7 @@ bool Renderer::isReadyToSubmit()
// Main thread
QVariant Renderer::executeCommand(const QStringList &args)
{
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
return m_commandExecuter->executeCommand(args);
#else
Q_UNUSED(args);
@@ -878,7 +888,7 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
// Update the draw command with all the information required for the drawing
if (command->m_drawIndexed) {
command->m_indexAttributeDataType = GraphicsContext::glDataTypeFromAttributeDataType(indexAttribute->vertexBaseType());
- command->m_indexAttributeByteOffset = indexAttribute->byteOffset();
+ command->m_indexAttributeByteOffset = indexAttribute->byteOffset() + rGeometryRenderer->indexBufferByteOffset();
}
// Note: we only care about the primitiveCount when using direct draw calls
@@ -991,6 +1001,7 @@ void Renderer::lookForDirtyShaders()
{
if (isRunning()) {
const QVector<HTechnique> activeTechniques = m_nodesManager->techniqueManager()->activeHandles();
+ const QVector<HShaderBuilder> activeBuilders = m_nodesManager->shaderBuilderManager()->activeHandles();
for (HTechnique techniqueHandle : activeTechniques) {
Technique *technique = m_nodesManager->techniqueManager()->data(techniqueHandle);
// If api of the renderer matches the one from the technique
@@ -1000,6 +1011,55 @@ void Renderer::lookForDirtyShaders()
RenderPass *renderPass = m_nodesManager->renderPassManager()->lookupResource(passId);
HShader shaderHandle = m_nodesManager->shaderManager()->lookupHandle(renderPass->shaderProgram());
Shader *shader = m_nodesManager->shaderManager()->data(shaderHandle);
+
+ ShaderBuilder *shaderBuilder = nullptr;
+ for (HShaderBuilder builderHandle : activeBuilders) {
+ ShaderBuilder *builder = m_nodesManager->shaderBuilderManager()->data(builderHandle);
+ if (builder->shaderProgramId() == shader->peerId()) {
+ shaderBuilder = builder;
+ break;
+ }
+ }
+
+ if (shaderBuilder) {
+ shaderBuilder->setGraphicsApi(*technique->graphicsApiFilter());
+
+ for (int i = 0; i <= ShaderBuilder::Compute; i++) {
+ const auto builderType = static_cast<ShaderBuilder::ShaderType>(i);
+ if (!shaderBuilder->shaderGraph(builderType).isValid())
+ continue;
+
+ if (shaderBuilder->isShaderCodeDirty(builderType)) {
+ shaderBuilder->generateCode(builderType);
+ }
+
+ QShaderProgram::ShaderType shaderType = QShaderProgram::Vertex;
+ switch (builderType) {
+ case ShaderBuilder::Vertex:
+ shaderType = QShaderProgram::Vertex;
+ break;
+ case ShaderBuilder::TessellationControl:
+ shaderType = QShaderProgram::TessellationControl;
+ break;
+ case ShaderBuilder::TessellationEvaluation:
+ shaderType = QShaderProgram::TessellationEvaluation;
+ break;
+ case ShaderBuilder::Geometry:
+ shaderType = QShaderProgram::Geometry;
+ break;
+ case ShaderBuilder::Fragment:
+ shaderType = QShaderProgram::Fragment;
+ break;
+ case ShaderBuilder::Compute:
+ shaderType = QShaderProgram::Compute;
+ break;
+ }
+
+ const auto code = shaderBuilder->shaderCode(builderType);
+ shader->setShaderCode(shaderType, code);
+ }
+ }
+
if (Q_UNLIKELY(shader->hasPendingNotifications()))
shader->submitPendingNotifications();
if (shader != nullptr && !shader->isLoaded())
@@ -1019,8 +1079,9 @@ void Renderer::updateGLResources()
for (HBuffer handle: dirtyBufferHandles) {
Buffer *buffer = m_nodesManager->bufferManager()->data(handle);
// Forces creation if it doesn't exit
+ // Also note the binding point doesn't really matter here, we just upload data
if (!m_graphicsContext->hasGLBufferForBuffer(buffer))
- m_graphicsContext->glBufferForRenderBuffer(buffer);
+ m_graphicsContext->glBufferForRenderBuffer(buffer, GLBuffer::ArrayBuffer);
// Update the glBuffer data
m_graphicsContext->updateBuffer(buffer);
buffer->unsetDirty();
@@ -1168,7 +1229,6 @@ void Renderer::downloadGLBuffers()
}
}
-
// Happens in RenderThread context when all RenderViewJobs are done
// Returns the id of the last bound FBO
Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Render::RenderView *> &renderViews)
@@ -1298,19 +1358,44 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
// of gc->currentContext() at the moment it was called (either
// renderViewStateSet or m_defaultRenderStateSet)
if (!renderView->renderCaptureNodeId().isNull()) {
+ const QRenderCaptureRequest request = renderView->renderCaptureRequest();
const QSize size = m_graphicsContext->renderTargetSize(renderView->surfaceSize() * renderView->devicePixelRatio());
- // Bind fbo as read framebuffer
- m_graphicsContext->bindFramebuffer(m_graphicsContext->activeFBO(), GraphicsHelperInterface::FBORead);
- const QImage image = m_graphicsContext->readFramebuffer(size);
+ QRect rect(QPoint(0, 0), size);
+ if (!request.rect.isEmpty())
+ rect = rect.intersected(request.rect);
+ QImage image;
+ if (!rect.isEmpty()) {
+ // Bind fbo as read framebuffer
+ m_graphicsContext->bindFramebuffer(m_graphicsContext->activeFBO(), GraphicsHelperInterface::FBORead);
+ image = m_graphicsContext->readFramebuffer(rect);
+ } else {
+ qWarning() << "Requested capture rectangle is outside framebuffer";
+ }
Render::RenderCapture *renderCapture =
static_cast<Render::RenderCapture*>(m_nodesManager->frameGraphManager()->lookupNode(renderView->renderCaptureNodeId()));
- renderCapture->addRenderCapture(image);
+ renderCapture->addRenderCapture(request.captureId, image);
addRenderCaptureSendRequest(renderView->renderCaptureNodeId());
}
if (renderView->isDownloadBuffersEnable())
downloadGLBuffers();
+ // Perform BlitFramebuffer operations
+ if (renderView->hasBlitFramebufferInfo()) {
+ const auto &blitFramebufferInfo = renderView->blitFrameBufferInfo();
+ const QNodeId inputTargetId = blitFramebufferInfo.sourceRenderTargetId;
+ const QNodeId outputTargetId = blitFramebufferInfo.destinationRenderTargetId;
+ const QRect inputRect = blitFramebufferInfo.sourceRect;
+ const QRect outputRect = blitFramebufferInfo.destinationRect;
+ const QRenderTargetOutput::AttachmentPoint inputAttachmentPoint = blitFramebufferInfo.sourceAttachmentPoint;
+ const QRenderTargetOutput::AttachmentPoint outputAttachmentPoint = blitFramebufferInfo.destinationAttachmentPoint;
+ const QBlitFramebuffer::InterpolationMethod interpolationMethod = blitFramebufferInfo.interpolationMethod;
+ m_graphicsContext->blitFramebuffer(inputTargetId, outputTargetId, inputRect, outputRect, lastBoundFBOId,
+ inputAttachmentPoint, outputAttachmentPoint,
+ interpolationMethod);
+ }
+
+
frameElapsed = timer.elapsed() - frameElapsed;
qCDebug(Rendering) << Q_FUNC_INFO << "Submitted Renderview " << i + 1 << "/" << renderViewsCount << "in " << frameElapsed << "ms";
frameElapsed = timer.elapsed();
@@ -1398,22 +1483,35 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
m_calculateBoundingVolumeJob->addDependency(bufferJob);
m_updateLevelOfDetailJob->setFrameGraphRoot(frameGraphRoot());
- // Set dependencies of resource gatherer
- for (const QAspectJobPtr &jobPtr : renderBinJobs) {
- jobPtr->addDependency(m_bufferGathererJob);
- jobPtr->addDependency(m_textureGathererJob);
- jobPtr->addDependency(m_shaderGathererJob);
- }
+
+ BackendNodeDirtySet changesToUnset = dirtyBits();
// Add jobs
- renderBinJobs.push_back(m_updateShaderDataTransformJob);
- renderBinJobs.push_back(m_updateMeshTriangleListJob);
- renderBinJobs.push_back(m_updateTreeEnabledJob);
+ const bool entitiesEnabledDirty = changesToUnset & AbstractRenderer::EntityEnabledDirty;
+ if (entitiesEnabledDirty) {
+ renderBinJobs.push_back(m_updateTreeEnabledJob);
+ m_calculateBoundingVolumeJob->addDependency(m_updateTreeEnabledJob);
+ }
+
+ if (changesToUnset & AbstractRenderer::TransformDirty) {
+ renderBinJobs.push_back(m_worldTransformJob);
+ renderBinJobs.push_back(m_updateWorldBoundingVolumeJob);
+ renderBinJobs.push_back(m_updateShaderDataTransformJob);
+ }
+
+ if (changesToUnset & AbstractRenderer::GeometryDirty) {
+ renderBinJobs.push_back(m_calculateBoundingVolumeJob);
+ renderBinJobs.push_back(m_updateMeshTriangleListJob);
+ }
+
+ if (changesToUnset & AbstractRenderer::GeometryDirty ||
+ changesToUnset & AbstractRenderer::TransformDirty) {
+ renderBinJobs.push_back(m_expandBoundingVolumeJob);
+ }
+
+ m_updateSkinningPaletteJob->setDirtyJoints(m_nodesManager->jointManager()->dirtyJoints());
+ renderBinJobs.push_back(m_updateSkinningPaletteJob);
renderBinJobs.push_back(m_updateLevelOfDetailJob);
- renderBinJobs.push_back(m_expandBoundingVolumeJob);
- renderBinJobs.push_back(m_updateWorldBoundingVolumeJob);
- renderBinJobs.push_back(m_calculateBoundingVolumeJob);
- renderBinJobs.push_back(m_worldTransformJob);
renderBinJobs.push_back(m_cleanupJob);
renderBinJobs.push_back(m_sendRenderCaptureJob);
renderBinJobs.push_back(m_sendBufferCaptureJob);
@@ -1421,13 +1519,27 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
renderBinJobs.append(bufferJobs);
// Jobs to prepare GL Resource upload
- renderBinJobs.push_back(m_syncTextureLoadingJob);
renderBinJobs.push_back(m_vaoGathererJob);
- renderBinJobs.push_back(m_bufferGathererJob);
- renderBinJobs.push_back(m_textureGathererJob);
- renderBinJobs.push_back(m_shaderGathererJob);
- QMutexLocker lock(&m_renderQueueMutex);
+ if (changesToUnset & AbstractRenderer::BuffersDirty)
+ renderBinJobs.push_back(m_bufferGathererJob);
+
+ if (changesToUnset & AbstractRenderer::ShadersDirty)
+ renderBinJobs.push_back(m_shaderGathererJob);
+
+ 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
// RenderView and set its configuration then create a job to
@@ -1437,16 +1549,42 @@ 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
+ // TO DO: When secondary GL thread is integrated, the following line can be removed
+ changesToUnset.setFlag(AbstractRenderer::ShadersDirty, false);
+
+ // Clear all dirty flags but Compute so that
+ // we still render every frame when a compute shader is used in a scene
+ if (changesToUnset.testFlag(Renderer::ComputeDirty))
+ changesToUnset.setFlag(Renderer::ComputeDirty, false);
+ clearDirtyBits(changesToUnset);
+
return renderBinJobs;
}
@@ -1469,6 +1607,11 @@ QAspectJobPtr Renderer::syncTextureLoadingJob()
return m_syncTextureLoadingJob;
}
+QAspectJobPtr Renderer::expandBoundingVolumeJob()
+{
+ return m_expandBoundingVolumeJob;
+}
+
QAbstractFrameAdvanceService *Renderer::frameAdvanceService() const
{
return static_cast<Qt3DCore::QAbstractFrameAdvanceService *>(m_vsyncFrameAdvanceService.data());
@@ -1488,7 +1631,7 @@ void Renderer::performDraw(RenderCommand *command)
}
// Get GLBuffer from Buffer;
- GLBuffer *indirectDrawGLBuffer = m_graphicsContext->glBufferForRenderBuffer(indirectDrawBuffer);
+ GLBuffer *indirectDrawGLBuffer = m_graphicsContext->glBufferForRenderBuffer(indirectDrawBuffer, GLBuffer::DrawIndirectBuffer);
if (Q_UNLIKELY(indirectDrawGLBuffer == nullptr)) {
qWarning() << "Invalid Indirect Draw Buffer - failed to retrieve GLBuffer";
return;
@@ -1723,16 +1866,16 @@ bool Renderer::updateVAOWithAttributes(Geometry *geometry,
if ((attributeWasDirty = attribute->isDirty()) == true || forceUpdate) {
// Find the location for the attribute
const QVector<ShaderAttribute> shaderAttributes = shader->attributes();
- int attributeLocation = -1;
+ const ShaderAttribute *attributeDescription = nullptr;
for (const ShaderAttribute &shaderAttribute : shaderAttributes) {
if (shaderAttribute.m_nameId == attribute->nameId()) {
- attributeLocation = shaderAttribute.m_location;
+ attributeDescription = &shaderAttribute;
break;
}
}
- if (attributeLocation < 0)
+ if (!attributeDescription || attributeDescription->m_location < 0)
return false;
- m_graphicsContext->specifyAttribute(attribute, buffer, attributeLocation);
+ m_graphicsContext->specifyAttribute(attribute, buffer, attributeDescription);
}
}
diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h
index af10108e9..28e8711a8 100644
--- a/src/render/backend/renderer_p.h
+++ b/src/render/backend/renderer_p.h
@@ -75,6 +75,8 @@
#include <Qt3DRender/private/genericlambdajob_p.h>
#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>
@@ -113,7 +115,7 @@ class QAbstractShapeMesh;
struct GraphicsApiFilterData;
class QSceneImporter;
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
namespace Debug {
class CommandExecuter;
}
@@ -157,7 +159,7 @@ public:
void setTime(qint64 time) Q_DECL_OVERRIDE;
void setNodeManagers(NodeManagers *managers) Q_DECL_OVERRIDE;
- void setServices(Qt3DCore::QServiceLocator *services) Q_DECL_OVERRIDE { m_services = services; }
+ void setServices(Qt3DCore::QServiceLocator *services) Q_DECL_OVERRIDE;
void setSurfaceExposed(bool exposed) Q_DECL_OVERRIDE;
NodeManagers *nodeManagers() const Q_DECL_OVERRIDE;
@@ -189,11 +191,11 @@ public:
QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() Q_DECL_OVERRIDE;
Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() Q_DECL_OVERRIDE;
Qt3DCore::QAspectJobPtr syncTextureLoadingJob() Q_DECL_OVERRIDE;
+ Qt3DCore::QAspectJobPtr expandBoundingVolumeJob() Q_DECL_OVERRIDE;
QVector<Qt3DCore::QAspectJobPtr> createRenderBufferJobs() const;
inline FrameCleanupJobPtr frameCleanupJob() const { return m_cleanupJob; }
- inline ExpandBoundingVolumeJobPtr expandBoundingVolumeJob() const { return m_expandBoundingVolumeJob; }
inline UpdateShaderDataTransformJobPtr updateShaderDataTransformJob() const { return m_updateShaderDataTransformJob; }
inline CalculateBoundingVolumeJobPtr calculateBoundingVolumeJob() const { return m_calculateBoundingVolumeJob; }
inline UpdateTreeEnabledJobPtr updateTreeEnabledJob() const { return m_updateTreeEnabledJob; }
@@ -203,6 +205,7 @@ public:
inline UpdateMeshTriangleListJobPtr updateMeshTriangleListJob() const { return m_updateMeshTriangleListJob; }
inline FilterCompatibleTechniqueJobPtr filterCompatibleTechniqueJob() const { return m_filterCompatibleTechniqueJob; }
inline SynchronizerJobPtr textureLoadSyncJob() const { return m_syncTextureLoadingJob; }
+ inline UpdateSkinningPaletteJobPtr updateSkinningPaletteJob() const { return m_updateSkinningPaletteJob; }
Qt3DCore::QAbstractFrameAdvanceService *frameAdvanceService() const Q_DECL_OVERRIDE;
@@ -216,6 +219,11 @@ public:
void updateTexture(Texture *texture);
void cleanupTexture(const Texture *texture);
void downloadGLBuffers();
+ void blitFramebuffer(Qt3DCore::QNodeId inputRenderTargetId,
+ Qt3DCore::QNodeId outputRenderTargetId,
+ QRect inputRect,
+ QRect outputRect,
+ GLuint defaultFramebuffer);
void prepareCommandsSubmission(const QVector<RenderView *> &renderViews);
bool executeCommandsSubmission(const RenderView *rv);
@@ -259,8 +267,7 @@ public:
ViewSubmissionResultData submitRenderViews(const QVector<Render::RenderView *> &renderViews);
- QMutex* mutex() { return &m_renderQueueMutex; }
-
+ RendererCache *cache() { return &m_cache; }
#ifdef QT3D_RENDER_UNIT_TESTS
public:
@@ -290,7 +297,6 @@ private:
QScopedPointer<RenderThread> m_renderThread;
QScopedPointer<VSyncFrameAdvanceService> m_vsyncFrameAdvanceService;
- QMutex m_renderQueueMutex;
QSemaphore m_submitRenderViewsSemaphore;
QSemaphore m_waitForInitializationToBeCompleted;
@@ -320,6 +326,7 @@ private:
UpdateTreeEnabledJobPtr m_updateTreeEnabledJob;
SendRenderCaptureJobPtr m_sendRenderCaptureJob;
SendBufferCaptureJobPtr m_sendBufferCaptureJob;
+ UpdateSkinningPaletteJobPtr m_updateSkinningPaletteJob;
UpdateLevelOfDetailJobPtr m_updateLevelOfDetailJob;
UpdateMeshTriangleListJobPtr m_updateMeshTriangleListJob;
FilterCompatibleTechniqueJobPtr m_filterCompatibleTechniqueJob;
@@ -358,12 +365,13 @@ private:
OffscreenSurfaceHelper *m_offscreenHelper;
QMutex m_offscreenSurfaceMutex;
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
QScopedPointer<Qt3DRender::Debug::CommandExecuter> m_commandExecuter;
friend class Qt3DRender::Debug::CommandExecuter;
#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/renderqueue_p.h b/src/render/backend/renderqueue_p.h
index 611f5849a..e565115f2 100644
--- a/src/render/backend/renderqueue_p.h
+++ b/src/render/backend/renderqueue_p.h
@@ -53,6 +53,7 @@
#include <QVector>
#include <QtGlobal>
+#include <QMutex>
QT_BEGIN_NAMESPACE
@@ -81,12 +82,15 @@ public:
inline bool wasReset() const { return m_wasReset; }
+ inline QMutex *mutex() { return &m_mutex; }
+
private:
bool m_noRender;
bool m_wasReset;
int m_targetRenderViewCount;
int m_currentRenderViewCount;
QVector<RenderView *> m_currentWorkQueue;
+ QMutex m_mutex;
};
} // namespace Render
diff --git a/src/render/backend/rendersettings.cpp b/src/render/backend/rendersettings.cpp
index 2cd2b1d07..397d297e9 100644
--- a/src/render/backend/rendersettings.cpp
+++ b/src/render/backend/rendersettings.cpp
@@ -57,6 +57,7 @@ RenderSettings::RenderSettings()
, m_pickMethod(QPickingSettings::BoundingVolumePicking)
, m_pickResultMode(QPickingSettings::NearestPick)
, m_faceOrientationPickingMode(QPickingSettings::FrontFace)
+ , m_pickWorldSpaceTolerance(.1f)
, m_activeFrameGraph()
{
}
@@ -69,6 +70,7 @@ void RenderSettings::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePt
m_renderPolicy = data.renderPolicy;
m_pickMethod = data.pickMethod;
m_pickResultMode = data.pickResultMode;
+ m_pickWorldSpaceTolerance = data.pickWorldSpaceTolerance;
m_faceOrientationPickingMode = data.faceOrientationPickingMode;
}
@@ -82,6 +84,8 @@ void RenderSettings::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
m_pickResultMode = propertyChange->value().value<QPickingSettings::PickResultMode>();
else if (propertyChange->propertyName() == QByteArrayLiteral("faceOrientationPickingMode"))
m_faceOrientationPickingMode = propertyChange->value().value<QPickingSettings::FaceOrientationPickingMode>();
+ else if (propertyChange->propertyName() == QByteArrayLiteral("pickWorldSpaceTolerance"))
+ m_pickWorldSpaceTolerance = propertyChange->value().toFloat();
else if (propertyChange->propertyName() == QByteArrayLiteral("activeFrameGraph"))
m_activeFrameGraph = propertyChange->value().value<QNodeId>();
else if (propertyChange->propertyName() == QByteArrayLiteral("renderPolicy"))
diff --git a/src/render/backend/rendersettings_p.h b/src/render/backend/rendersettings_p.h
index 37771c40b..960edee29 100644
--- a/src/render/backend/rendersettings_p.h
+++ b/src/render/backend/rendersettings_p.h
@@ -74,6 +74,10 @@ public:
QPickingSettings::PickMethod pickMethod() const { return m_pickMethod; }
QPickingSettings::PickResultMode pickResultMode() const { return m_pickResultMode; }
QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode() const { return m_faceOrientationPickingMode; }
+ float pickWorldSpaceTolerance() const { return m_pickWorldSpaceTolerance; }
+
+ // For unit test purposes
+ void setActiveFrameGraphId(Qt3DCore::QNodeId frameGraphNodeId) { m_activeFrameGraph = frameGraphNodeId; }
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
@@ -82,6 +86,7 @@ private:
QPickingSettings::PickMethod m_pickMethod;
QPickingSettings::PickResultMode m_pickResultMode;
QPickingSettings::FaceOrientationPickingMode m_faceOrientationPickingMode;
+ float m_pickWorldSpaceTolerance;
Qt3DCore::QNodeId m_activeFrameGraph;
};
diff --git a/src/render/backend/renderthread.cpp b/src/render/backend/renderthread.cpp
index 03cbb7a5f..6b95ed396 100644
--- a/src/render/backend/renderthread.cpp
+++ b/src/render/backend/renderthread.cpp
@@ -75,23 +75,12 @@ void RenderThread::waitForStart( Priority priority )
// RenderThread context
void RenderThread::run()
{
- // We lock the renderer's mutex here before returning control to the calling
- // thread (the Aspect Thread). This is
- // to ensure that the Renderer's initialize() waitCondition is reached before
- // other threads try to wake it up. This is guaranteed by having the
- // Renderer::setSurface() function try to lock the renderer's mutex too.
- // That function will block until the mutex is unlocked by the wait condition
- // in the initialize() call below.
- QMutexLocker locker(m_renderer->mutex());
-
- // Now we have ensured we will reach the wait condition as described above,
// return control to the aspect thread that created us.
m_semaphore.release();
// This call to Renderer::initialize() waits for a surface to be set on the
// renderer in the context of the Aspect Thread
m_renderer->initialize();
- locker.unlock();
// Enter the main OpenGL submission loop.
m_renderer->render();
diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp
index 7adf7c5d2..dbb6ead21 100644
--- a/src/render/backend/renderview.cpp
+++ b/src/render/backend/renderview.cpp
@@ -129,10 +129,12 @@ RenderView::StandardUniformsNameToTypeHash RenderView::initializeStandardUniform
setters.insert(StringToInt::lookupId(QLatin1String("modelViewNormal")), ModelViewNormalMatrix);
setters.insert(StringToInt::lookupId(QLatin1String("viewportMatrix")), ViewportMatrix);
setters.insert(StringToInt::lookupId(QLatin1String("inverseViewportMatrix")), InverseViewportMatrix);
+ setters.insert(StringToInt::lookupId(QLatin1String("aspectRatio")), AspectRatio);
setters.insert(StringToInt::lookupId(QLatin1String("exposure")), Exposure);
setters.insert(StringToInt::lookupId(QLatin1String("gamma")), Gamma);
setters.insert(StringToInt::lookupId(QLatin1String("time")), Time);
setters.insert(StringToInt::lookupId(QLatin1String("eyePosition")), EyePosition);
+ setters.insert(StringToInt::lookupId(QLatin1String("skinningPalette[0]")), SkinningPalette);
return setters;
}
@@ -153,7 +155,9 @@ static QMatrix4x4 getProjectionMatrix(const CameraLens *lens)
return lens ? lens->projection() : QMatrix4x4();
}
-UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standardUniformType, const QMatrix4x4 &model) const
+UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standardUniformType,
+ Entity *entity,
+ const QMatrix4x4 &model) const
{
switch (standardUniformType) {
case ModelMatrix:
@@ -197,6 +201,8 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa
viewportMatrix.viewport(resolveViewport(m_viewport, m_surfaceSize));
return UniformValue(viewportMatrix.inverted());
}
+ case AspectRatio:
+ return float(m_surfaceSize.width()) / float(m_surfaceSize.height());
case Exposure:
return UniformValue(m_data.m_renderCameraLens ? m_data.m_renderCameraLens->exposure() : 0.0f);
case Gamma:
@@ -205,6 +211,14 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa
return UniformValue(float(m_renderer->time() / 1000000000.0f));
case EyePosition:
return UniformValue(m_data.m_eyePos);
+ case SkinningPalette: {
+ const Armature *armature = entity->renderComponent<Armature>();
+ if (!armature) {
+ qCWarning(Jobs, "Requesting skinningPalette uniform but no armature set on entity");
+ return UniformValue();
+ }
+ return armature->skinningPaletteUniform();
+ }
default:
Q_UNREACHABLE();
return UniformValue();
@@ -213,6 +227,7 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa
RenderView::RenderView()
: m_isDownloadBuffersEnable(false)
+ , m_hasBlitFramebufferInfo(false)
, m_renderer(nullptr)
, m_devicePixelRatio(1.)
, m_viewport(QRectF(0.0f, 0.0f, 1.0f, 1.0f))
@@ -539,16 +554,16 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
QVector<RenderCommand *> commands;
commands.reserve(entities.size());
- for (Entity *node : entities) {
+ for (Entity *entity : entities) {
GeometryRenderer *geometryRenderer = nullptr;
- HGeometryRenderer geometryRendererHandle = node->componentHandle<GeometryRenderer, 16>();
+ HGeometryRenderer geometryRendererHandle = entity->componentHandle<GeometryRenderer, 16>();
// There is a geometry renderer with geometry
if ((geometryRenderer = m_manager->geometryRendererManager()->data(geometryRendererHandle)) != nullptr
&& geometryRenderer->isEnabled()
&& !geometryRenderer->geometryId().isNull()) {
- const Qt3DCore::QNodeId materialComponentId = node->componentUuid<Material>();
- const HMaterial materialHandle = node->componentHandle<Material, 16>();
+ const Qt3DCore::QNodeId materialComponentId = entity->componentUuid<Material>();
+ const HMaterial materialHandle = entity->componentHandle<Material, 16>();
const QVector<RenderPassParameterData> renderPassData = m_parameters.value(materialComponentId);
HGeometry geometryHandle = m_manager->lookupHandle<Geometry, GeometryManager, HGeometry>(geometryRenderer->geometryId());
Geometry *geometry = m_manager->data<Geometry, GeometryManager>(geometryHandle);
@@ -561,7 +576,7 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
// Project the camera-to-object-center vector onto the camera
// view vector. This gives a depth value suitable as the key
// for BackToFront sorting.
- command->m_depth = QVector3D::dotProduct(node->worldBoundingVolume()->center() - m_data.m_eyePos, m_data.m_eyeViewDir);
+ command->m_depth = QVector3D::dotProduct(entity->worldBoundingVolume()->center() - m_data.m_eyePos, m_data.m_eyeViewDir);
command->m_geometry = geometryHandle;
command->m_geometryRenderer = geometryRendererHandle;
@@ -588,7 +603,7 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
// Copy vector so that we can sort it concurrently and we only want to sort the one for the current command
QVector<LightSource> lightSources = m_lightSources;
if (lightSources.size() > 1)
- std::sort(lightSources.begin(), lightSources.end(), LightSourceCompare(node));
+ std::sort(lightSources.begin(), lightSources.end(), LightSourceCompare(entity));
ParameterInfoList globalParameters = passData.parameterInfo;
// setShaderAndUniforms can initialize a localData
@@ -596,7 +611,7 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
setShaderAndUniforms(command,
pass,
globalParameters,
- *(node->worldTransform()),
+ entity,
lightSources.mid(0, std::max(lightSources.size(), MAX_LIGHTS)),
m_environmentLight);
@@ -674,12 +689,12 @@ QVector<RenderCommand *> RenderView::buildComputeRenderCommands(const QVector<En
// material/effect/technique/parameters/filters/
QVector<RenderCommand *> commands;
commands.reserve(entities.size());
- for (Entity *node : entities) {
+ for (Entity *entity : entities) {
ComputeCommand *computeJob = nullptr;
- if ((computeJob = node->renderComponent<ComputeCommand>()) != nullptr
+ if ((computeJob = entity->renderComponent<ComputeCommand>()) != nullptr
&& computeJob->isEnabled()) {
- const Qt3DCore::QNodeId materialComponentId = node->componentUuid<Material>();
+ const Qt3DCore::QNodeId materialComponentId = entity->componentUuid<Material>();
const QVector<RenderPassParameterData> renderPassData = m_parameters.value(materialComponentId);
// 1 RenderCommand per RenderPass pass on an Entity with a Mesh
@@ -697,7 +712,7 @@ QVector<RenderCommand *> RenderView::buildComputeRenderCommands(const QVector<En
setShaderAndUniforms(command,
pass,
globalParameters,
- *(node->worldTransform()),
+ entity,
QVector<LightSource>(),
nullptr);
commands.append(command);
@@ -750,9 +765,13 @@ void RenderView::setUniformValue(ShaderParameterPack &uniformPack, int nameId, c
}
}
-void RenderView::setStandardUniformValue(ShaderParameterPack &uniformPack, int glslNameId, int nameId, const QMatrix4x4 &worldTransform) const
+void RenderView::setStandardUniformValue(ShaderParameterPack &uniformPack,
+ int glslNameId,
+ int nameId,
+ Entity *entity,
+ const QMatrix4x4 &worldTransform) const
{
- uniformPack.setUniform(glslNameId, standardUniformValue(ms_standardUniformSetters[nameId], worldTransform));
+ uniformPack.setUniform(glslNameId, standardUniformValue(ms_standardUniformSetters[nameId], entity, worldTransform));
}
void RenderView::setUniformBlockValue(ShaderParameterPack &uniformPack,
@@ -887,8 +906,12 @@ void RenderView::prepareForSorting(RenderCommand *command) const
}
}
-void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass, ParameterInfoList &parameters, const QMatrix4x4 &worldTransform,
- const QVector<LightSource> &activeLightSources, EnvironmentLight *environmentLight) const
+void RenderView::setShaderAndUniforms(RenderCommand *command,
+ RenderPass *rPass,
+ ParameterInfoList &parameters,
+ Entity *entity,
+ const QVector<LightSource> &activeLightSources,
+ EnvironmentLight *environmentLight) const
{
// The VAO Handle is set directly in the renderer thread so as to avoid having to use a mutex here
// Set shader, technique, and effect by basically doing :
@@ -931,9 +954,10 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass,
!shaderStorageBlockNamesIds.isEmpty() || !attributeNamesIds.isEmpty()) {
// Set default standard uniforms without bindings
+ QMatrix4x4 worldTransform = *(entity->worldTransform());
for (const int uniformNameId : uniformNamesIds) {
if (ms_standardUniformSetters.contains(uniformNameId))
- setStandardUniformValue(command->m_parameterPack, uniformNameId, uniformNameId, worldTransform);
+ setStandardUniformValue(command->m_parameterPack, uniformNameId, uniformNameId, entity, worldTransform);
}
// Set default attributes
@@ -1039,6 +1063,26 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass,
}
}
+bool RenderView::hasBlitFramebufferInfo() const
+{
+ return m_hasBlitFramebufferInfo;
+}
+
+void RenderView::setHasBlitFramebufferInfo(bool hasBlitFramebufferInfo)
+{
+ m_hasBlitFramebufferInfo = hasBlitFramebufferInfo;
+}
+
+BlitFramebufferInfo RenderView::blitFrameBufferInfo() const
+{
+ return m_blitFrameBufferInfo;
+}
+
+void RenderView::setBlitFrameBufferInfo(const BlitFramebufferInfo &blitFrameBufferInfo)
+{
+ m_blitFrameBufferInfo = blitFrameBufferInfo;
+}
+
bool RenderView::isDownloadBuffersEnable() const
{
return m_isDownloadBuffersEnable;
diff --git a/src/render/backend/renderview_p.h b/src/render/backend/renderview_p.h
index 295d820e6..21d25a528 100644
--- a/src/render/backend/renderview_p.h
+++ b/src/render/backend/renderview_p.h
@@ -54,6 +54,7 @@
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/qclearbuffers.h>
+#include <Qt3DRender/qlayerfilter.h>
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/clearbuffers_p.h>
#include <Qt3DRender/private/cameralens_p.h>
@@ -62,6 +63,8 @@
#include <Qt3DRender/private/qsortpolicy_p.h>
#include <Qt3DRender/private/lightsource_p.h>
#include <Qt3DRender/private/qmemorybarrier_p.h>
+#include <Qt3DRender/private/qrendercapture_p.h>
+#include <Qt3DRender/private/qblitframebuffer_p.h>
#include <Qt3DCore/private/qframeallocator_p.h>
@@ -113,6 +116,17 @@ struct Q_AUTOTEST_EXPORT ClearBufferInfo
QVector4D clearColor;
};
+struct Q_AUTOTEST_EXPORT BlitFramebufferInfo
+{
+ Qt3DCore::QNodeId sourceRenderTargetId;
+ Qt3DCore::QNodeId destinationRenderTargetId;
+ QRect sourceRect;
+ QRect destinationRect;
+ Qt3DRender::QRenderTargetOutput::AttachmentPoint sourceAttachmentPoint;
+ Qt3DRender::QRenderTargetOutput::AttachmentPoint destinationAttachmentPoint;
+ QBlitFramebuffer::InterpolationMethod interpolationMethod;
+};
+
// This class is kind of analogous to RenderBin but I want to avoid trampling
// on that until we get this working
@@ -151,10 +165,11 @@ public:
inline void setEyeViewDirection(const QVector3D &dir) Q_DECL_NOTHROW { m_data.m_eyeViewDir = dir; }
inline QVector3D eyeViewDirection() const Q_DECL_NOTHROW { return m_data.m_eyeViewDir; }
- inline void setHasLayerFilter(bool filter) Q_DECL_NOTHROW { m_data.m_hasLayerFilter = filter; }
- inline bool hasLayerFilter() const Q_DECL_NOTHROW { return m_data.m_hasLayerFilter; }
- inline void appendLayerFilter(const Qt3DCore::QNodeIdVector &layerIds) Q_DECL_NOTHROW { m_data.m_layerIds << layerIds; }
- inline Qt3DCore::QNodeIdVector layerFilter() const Q_DECL_NOTHROW { return m_data.m_layerIds; }
+ inline void appendLayerFilter(const Qt3DCore::QNodeId layerFilterId) Q_DECL_NOTHROW { m_data.m_layerFilterIds.push_back(layerFilterId); }
+ inline Qt3DCore::QNodeIdVector layerFilters() const Q_DECL_NOTHROW { return m_data.m_layerFilterIds; }
+
+ inline void appendProximityFilterId(const Qt3DCore::QNodeId proximityFilterId) { m_data.m_proximityFilterIds.push_back(proximityFilterId); }
+ inline Qt3DCore::QNodeIdVector proximityFilterIds() const { return m_data.m_proximityFilterIds; }
inline void setRenderPassFilter(const RenderPassFilter *rpFilter) Q_DECL_NOTHROW { m_data.m_passFilter = rpFilter; }
inline const RenderPassFilter *renderPassFilter() const Q_DECL_NOTHROW { return m_data.m_passFilter; }
@@ -224,6 +239,8 @@ public:
inline void setRenderCaptureNodeId(const Qt3DCore::QNodeId nodeId) Q_DECL_NOTHROW { m_renderCaptureNodeId = nodeId; }
inline const Qt3DCore::QNodeId renderCaptureNodeId() const Q_DECL_NOTHROW { return m_renderCaptureNodeId; }
+ inline void setRenderCaptureRequest(const QRenderCaptureRequest& request) Q_DECL_NOTHROW { m_renderCaptureRequest = request; }
+ inline const QRenderCaptureRequest renderCaptureRequest() const Q_DECL_NOTHROW { return m_renderCaptureRequest; }
void setMemoryBarrier(QMemoryBarrier::Operations barrier) Q_DECL_NOTHROW { m_memoryBarrier = barrier; }
QMemoryBarrier::Operations memoryBarrier() const Q_DECL_NOTHROW { return m_memoryBarrier; }
@@ -237,7 +254,6 @@ public:
, m_renderCameraNode(nullptr)
, m_techniqueFilter(nullptr)
, m_passFilter(nullptr)
- , m_hasLayerFilter(false)
{
}
CameraLens *m_renderCameraLens;
@@ -246,25 +262,39 @@ public:
const RenderPassFilter *m_passFilter;
QMatrix4x4 m_viewMatrix;
QMatrix4x4 m_viewProjectionMatrix;
- bool m_hasLayerFilter;
- Qt3DCore::QNodeIdVector m_layerIds;
+ Qt3DCore::QNodeIdVector m_layerFilterIds;
QVector<Qt3DRender::QSortPolicy::SortType> m_sortingTypes;
QVector3D m_eyePos;
QVector3D m_eyeViewDir;
+ Qt3DCore::QNodeIdVector m_proximityFilterIds;
};
bool isDownloadBuffersEnable() const;
void setIsDownloadBuffersEnable(bool isDownloadBuffersEnable);
+ BlitFramebufferInfo blitFrameBufferInfo() const;
+ void setBlitFrameBufferInfo(const BlitFramebufferInfo &blitFrameBufferInfo);
+
+ bool hasBlitFramebufferInfo() const;
+ void setHasBlitFramebufferInfo(bool hasBlitFramebufferInfo);
+
private:
- void setShaderAndUniforms(RenderCommand *command, RenderPass *pass, ParameterInfoList &parameters, const QMatrix4x4 &worldTransform,
- const QVector<LightSource> &activeLightSources, EnvironmentLight *environmentLight) const;
+ void setShaderAndUniforms(RenderCommand *command,
+ RenderPass *pass,
+ ParameterInfoList &parameters,
+ Entity *entity,
+ const QVector<LightSource> &activeLightSources,
+ EnvironmentLight *environmentLight) const;
mutable QThreadStorage<UniformBlockValueBuilder*> m_localData;
Qt3DCore::QNodeId m_renderCaptureNodeId;
+ QRenderCaptureRequest m_renderCaptureRequest;
bool m_isDownloadBuffersEnable;
+ bool m_hasBlitFramebufferInfo;
+ BlitFramebufferInfo m_blitFrameBufferInfo;
+
Renderer *m_renderer;
NodeManagers *m_manager;
QSize m_surfaceSize;
@@ -316,20 +346,28 @@ private:
ModelViewNormalMatrix,
ViewportMatrix,
InverseViewportMatrix,
+ AspectRatio,
Time,
Exposure,
Gamma,
- EyePosition
+ EyePosition,
+ SkinningPalette
};
typedef QHash<int, StandardUniform> StandardUniformsNameToTypeHash;
static StandardUniformsNameToTypeHash ms_standardUniformSetters;
static StandardUniformsNameToTypeHash initializeStandardUniformSetters();
- UniformValue standardUniformValue(StandardUniform standardUniformType, const QMatrix4x4 &model) const;
+ UniformValue standardUniformValue(StandardUniform standardUniformType,
+ Entity *entity,
+ const QMatrix4x4 &model) const;
void setUniformValue(ShaderParameterPack &uniformPack, int nameId, const UniformValue &value) const;
- void setStandardUniformValue(ShaderParameterPack &uniformPack, int glslNameId, int nameId, const QMatrix4x4 &worldTransform) const;
+ void setStandardUniformValue(ShaderParameterPack &uniformPack,
+ int glslNameId,
+ int nameId,
+ Entity *entity,
+ const QMatrix4x4 &worldTransform) const;
void setUniformBlockValue(ShaderParameterPack &uniformPack,
Shader *shader,
const ShaderUniformBlock &block,
diff --git a/src/render/backend/renderviewbuilder.cpp b/src/render/backend/renderviewbuilder.cpp
index f47c6f419..769eee29f 100644
--- a/src/render/backend/renderviewbuilder.cpp
+++ b/src/render/backend/renderviewbuilder.cpp
@@ -39,6 +39,8 @@
#include "renderviewbuilder_p.h"
+#include <QThread>
+
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
@@ -121,11 +123,13 @@ public:
explicit SyncRenderViewInitialization(const RenderViewInitializerJobPtr &renderViewJob,
const FrustumCullingJobPtr &frustumCullingJob,
const FilterLayerEntityJobPtr &filterEntityByLayerJob,
+ const FilterProximityDistanceJobPtr &filterProximityJob,
const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs,
const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs)
: m_renderViewJob(renderViewJob)
, m_frustumCullingJob(frustumCullingJob)
, m_filterEntityByLayerJob(filterEntityByLayerJob)
+ , m_filterProximityJob(filterProximityJob)
, m_materialGathererJobs(materialGathererJobs)
, m_renderViewBuilderJobs(renderViewBuilderJobs)
{}
@@ -135,8 +139,11 @@ public:
RenderView *rv = m_renderViewJob->renderView();
// Layer filtering
- m_filterEntityByLayerJob->setHasLayerFilter(rv->hasLayerFilter());
- m_filterEntityByLayerJob->setLayers(rv->layerFilter());
+ if (!m_filterEntityByLayerJob.isNull())
+ m_filterEntityByLayerJob->setLayerFilters(rv->layerFilters());
+
+ // Proximity filtering
+ m_filterProximityJob->setProximityFilterIds(rv->proximityFilterIds());
// Material Parameter building
for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) {
@@ -156,6 +163,7 @@ private:
RenderViewInitializerJobPtr m_renderViewJob;
FrustumCullingJobPtr m_frustumCullingJob;
FilterLayerEntityJobPtr m_filterEntityByLayerJob;
+ FilterProximityDistanceJobPtr m_filterProximityJob;
QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs;
};
@@ -165,20 +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()()
@@ -202,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
- QVector<Entity *> filteredEntities = m_filterEntityByLayerJob->filteredEntities();
RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, filteredEntities);
// Set the light sources, with layer filters applied.
@@ -214,9 +228,13 @@ public:
}
rv->setLightSources(lightSources);
- // Filter out frustum culled entity for drawable entities
- if (isDraw && rv->frustumCulling())
- RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, m_frustumCullingJob->visibleEntities());
+ if (isDraw) {
+ // Filter out frustum culled entity for drawable entities
+ if (rv->frustumCulling())
+ RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, m_frustumCullingJob->visibleEntities());
+ // Filter out entities which didn't satisfy proximity filtering
+ RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, m_filterProximityJob->filteredEntities());
+ }
// Split among the number of command builders
int i = 0;
@@ -241,12 +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
@@ -270,78 +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_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_materialGathererJobs,
- m_renderViewBuilderJobs),
- JobTypes::SyncRenderViewInitialization);
-
- m_syncRenderCommandBuildingJob = SynchronizerJobPtr::create(SyncRenderCommandBuilding(m_renderViewJob,
- m_frustumCullingJob,
- m_filterEntityByLayerJob,
- 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
@@ -409,6 +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;
@@ -416,6 +494,11 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
jobs.reserve(m_materialGathererJobs.size() + m_renderViewBuilderJobs.size() + 11);
// Set dependencies
+
+ // Finish the skinning palette job before processing renderviews
+ // TODO: Maybe only update skinning palettes for non-culled entities
+ m_renderViewJob->addDependency(m_renderer->updateSkinningPaletteJob());
+
m_syncFrustumCullingJob->addDependency(m_renderer->updateWorldTransformJob());
m_syncFrustumCullingJob->addDependency(m_renderer->updateShaderDataTransformJob());
m_syncFrustumCullingJob->addDependency(m_syncRenderViewInitializationJob);
@@ -427,8 +510,8 @@ 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);
m_syncRenderCommandBuildingJob->addDependency(m_syncRenderViewInitializationJob);
for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) {
@@ -438,7 +521,7 @@ 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);
@@ -460,20 +543,30 @@ 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
for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) // Step3
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;
}
@@ -488,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 6f09a6282..a1fb4eb8b 100644
--- a/src/render/backend/renderviewbuilder_p.h
+++ b/src/render/backend/renderviewbuilder_p.h
@@ -62,6 +62,7 @@
#include <Qt3DRender/private/renderview_p.h>
#include <Qt3DRender/private/frustumcullingjob_p.h>
#include <Qt3DRender/private/lightgatherer_p.h>
+#include <Qt3DRender/private/filterproximitydistancejob_p.h>
QT_BEGIN_NAMESPACE
@@ -93,18 +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;
@@ -120,6 +129,8 @@ 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/backend/segmentsvisitor.cpp b/src/render/backend/segmentsvisitor.cpp
new file mode 100644
index 000000000..96e2b3b6c
--- /dev/null
+++ b/src/render/backend/segmentsvisitor.cpp
@@ -0,0 +1,369 @@
+/****************************************************************************
+**
+** 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 "segmentsvisitor_p.h"
+#include <Qt3DCore/qentity.h>
+#include <Qt3DRender/qgeometryrenderer.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/buffermanager_p.h>
+#include <Qt3DRender/private/geometryrenderer_p.h>
+#include <Qt3DRender/private/geometryrenderermanager_p.h>
+#include <Qt3DRender/private/geometry_p.h>
+#include <Qt3DRender/private/attribute_p.h>
+#include <Qt3DRender/private/buffer_p.h>
+#include <Qt3DRender/private/trianglesvisitor_p.h>
+#include <Qt3DRender/private/visitorutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+namespace {
+
+bool isSegmentBased(Qt3DRender::QGeometryRenderer::PrimitiveType type) Q_DECL_NOTHROW
+{
+ switch (type) {
+ case Qt3DRender::QGeometryRenderer::Lines:
+ case Qt3DRender::QGeometryRenderer::LineStrip:
+ case Qt3DRender::QGeometryRenderer::LineLoop:
+ case Qt3DRender::QGeometryRenderer::LinesAdjacency:
+ case Qt3DRender::QGeometryRenderer::LineStripAdjacency:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// indices, vertices are already offset
+template<typename Index, typename Vertex>
+void traverseSegmentsIndexed(Index *indices,
+ Vertex *vertices,
+ const BufferInfo &indexInfo,
+ const BufferInfo &vertexInfo,
+ SegmentsVisitor *visitor)
+{
+ uint i = 0;
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[2];
+ QVector3D abc[2];
+ while (i < indexInfo.count) {
+ for (uint u = 0; u < 2; ++u) {
+ ndx[u] = indices[i + u];
+ const uint idx = ndx[u] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[u][j] = vertices[idx + j];
+ }
+ }
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ i += 2;
+ }
+}
+
+// vertices are already offset
+template<typename Vertex>
+void traverseSegments(Vertex *vertices,
+ const BufferInfo &vertexInfo,
+ SegmentsVisitor *visitor)
+{
+ uint i = 0;
+
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[2];
+ QVector3D abc[2];
+ while (i < vertexInfo.count) {
+ for (uint u = 0; u < 2; ++u) {
+ ndx[u] = (i + u);
+ const uint idx = ndx[u] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[u][j] = vertices[idx + j];
+ }
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ i += 2;
+ }
+}
+
+// indices, vertices are already offset
+template<typename Index, typename Vertex>
+void traverseSegmentStripIndexed(Index *indices,
+ Vertex *vertices,
+ const BufferInfo &indexInfo,
+ const BufferInfo &vertexInfo,
+ SegmentsVisitor *visitor,
+ bool loop)
+{
+ uint i = 0;
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[2];
+ QVector3D abc[2];
+ ndx[0] = indices[0];
+ uint idx = ndx[0] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[0][j] = vertices[idx + j];
+ while (i < indexInfo.count - 1) {
+ ndx[1] = indices[i + 1];
+ if (ndx[0] != ndx[1]) {
+ idx = ndx[1] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[1][j] = vertices[idx + j];
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ }
+ ++i;
+ ndx[0] = ndx[1];
+ abc[0] = abc[1];
+ }
+ if (loop) {
+ ndx[1] = indices[0];
+ if (ndx[0] != ndx[1]) {
+ idx = ndx[1] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[1][j] = vertices[idx + j];
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ }
+ }
+}
+
+// vertices are already offset
+template<typename Vertex>
+void traverseSegmentStrip(Vertex *vertices,
+ const BufferInfo &vertexInfo,
+ SegmentsVisitor *visitor,
+ bool loop)
+{
+ uint i = 0;
+
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[2];
+ QVector3D abc[2];
+ ndx[0] = i;
+ uint idx = ndx[0] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[0][j] = vertices[idx + j];
+ while (i < vertexInfo.count - 1) {
+ ndx[1] = (i + 1);
+ idx = ndx[1] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[1][j] = vertices[idx + j];
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ ++i;
+ ndx[0] = ndx[1];
+ abc[0] = abc[1];
+ }
+ if (loop) {
+ ndx[1] = 0;
+ idx = ndx[1] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[1][j] = vertices[idx + j];
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ }
+}
+
+// indices, vertices are already offset
+template<typename Index, typename Vertex>
+void traverseSegmentAdjacencyIndexed(Index *indices,
+ Vertex *vertices,
+ const BufferInfo &indexInfo,
+ const BufferInfo &vertexInfo,
+ SegmentsVisitor *visitor)
+{
+ uint i = 1;
+ uint n = indexInfo.count - 1;
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[2];
+ QVector3D abc[2];
+ while (i < n) {
+ for (uint u = 0; u < 2; ++u) {
+ ndx[u] = indices[i + u];
+ const uint idx = ndx[u] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[u][j] = vertices[idx + j];
+ }
+ }
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ i += 2;
+ }
+}
+
+// vertices are already offset
+template<typename Vertex>
+void traverseSegmentAdjacency(Vertex *vertices,
+ const BufferInfo &vertexInfo,
+ SegmentsVisitor *visitor)
+{
+ uint i = 1;
+ uint n = vertexInfo.count - 1;
+
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[2];
+ QVector3D abc[2];
+ while (i < n) {
+ for (uint u = 0; u < 2; ++u) {
+ ndx[u] = (i + u);
+ const uint idx = ndx[u] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[u][j] = vertices[idx + j];
+ }
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ i += 2;
+ }
+}
+
+template<typename Index, typename Visitor>
+struct IndexedVertexExecutor
+{
+ template<typename Vertex>
+ void operator ()(const BufferInfo &vertexInfo, Vertex * vertices)
+ {
+ switch (m_primitiveType) {
+ case Qt3DRender::QGeometryRenderer::Lines:
+ traverseSegmentsIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::LineStrip:
+ traverseSegmentStripIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor, false);
+ return;
+ case Qt3DRender::QGeometryRenderer::LineLoop:
+ traverseSegmentStripIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor, true);
+ return;
+ case Qt3DRender::QGeometryRenderer::LinesAdjacency:
+ traverseSegmentAdjacencyIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::LineStripAdjacency: // fall through
+ default:
+ Q_UNREACHABLE();
+ return;
+ }
+ }
+
+ BufferInfo m_indexBufferInfo;
+ Index *m_indices;
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
+};
+
+template<typename Visitor>
+struct IndexExecutor
+{
+ template<typename Index>
+ void operator ()( const BufferInfo &indexInfo, Index *indices)
+ {
+ IndexedVertexExecutor<Index, Visitor> exec;
+ exec.m_primitiveType = m_primitiveType;
+ exec.m_indices = indices;
+ exec.m_indexBufferInfo = indexInfo;
+ exec.m_visitor = m_visitor;
+ Qt3DRender::Render::Visitor::processBuffer(m_vertexBufferInfo, exec);
+ }
+
+ BufferInfo m_vertexBufferInfo;
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
+};
+
+template<typename Visitor>
+struct VertexExecutor
+{
+ template<typename Vertex>
+ void operator ()(const BufferInfo &vertexInfo, Vertex *vertices)
+ {
+ switch (m_primitiveType) {
+ case Qt3DRender::QGeometryRenderer::Lines:
+ traverseSegments(vertices, vertexInfo, m_visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::LineStrip:
+ traverseSegmentStrip(vertices, vertexInfo, m_visitor, false);
+ return;
+ case Qt3DRender::QGeometryRenderer::LineLoop:
+ traverseSegmentStrip(vertices, vertexInfo, m_visitor, true);
+ return;
+ case Qt3DRender::QGeometryRenderer::LinesAdjacency:
+ traverseSegmentAdjacency(vertices, vertexInfo, m_visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::LineStripAdjacency: // fall through
+ default:
+ Q_UNREACHABLE();
+ return;
+ }
+ }
+
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
+};
+
+} // anonymous
+
+
+SegmentsVisitor::~SegmentsVisitor()
+{
+
+}
+
+void SegmentsVisitor::apply(const Qt3DCore::QEntity *entity)
+{
+ GeometryRenderer *renderer = m_manager->geometryRendererManager()->lookupResource(entity->id());
+ apply(renderer, entity->id());
+}
+
+void SegmentsVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id)
+{
+ m_nodeId = id;
+ if (renderer && renderer->instanceCount() == 1 && isSegmentBased(renderer->primitiveType())) {
+ Visitor::visitPrimitives<VertexExecutor<SegmentsVisitor>,
+ IndexExecutor<SegmentsVisitor>, SegmentsVisitor>(m_manager, renderer, this);
+ }
+}
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/segmentsvisitor_p.h b/src/render/backend/segmentsvisitor_p.h
new file mode 100644
index 000000000..21867b0d5
--- /dev/null
+++ b/src/render/backend/segmentsvisitor_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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 QT3DRENDER_RENDER_SEGMENTSVISITOR_P_H
+#define QT3DRENDER_RENDER_SEGMENTSVISITOR_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 <Qt3DCore/qnodeid.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+class QEntity;
+}
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class GeometryRenderer;
+class NodeManagers;
+
+class Q_AUTOTEST_EXPORT SegmentsVisitor
+{
+public:
+ explicit SegmentsVisitor(NodeManagers *manager) : m_manager(manager) { }
+ virtual ~SegmentsVisitor();
+
+ void apply(const Qt3DCore::QEntity *entity);
+ void apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id);
+
+ virtual void visit(uint andx, const QVector3D &a,
+ uint bndx, const QVector3D &b) = 0;
+
+protected:
+ NodeManagers *m_manager;
+ Qt3DCore::QNodeId m_nodeId;
+};
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+
+#endif // QT3DRENDER_RENDER_SEGMENTSVISITOR_P_H
diff --git a/src/render/backend/trianglesvisitor.cpp b/src/render/backend/trianglesvisitor.cpp
index 036f43fa0..57538c8d7 100644
--- a/src/render/backend/trianglesvisitor.cpp
+++ b/src/render/backend/trianglesvisitor.cpp
@@ -48,6 +48,7 @@
#include <Qt3DRender/private/geometry_p.h>
#include <Qt3DRender/private/attribute_p.h>
#include <Qt3DRender/private/buffer_p.h>
+#include <Qt3DRender/private/visitorutils_p.h>
#include <Qt3DRender/private/bufferutils_p.h>
QT_BEGIN_NAMESPACE
@@ -322,29 +323,21 @@ QVector4D readCoordinate(const BufferInfo &info, Coordinate *coordinates, uint i
return ret;
}
-template<typename Func>
-void processBuffer(const BufferInfo &info, Func &f)
+
+template <QAttribute::VertexBaseType> struct EnumToType;
+template <> struct EnumToType<QAttribute::Byte> { typedef const char type; };
+template <> struct EnumToType<QAttribute::UnsignedByte> { typedef const uchar type; };
+template <> struct EnumToType<QAttribute::Short> { typedef const short type; };
+template <> struct EnumToType<QAttribute::UnsignedShort> { typedef const ushort type; };
+template <> struct EnumToType<QAttribute::Int> { typedef const int type; };
+template <> struct EnumToType<QAttribute::UnsignedInt> { typedef const uint type; };
+template <> struct EnumToType<QAttribute::Float> { typedef const float type; };
+template <> struct EnumToType<QAttribute::Double> { typedef const double type; };
+
+template<QAttribute::VertexBaseType v>
+typename EnumToType<v>::type *castToType(const QByteArray &u, uint byteOffset)
{
- switch (info.type) {
- case QAttribute::Byte: f(info, BufferTypeInfo::castToType<QAttribute::Byte>(info.data, info.byteOffset));
- return;
- case QAttribute::UnsignedByte: f(info, BufferTypeInfo::castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset));
- return;
- case QAttribute::Short: f(info, BufferTypeInfo::castToType<QAttribute::Short>(info.data, info.byteOffset));
- return;
- case QAttribute::UnsignedShort: f(info, BufferTypeInfo::castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset));
- return;
- case QAttribute::Int: f(info, BufferTypeInfo::castToType<QAttribute::Int>(info.data, info.byteOffset));
- return;
- case QAttribute::UnsignedInt: f(info, BufferTypeInfo::castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset));
- return;
- case QAttribute::Float: f(info, BufferTypeInfo::castToType<QAttribute::Float>(info.data, info.byteOffset));
- return;
- case QAttribute::Double: f(info, BufferTypeInfo::castToType<QAttribute::Double>(info.data, info.byteOffset));
- return;
- default:
- return;
- }
+ return reinterpret_cast< typename EnumToType<v>::type *>(u.constData() + byteOffset);
}
QVector4D readBuffer(const BufferInfo &info, uint index)
@@ -372,24 +365,24 @@ QVector4D readBuffer(const BufferInfo &info, uint index)
return QVector4D();
}
-template<typename Index>
+template<typename Index, typename Visitor>
struct IndexedVertexExecutor
{
template<typename Vertex>
void operator ()(const BufferInfo &vertexInfo, Vertex * vertices)
{
- switch (primitiveType) {
+ switch (m_primitiveType) {
case Qt3DRender::QGeometryRenderer::Triangles:
- traverseTrianglesIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor);
+ traverseTrianglesIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TriangleStrip:
- traverseTriangleStripIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor);
+ traverseTriangleStripIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TriangleFan:
- traverseTriangleFanIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor);
+ traverseTriangleFanIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TrianglesAdjacency:
- traverseTriangleAdjacencyIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor);
+ traverseTriangleAdjacencyIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency: // fall through
default:
@@ -397,48 +390,49 @@ struct IndexedVertexExecutor
}
}
- BufferInfo indexBufferInfo;
- Index *indices;
- Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType;
- TrianglesVisitor* visitor;
+ BufferInfo m_indexBufferInfo;
+ Index *m_indices;
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
};
+template<typename Visitor>
struct IndexExecutor
{
- BufferInfo vertexBufferInfo;
-
template<typename Index>
void operator ()( const BufferInfo &indexInfo, Index *indices)
{
- IndexedVertexExecutor<Index> exec;
- exec.primitiveType = primitiveType;
- exec.indices = indices;
- exec.indexBufferInfo = indexInfo;
- exec.visitor = visitor;
- processBuffer(vertexBufferInfo, exec);
+ IndexedVertexExecutor<Index, Visitor> exec;
+ exec.m_primitiveType = m_primitiveType;
+ exec.m_indices = indices;
+ exec.m_indexBufferInfo = indexInfo;
+ exec.m_visitor = m_visitor;
+ Qt3DRender::Render::Visitor::processBuffer(m_vertexBufferInfo, exec);
}
- Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType;
- TrianglesVisitor* visitor;
+ BufferInfo m_vertexBufferInfo;
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
};
+template<typename Visitor>
struct VertexExecutor
{
template<typename Vertex>
void operator ()(const BufferInfo &vertexInfo, Vertex *vertices)
{
- switch (primitiveType) {
+ switch (m_primitiveType) {
case Qt3DRender::QGeometryRenderer::Triangles:
- traverseTriangles(vertices, vertexInfo, visitor);
+ traverseTriangles(vertices, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TriangleStrip:
- traverseTriangleStrip(vertices, vertexInfo, visitor);
+ traverseTriangleStrip(vertices, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TriangleFan:
- traverseTriangleFan(vertices, vertexInfo, visitor);
+ traverseTriangleFan(vertices, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TrianglesAdjacency:
- traverseTriangleAdjacency(vertices, vertexInfo, visitor);
+ traverseTriangleAdjacency(vertices, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency: // fall through
default:
@@ -446,8 +440,8 @@ struct VertexExecutor
}
}
- Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType;
- TrianglesVisitor* visitor;
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
};
} // anonymous
@@ -468,67 +462,8 @@ void TrianglesVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::Q
{
m_nodeId = id;
if (renderer && renderer->instanceCount() == 1 && isTriangleBased(renderer->primitiveType())) {
- Attribute *positionAttribute = nullptr;
- Attribute *indexAttribute = nullptr;
- Buffer *positionBuffer = nullptr;
- Buffer *indexBuffer = nullptr;
- Geometry *geom = m_manager->lookupResource<Geometry, GeometryManager>(renderer->geometryId());
-
- if (geom) {
- Qt3DRender::Render::Attribute *attribute = nullptr;
- const auto attrIds = geom->attributes();
- for (const Qt3DCore::QNodeId attrId : attrIds) {
- attribute = m_manager->lookupResource<Attribute, AttributeManager>(attrId);
- if (attribute){
- if (attribute->name() == QAttribute::defaultPositionAttributeName())
- positionAttribute = attribute;
- else if (attribute->attributeType() == QAttribute::IndexAttribute)
- indexAttribute = attribute;
- }
- }
-
- if (positionAttribute)
- positionBuffer = m_manager->lookupResource<Buffer, BufferManager>(positionAttribute->bufferId());
- if (indexAttribute)
- indexBuffer = m_manager->lookupResource<Buffer, BufferManager>(indexAttribute->bufferId());
-
- if (positionBuffer) {
-
- BufferInfo vertexBufferInfo;
- vertexBufferInfo.data = positionBuffer->data();
- vertexBufferInfo.type = positionAttribute->vertexBaseType();
- vertexBufferInfo.byteOffset = positionAttribute->byteOffset();
- vertexBufferInfo.byteStride = positionAttribute->byteStride();
- vertexBufferInfo.dataSize = positionAttribute->vertexSize();
- vertexBufferInfo.count = positionAttribute->count();
-
- if (indexBuffer) { // Indexed
-
- BufferInfo indexBufferInfo;
- indexBufferInfo.data = indexBuffer->data();
- indexBufferInfo.type = indexAttribute->vertexBaseType();
- indexBufferInfo.byteOffset = indexAttribute->byteOffset();
- indexBufferInfo.byteStride = indexAttribute->byteStride();
- indexBufferInfo.count = indexAttribute->count();
-
- IndexExecutor executor;
- executor.vertexBufferInfo = vertexBufferInfo;
- executor.primitiveType = renderer->primitiveType();
- executor.visitor = this;
-
- return processBuffer(indexBufferInfo, executor);
-
- } else { // Non Indexed
-
- // Check into which type the buffer needs to be casted
- VertexExecutor executor;
- executor.primitiveType = renderer->primitiveType();
- executor.visitor = this;
-
- return processBuffer(vertexBufferInfo, executor);
- }
- }
- }
+ Visitor::visitPrimitives<VertexExecutor<TrianglesVisitor>,
+ IndexExecutor<TrianglesVisitor>, TrianglesVisitor>(m_manager, renderer, this);
}
}
diff --git a/src/render/backend/uniform.cpp b/src/render/backend/uniform.cpp
index c2088b60f..03220a219 100644
--- a/src/render/backend/uniform.cpp
+++ b/src/render/backend/uniform.cpp
@@ -225,12 +225,34 @@ UniformValue UniformValue::fromVariant(const QVariant &variant)
break;
}
- default:
+ default: {
+ if (variant.userType() == qMetaTypeId<QMatrix3x3>()) {
+ const QMatrix3x3 mat33 = variant.value<QMatrix3x3>();
+ // Use constData because we want column-major layout
+ v.m_data.resize(9);
+ memcpy(v.data<float>(), mat33.constData(), 9 * sizeof(float));
+ break;
+ }
qWarning() << "Unknown uniform type or value:" << variant << "Please check your QParameters";
}
+ }
return v;
}
+template<>
+void UniformValue::setData<QMatrix4x4>(const QVector<QMatrix4x4> &v)
+{
+ m_data.resize(16 * v.size());
+ m_valueType = ScalarValue;
+ int offset = 0;
+ const int byteSize = 16 * sizeof(float);
+ float *data = m_data.data();
+ for (const auto m : v) {
+ memcpy(data + offset, m.constData(), byteSize);
+ offset += 16;
+ }
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/uniform_p.h b/src/render/backend/uniform_p.h
index 6b5ae4172..e0d8fedeb 100644
--- a/src/render/backend/uniform_p.h
+++ b/src/render/backend/uniform_p.h
@@ -152,6 +152,18 @@ public:
memcpy(m_data.data(), mat44.constData(), 16 * sizeof(float));
}
+ UniformValue(const QVector<QMatrix4x4> &v)
+ : m_data(16 * v.size())
+ {
+ int offset = 0;
+ const int byteSize = 16 * sizeof(float);
+ float *data = m_data.data();
+ for (const auto m : v) {
+ memcpy(data + offset, m.constData(), byteSize);
+ offset += 16;
+ }
+ }
+
// For nodes which will later be replaced by a Texture or Buffer
UniformValue(Qt3DCore::QNodeId id)
: UniformValue()
@@ -171,8 +183,19 @@ public:
ValueType valueType() const { return m_valueType; }
UniformType storedType() const { return m_storedType; }
+ template<typename T>
+ void setData(const QVector<T> &v)
+ {
+ m_data.resize(v.size() * sizeof(T) / sizeof(float));
+ m_valueType = ScalarValue;
+ float *data = m_data.data();
+ memcpy(data, v.constData(), v.size() * sizeof(T));
+ }
+
static UniformValue fromVariant(const QVariant &variant);
+ int byteSize() const { return m_data.size() * sizeof(float); }
+
template<typename T>
const T *constData() const
{
@@ -205,6 +228,9 @@ private:
UniformType m_storedType = Unknown;
};
+template<>
+Q_AUTOTEST_EXPORT void UniformValue::setData<QMatrix4x4>(const QVector<QMatrix4x4> &v);
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/visitorutils_p.h b/src/render/backend/visitorutils_p.h
new file mode 100644
index 000000000..452cf153b
--- /dev/null
+++ b/src/render/backend/visitorutils_p.h
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Paul Lemire paul.lemire350@gmail.com
+** 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_VISITORUTILS_P_H
+#define QT3DRENDER_VISITORUTILS_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 <QtGlobal>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+namespace Visitor {
+
+template <QAttribute::VertexBaseType> struct EnumToType;
+template <> struct EnumToType<QAttribute::Byte> { typedef const char type; };
+template <> struct EnumToType<QAttribute::UnsignedByte> { typedef const uchar type; };
+template <> struct EnumToType<QAttribute::Short> { typedef const short type; };
+template <> struct EnumToType<QAttribute::UnsignedShort> { typedef const ushort type; };
+template <> struct EnumToType<QAttribute::Int> { typedef const int type; };
+template <> struct EnumToType<QAttribute::UnsignedInt> { typedef const uint type; };
+template <> struct EnumToType<QAttribute::Float> { typedef const float type; };
+template <> struct EnumToType<QAttribute::Double> { typedef const double type; };
+
+template<QAttribute::VertexBaseType v>
+inline typename EnumToType<v>::type *castToType(const QByteArray &u, uint byteOffset)
+{
+ return reinterpret_cast< typename EnumToType<v>::type *>(u.constData() + byteOffset);
+}
+
+template<typename Func>
+void processBuffer(const BufferInfo &info, Func &f)
+{
+ switch (info.type) {
+ case QAttribute::Byte: f(info, castToType<QAttribute::Byte>(info.data, info.byteOffset));
+ return;
+ case QAttribute::UnsignedByte: f(info, castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset));
+ return;
+ case QAttribute::Short: f(info, castToType<QAttribute::Short>(info.data, info.byteOffset));
+ return;
+ case QAttribute::UnsignedShort: f(info, castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset));
+ return;
+ case QAttribute::Int: f(info, castToType<QAttribute::Int>(info.data, info.byteOffset));
+ return;
+ case QAttribute::UnsignedInt: f(info, castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset));
+ return;
+ case QAttribute::Float: f(info, castToType<QAttribute::Float>(info.data, info.byteOffset));
+ return;
+ case QAttribute::Double: f(info, castToType<QAttribute::Double>(info.data, info.byteOffset));
+ return;
+ default:
+ return;
+ }
+}
+
+template<typename VertexExecutor, typename IndexExecutor, typename Visitor>
+void visitPrimitives(NodeManagers *manager, const GeometryRenderer *renderer, Visitor* visitor)
+{
+ Geometry *geom = manager->lookupResource<Geometry, GeometryManager>(renderer->geometryId());
+ Attribute *positionAttribute = nullptr;
+ Attribute *indexAttribute = nullptr;
+ Buffer *positionBuffer = nullptr;
+ Buffer *indexBuffer = nullptr;
+
+ if (geom) {
+ Qt3DRender::Render::Attribute *attribute = nullptr;
+ const auto attrIds = geom->attributes();
+ for (const Qt3DCore::QNodeId attrId : attrIds) {
+ attribute = manager->lookupResource<Attribute, AttributeManager>(attrId);
+ if (attribute){
+ if (attribute->name() == QAttribute::defaultPositionAttributeName())
+ positionAttribute = attribute;
+ else if (attribute->attributeType() == QAttribute::IndexAttribute)
+ indexAttribute = attribute;
+ }
+ }
+
+ if (positionAttribute)
+ positionBuffer = manager->lookupResource<Buffer, BufferManager>(positionAttribute->bufferId());
+ if (indexAttribute)
+ indexBuffer = manager->lookupResource<Buffer, BufferManager>(indexAttribute->bufferId());
+
+ if (positionBuffer) {
+
+ BufferInfo vertexBufferInfo;
+ vertexBufferInfo.data = positionBuffer->data();
+ vertexBufferInfo.type = positionAttribute->vertexBaseType();
+ vertexBufferInfo.byteOffset = positionAttribute->byteOffset();
+ vertexBufferInfo.byteStride = positionAttribute->byteStride();
+ vertexBufferInfo.dataSize = positionAttribute->vertexSize();
+ vertexBufferInfo.count = positionAttribute->count();
+
+ if (indexBuffer) { // Indexed
+
+ BufferInfo indexBufferInfo;
+ indexBufferInfo.data = indexBuffer->data();
+ indexBufferInfo.type = indexAttribute->vertexBaseType();
+ indexBufferInfo.byteOffset = indexAttribute->byteOffset();
+ indexBufferInfo.byteStride = indexAttribute->byteStride();
+ indexBufferInfo.count = indexAttribute->count();
+
+ IndexExecutor executor;
+ executor.m_vertexBufferInfo = vertexBufferInfo;
+ executor.m_primitiveType = renderer->primitiveType();
+ executor.m_visitor = visitor;
+
+ return processBuffer(indexBufferInfo, executor);
+
+ } else { // Non Indexed
+
+ // Check into which type the buffer needs to be casted
+ VertexExecutor executor;
+ executor.m_primitiveType = renderer->primitiveType();
+ executor.m_visitor = visitor;
+
+ return processBuffer(vertexBufferInfo, executor);
+ }
+ }
+ }
+}
+
+} // namespace Visitor
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_VISITORUTILS_P_H