diff options
Diffstat (limited to 'src/render/backend')
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 ¶meters, const QMatrix4x4 &worldTransform, - const QVector<LightSource> &activeLightSources, EnvironmentLight *environmentLight) const +void RenderView::setShaderAndUniforms(RenderCommand *command, + RenderPass *rPass, + ParameterInfoList ¶meters, + 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 ¶meters, const QMatrix4x4 &worldTransform, - const QVector<LightSource> &activeLightSources, EnvironmentLight *environmentLight) const; + void setShaderAndUniforms(RenderCommand *command, + RenderPass *pass, + ParameterInfoList ¶meters, + 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 |