diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-11-02 03:02:38 +0100 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-11-02 03:02:38 +0100 |
commit | bfeba7c431fd7bebbf7163853cb2e6a327e188aa (patch) | |
tree | f89b0abaef1cf74acb5cfe88648cd23c642a6a24 | |
parent | c9d4103e52b28c7a242d90433112bfaedb77f0cc (diff) | |
parent | fae98c57264e78e62c5955559c7e513969462a79 (diff) |
Merge remote-tracking branch 'origin/5.14' into 5.15
Change-Id: I8564907ed5efd7617be383017fe12ffa7cd3a0d1
33 files changed, 552 insertions, 442 deletions
diff --git a/src/core/aspects/qaspectmanager.cpp b/src/core/aspects/qaspectmanager.cpp index dffdd1c1a..f24248399 100644 --- a/src/core/aspects/qaspectmanager.cpp +++ b/src/core/aspects/qaspectmanager.cpp @@ -414,6 +414,8 @@ bool QAspectManager::event(QEvent *e) // the loop if (m_simulationLoopRunning && m_driveMode == QAspectEngine::Automatic) requestNextFrame(); + + return true; } return QObject::event(e); @@ -424,7 +426,7 @@ void QAspectManager::requestNextFrame() qCDebug(Aspects) << "Requesting new Frame"; // Post event in the event loop to force // next frame to be processed - qApp->postEvent(this, new RequestFrameEvent()); + QCoreApplication::postEvent(this, new RequestFrameEvent()); } void QAspectManager::processFrame() @@ -436,6 +438,8 @@ void QAspectManager::processFrame() m_serviceLocator->service<QAbstractFrameAdvanceService>(QServiceLocator::FrameAdvanceService); const qint64 t = frameAdvanceService->waitForNextFrame(); + if (t < 0) + return; // Distribute accumulated changes. This includes changes sent from the frontend // to the backend nodes. We call this before the call to m_scheduler->update() to ensure diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp index cfe83f4db..739b46cfe 100644 --- a/src/core/nodes/qnode.cpp +++ b/src/core/nodes/qnode.cpp @@ -683,6 +683,11 @@ void QNodePrivate::update() void QNodePrivate::updateNode(QNode *node, const char *property, ChangeFlag change) { if (m_changeArbiter) { + // Ensure node has its postConstructorInit called if we reach this + // point, we could otherwise endup referencing a node that has yet + // to be created in the backend + QNodePrivate::get(node)->_q_ensureBackendNodeCreated(); + Q_Q(QNode); m_changeArbiter->addDirtyFrontEndNode(q, node, property, change); } diff --git a/src/doc/src/qmlextramaterials.qdoc b/src/doc/src/qmlextramaterials.qdoc index e0a2e9edf..338bada09 100644 --- a/src/doc/src/qmlextramaterials.qdoc +++ b/src/doc/src/qmlextramaterials.qdoc @@ -544,6 +544,41 @@ The default value is 0.5. */ +/*! + \qmlproperty BlendEquationArguments::Blending PhongAlphaMaterial::sourceRgbArg + + Holds the blend equation source RGB blending argument. + + \sa Qt3DRender::QBlendEquationArguments::Blending +*/ +/*! + \qmlproperty BlendEquationArguments::Blending PhongAlphaMaterial::destinationRgbArg + + Holds the blend equation destination RGB blending argument. + + \sa Qt3DRender::QBlendEquationArguments::Blending +*/ +/*! + \qmlproperty BlendEquationArguments::Blending PhongAlphaMaterial::sourceAlphaArg + + Holds the blend equation source alpha blending argument. + + \sa Qt3DRender::QBlendEquationArguments::Blending +*/ +/*! + \qmlproperty BlendEquationArguments::Blending PhongAlphaMaterial::destinationAlphaArg + + Holds the blend equation destination alpha blending argument. + + \sa Qt3DRender::QBlendEquationArguments::Blending +*/ +/*! + \qmlproperty BlendEquation::BlendFunction PhongAlphaMaterial::blendFunctionArg + + Holds the blend equation function argument. + + \sa Qt3DRender::QBlendEquation::BlendFunction +*/ /*! \qmltype PhongMaterial diff --git a/src/quick3d/imports/scene3d/scene3ditem.cpp b/src/quick3d/imports/scene3d/scene3ditem.cpp index 55e972406..0fbde1191 100644 --- a/src/quick3d/imports/scene3d/scene3ditem.cpp +++ b/src/quick3d/imports/scene3d/scene3ditem.cpp @@ -581,25 +581,45 @@ bool Scene3DItem::isHoverEnabled() const void Scene3DItem::setCameraAspectModeHelper() { - switch (m_cameraAspectRatioMode) { - case AutomaticAspectRatio: - connect(this, &Scene3DItem::widthChanged, this, &Scene3DItem::updateCameraAspectRatio); - connect(this, &Scene3DItem::heightChanged, this, &Scene3DItem::updateCameraAspectRatio); - // Update the aspect ratio the first time the surface is set - updateCameraAspectRatio(); - break; - case UserAspectRatio: - disconnect(this, &Scene3DItem::widthChanged, this, &Scene3DItem::updateCameraAspectRatio); - disconnect(this, &Scene3DItem::heightChanged, this, &Scene3DItem::updateCameraAspectRatio); - break; + if (m_compositingMode == FBO) { + switch (m_cameraAspectRatioMode) { + case AutomaticAspectRatio: + connect(this, &Scene3DItem::widthChanged, this, &Scene3DItem::updateCameraAspectRatio); + connect(this, &Scene3DItem::heightChanged, this, &Scene3DItem::updateCameraAspectRatio); + // Update the aspect ratio the first time the surface is set + updateCameraAspectRatio(); + break; + case UserAspectRatio: + disconnect(this, &Scene3DItem::widthChanged, this, &Scene3DItem::updateCameraAspectRatio); + disconnect(this, &Scene3DItem::heightChanged, this, &Scene3DItem::updateCameraAspectRatio); + break; + } + } else { + // In Underlay mode, we rely on the window for aspect ratio and not the size of the Scene3DItem + switch (m_cameraAspectRatioMode) { + case AutomaticAspectRatio: + connect(window(), &QWindow::widthChanged, this, &Scene3DItem::updateCameraAspectRatio); + connect(window(), &QWindow::heightChanged, this, &Scene3DItem::updateCameraAspectRatio); + // Update the aspect ratio the first time the surface is set + updateCameraAspectRatio(); + break; + case UserAspectRatio: + disconnect(window(), &QWindow::widthChanged, this, &Scene3DItem::updateCameraAspectRatio); + disconnect(window(), &QWindow::heightChanged, this, &Scene3DItem::updateCameraAspectRatio); + break; + } } } void Scene3DItem::updateCameraAspectRatio() { if (m_camera) { - m_camera->setAspectRatio(static_cast<float>(width()) / - static_cast<float>(height())); + if (m_compositingMode == FBO) + m_camera->setAspectRatio(static_cast<float>(width()) / + static_cast<float>(height())); + else + m_camera->setAspectRatio(static_cast<float>(window()->width()) / + static_cast<float>(window()->height())); } } diff --git a/src/quick3d/imports/scene3d/scene3dview.cpp b/src/quick3d/imports/scene3d/scene3dview.cpp index 9d298b435..f38d135f0 100644 --- a/src/quick3d/imports/scene3d/scene3dview.cpp +++ b/src/quick3d/imports/scene3d/scene3dview.cpp @@ -278,6 +278,8 @@ QSGNode *Scene3DView::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNode if (m_dirtyFlags & DirtyTexture) { fboNode->setTexture(m_texture); m_dirtyFlags.setFlag(DirtyTexture, false); + // Show FBO Node at this point + fboNode->show(); } if (m_dirtyFlags & DirtyNode) { fboNode->markDirty(QSGNode::DirtyMaterial); diff --git a/src/render/framegraph/qbuffercapture.cpp b/src/render/framegraph/qbuffercapture.cpp index 0c12a3aff..c71c0adb7 100644 --- a/src/render/framegraph/qbuffercapture.cpp +++ b/src/render/framegraph/qbuffercapture.cpp @@ -62,6 +62,14 @@ QBufferCapturePrivate::QBufferCapturePrivate() \inmodule Qt3DRender \brief Exchanges buffer data between GPU and CPU. */ + +/*! + \qmltype BufferCapture + \inqmlmodule Qt3D.Render + \instantiates Qt3DRender::QBufferCapture + \brief Exchanges buffer data between GPU and CPU. +*/ + QBufferCapture::QBufferCapture(Qt3DCore::QNode *parent) : QFrameGraphNode(*new QBufferCapturePrivate, parent) { diff --git a/src/render/geometry/buffer.cpp b/src/render/geometry/buffer.cpp index 0d634c911..6db3bab44 100644 --- a/src/render/geometry/buffer.cpp +++ b/src/render/geometry/buffer.cpp @@ -137,20 +137,31 @@ void Buffer::syncFromFrontEnd(const QNode *frontEnd, bool firstTime) m_manager->addDirtyBuffer(peerId()); } { - QVariant v = node->property("QT3D_updateData"); - if (v.isValid()) { + const QVariant v = node->property("QT3D_updateData"); + + // Make sure we record data if it's the first time we are called + // or if we have no partial updates + if (firstTime || !v.isValid()){ + const QByteArray newData = node->data(); + const bool dirty = m_data != newData; + m_bufferDirty |= dirty; + m_data = newData; + + // Since frontend applies partial updates to its m_data + // if we enter this code block, there's no problem in actually + // ignoring the partial updates + if (v.isValid()) + const_cast<QBuffer *>(node)->setProperty("QT3D_updateData", {}); + + if (dirty && !m_data.isEmpty()) + forceDataUpload(); + } else if (v.isValid()) { + // Apply partial updates and record them to allow partial upload to the GPU Qt3DRender::QBufferUpdate updateData = v.value<Qt3DRender::QBufferUpdate>(); m_data.replace(updateData.offset, updateData.data.size(), updateData.data); m_bufferUpdates.push_back(updateData); m_bufferDirty = true; const_cast<QBuffer *>(node)->setProperty("QT3D_updateData", {}); - } else { - QByteArray newData = node->data(); - bool dirty = m_data != newData; - m_bufferDirty |= dirty; - m_data = newData; - if (dirty && !m_data.isEmpty()) - forceDataUpload(); } } markDirty(AbstractRenderer::BuffersDirty); diff --git a/src/render/geometry/geometryrenderer.cpp b/src/render/geometry/geometryrenderer.cpp index 3b460f48c..881c0f66b 100644 --- a/src/render/geometry/geometryrenderer.cpp +++ b/src/render/geometry/geometryrenderer.cpp @@ -139,8 +139,16 @@ void GeometryRenderer::syncFromFrontEnd(const QNode *frontEnd, bool firstTime) if (functorDirty) { m_dirty = true; m_geometryFactory = newFunctor; - if (m_geometryFactory && m_manager != nullptr) + if (m_geometryFactory && m_manager != nullptr) { m_manager->addDirtyGeometryRenderer(peerId()); + + const bool isQMeshFunctor = m_geometryFactory->id() == Qt3DRender::functorTypeId<MeshLoaderFunctor>(); + if (isQMeshFunctor) { + const QMesh *meshNode = static_cast<const QMesh *>(node); + QMeshPrivate *dmeshNode = QMeshPrivate::get(const_cast<QMesh *>(meshNode)); + dmeshNode->setStatus(QMesh::Loading); + } + } } markDirty(AbstractRenderer::GeometryDirty); diff --git a/src/render/jobs/filterentitybycomponentjob_p.h b/src/render/jobs/filterentitybycomponentjob_p.h index dd64e50a7..75e487d7f 100644 --- a/src/render/jobs/filterentitybycomponentjob_p.h +++ b/src/render/jobs/filterentitybycomponentjob_p.h @@ -97,10 +97,6 @@ private: QVector<Entity *> m_filteredEntities; }; -template<typename T, typename ... Ts> -using FilterEntityByComponentJobPtr = QSharedPointer<FilterEntityByComponentJob<T, Ts...>>; - - } // Render } // Qt3DRender diff --git a/src/render/jobs/lightgatherer.cpp b/src/render/jobs/lightgatherer.cpp index b76cd4d73..f4c8dfba8 100644 --- a/src/render/jobs/lightgatherer.cpp +++ b/src/render/jobs/lightgatherer.cpp @@ -58,6 +58,9 @@ LightGatherer::LightGatherer() void LightGatherer::run() { + m_lights.clear(); + m_environmentLight = nullptr; + const QVector<HEntity> handles = m_manager->activeHandles(); int envLightCount = 0; diff --git a/src/render/renderers/opengl/jobs/renderviewcommandbuilderjob_p.h b/src/render/renderers/opengl/jobs/renderviewcommandbuilderjob_p.h index 725f83b62..9f45a8005 100644 --- a/src/render/renderers/opengl/jobs/renderviewcommandbuilderjob_p.h +++ b/src/render/renderers/opengl/jobs/renderviewcommandbuilderjob_p.h @@ -68,14 +68,14 @@ public: inline void setRenderView(RenderView *rv) Q_DECL_NOTHROW { m_renderView = rv; } inline void setEntities(const QVector<Entity *> &entities) { m_entities = entities; } - inline QVector<EntityRenderCommandData> &commandData() { return m_commandData; } + inline EntityRenderCommandData &commandData() { return m_commandData; } void run() final; private: RenderView *m_renderView; QVector<Entity *> m_entities; - QVector<EntityRenderCommandData> m_commandData; + EntityRenderCommandData m_commandData; }; typedef QSharedPointer<RenderViewCommandBuilderJob> RenderViewCommandBuilderJobPtr; diff --git a/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob.cpp b/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob.cpp index d58b288e6..af1d545ed 100644 --- a/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob.cpp +++ b/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob.cpp @@ -70,11 +70,7 @@ void RenderViewCommandUpdaterJob::run() // Copy commands out of cached -> ensures we can submit them for rendering // while cache is rebuilt or modified for next frame - QVector<RenderCommand> commands; - commands.reserve(m_renderables.size()); - for (const EntityRenderCommandData *data : m_renderables) - commands.push_back(data->command); - m_commands = commands; + m_commands = m_renderables.commands; } } diff --git a/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob_p.h b/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob_p.h index 3fff5f1a0..72caef6cf 100644 --- a/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob_p.h +++ b/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob_p.h @@ -71,7 +71,7 @@ public: inline void setRenderView(RenderView *rv) Q_DECL_NOTHROW { m_renderView = rv; } inline void setRenderer(Renderer *renderer) Q_DECL_NOTHROW { m_renderer = renderer; } - inline void setRenderables(const QVector<EntityRenderCommandData *> &renderables) Q_DECL_NOTHROW { m_renderables = renderables; } + inline void setRenderables(const EntityRenderCommandData &renderables) Q_DECL_NOTHROW { m_renderables = renderables; } QVector<RenderCommand> &commands() Q_DECL_NOTHROW { return m_commands; } @@ -80,7 +80,7 @@ public: private: RenderView *m_renderView; Renderer *m_renderer; - QVector<EntityRenderCommandData *> m_renderables; + EntityRenderCommandData m_renderables; QVector<RenderCommand> m_commands; }; diff --git a/src/render/renderers/opengl/renderer/rendercommand_p.h b/src/render/renderers/opengl/renderer/rendercommand_p.h index 58ab0cadd..0180d6996 100644 --- a/src/render/renderers/opengl/renderer/rendercommand_p.h +++ b/src/render/renderers/opengl/renderer/rendercommand_p.h @@ -131,11 +131,58 @@ inline bool operator!=(const RenderCommand &lhs, const RenderCommand &rhs) noexc struct EntityRenderCommandData { - Entity *entity; - RenderCommand command; - RenderPassParameterData passData; + QVector<Entity *> entities; + QVector<RenderCommand> commands; + QVector<RenderPassParameterData> passesData; + + void reserve(int size) + { + entities.reserve(size); + commands.reserve(size); + passesData.reserve(size); + } + + inline int size() const { return entities.size(); } + + inline void push_back(Entity *e, const RenderCommand &c, const RenderPassParameterData &p) + { + entities.push_back(e); + commands.push_back(c); + passesData.push_back(p); + } + + inline void push_back(Entity *e, RenderCommand &&c, RenderPassParameterData &&p) + { + entities.push_back(e); + commands.push_back(std::move(c)); + passesData.push_back(std::move(p)); + } + + EntityRenderCommandData &operator+=(const EntityRenderCommandData &t) + { + entities += t.entities; + commands += t.commands; + passesData += t.passesData; + return *this; + } + + EntityRenderCommandData &operator+=(EntityRenderCommandData &&t) + { + entities += std::move(t.entities); + commands += std::move(t.commands); + passesData += std::move(t.passesData); + return *this; + } + + EntityRenderCommandData mid(int idx, int len) const + { + return { entities.mid(idx, len), commands.mid(idx, len), passesData.mid(idx, len) }; + } + + }; + } // namespace Render } // namespace Qt3DRender diff --git a/src/render/renderers/opengl/renderer/renderer.cpp b/src/render/renderers/opengl/renderer/renderer.cpp index 9220a719a..a530c26b0 100644 --- a/src/render/renderers/opengl/renderer/renderer.cpp +++ b/src/render/renderers/opengl/renderer/renderer.cpp @@ -93,6 +93,7 @@ #include <Qt3DRender/private/subtreeenabler_p.h> #include <Qt3DRender/private/qshaderprogrambuilder_p.h> #include <Qt3DRender/private/qshaderprogram_p.h> +#include <Qt3DRender/private/filterentitybycomponentjob_p.h> #include <Qt3DRender/qcameralens.h> #include <Qt3DCore/private/qeventfilterservice_p.h> @@ -138,6 +139,82 @@ using namespace Qt3DCore; namespace Qt3DRender { namespace Render { + +namespace { + +class SyncLightsGatherer +{ +public: + explicit SyncLightsGatherer(LightGathererPtr gatherJob, + RendererCache *cache) + : m_gatherJob(gatherJob) + , m_cache(cache) + { + } + + void operator()() + { + QMutexLocker lock(m_cache->mutex()); + m_cache->gatheredLights = m_gatherJob->lights(); + m_cache->environmentLight = m_gatherJob->takeEnvironmentLight(); + } + +private: + LightGathererPtr m_gatherJob; + RendererCache *m_cache; +}; + +class SyncRenderableEntities +{ +public: + explicit SyncRenderableEntities(RenderableEntityFilterPtr gatherJob, + RendererCache *cache) + : m_gatherJob(gatherJob) + , m_cache(cache) + { + } + + void operator()() + { + QVector<Entity *> selectedEntities = m_gatherJob->filteredEntities(); + std::sort(selectedEntities.begin(), selectedEntities.end()); + + QMutexLocker lock(m_cache->mutex()); + m_cache->renderableEntities = selectedEntities; + } + +private: + RenderableEntityFilterPtr m_gatherJob; + RendererCache *m_cache; +}; + +class SyncComputableEntities +{ +public: + explicit SyncComputableEntities(ComputableEntityFilterPtr gatherJob, + RendererCache *cache) + : m_gatherJob(gatherJob) + , m_cache(cache) + { + } + + void operator()() + { + QVector<Entity *> selectedEntities = m_gatherJob->filteredEntities(); + std::sort(selectedEntities.begin(), selectedEntities.end()); + + QMutexLocker lock(m_cache->mutex()); + m_cache->computeEntities = selectedEntities; + } + +private: + ComputableEntityFilterPtr m_gatherJob; + RendererCache *m_cache; +}; + +} // anonymous + + /*! \internal @@ -193,6 +270,9 @@ Renderer::Renderer(QRenderAspect::RenderType type) , m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create()) , m_filterCompatibleTechniqueJob(Render::FilterCompatibleTechniqueJobPtr::create()) , m_updateEntityLayersJob(Render::UpdateEntityLayersJobPtr::create()) + , m_lightGathererJob(Render::LightGathererPtr::create()) + , m_renderableEntityFilterJob(Render::RenderableEntityFilterPtr::create()) + , m_computableEntityFilterJob(Render::ComputableEntityFilterPtr::create()) , m_bufferGathererJob(SynchronizerJobPtr::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering)) , m_vaoGathererJob(SynchronizerJobPtr::create([this] { lookForAbandonedVaos(); }, JobTypes::DirtyVaoGathering)) , m_textureGathererJob(SynchronizerJobPtr::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering)) @@ -207,6 +287,12 @@ Renderer::Renderer(QRenderAspect::RenderType type) [this] (Qt3DCore::QAspectManager *m) { sendShaderChangesToFrontend(m); }, JobTypes::DirtyShaderGathering)) , m_syncLoadingJobs(SynchronizerJobPtr::create([] {}, JobTypes::SyncLoadingJobs)) + , m_cacheRenderableEntitiesJob(SynchronizerJobPtr::create(SyncRenderableEntities(m_renderableEntityFilterJob, &m_cache), + JobTypes::EntityComponentTypeFiltering)) + , m_cacheComputableEntitiesJob(SynchronizerJobPtr::create(SyncComputableEntities(m_computableEntityFilterJob, &m_cache), + JobTypes::EntityComponentTypeFiltering)) + , m_cacheLightsJob(SynchronizerJobPtr::create(SyncLightsGatherer(m_lightGathererJob, &m_cache), + JobTypes::EntityComponentTypeFiltering)) , m_ownedContext(false) , m_offscreenHelper(nullptr) , m_shouldSwapBuffers(true) @@ -240,6 +326,10 @@ Renderer::Renderer(QRenderAspect::RenderType type) m_introspectShaderJob->addDependency(m_filterCompatibleTechniqueJob); + m_cacheLightsJob->addDependency(m_lightGathererJob); + m_cacheRenderableEntitiesJob->addDependency(m_renderableEntityFilterJob); + m_cacheComputableEntitiesJob->addDependency(m_computableEntityFilterJob); + m_filterCompatibleTechniqueJob->setRenderer(this); m_defaultRenderStateSet = new RenderStateSet; @@ -309,6 +399,9 @@ void Renderer::setNodeManagers(NodeManagers *managers) m_updateEntityLayersJob->setManager(m_nodesManager); m_updateTreeEnabledJob->setManagers(m_nodesManager); m_sendBufferCaptureJob->setManagers(m_nodesManager); + m_lightGathererJob->setManager(m_nodesManager->renderNodesManager()); + m_renderableEntityFilterJob->setManager(m_nodesManager->renderNodesManager()); + m_computableEntityFilterJob->setManager(m_nodesManager->renderNodesManager()); } void Renderer::setServices(QServiceLocator *services) @@ -1862,6 +1955,21 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() if (layersDirty) renderBinJobs.push_back(m_updateEntityLayersJob); + if (renderableDirty) { + renderBinJobs.push_back(m_renderableEntityFilterJob); + renderBinJobs.push_back(m_cacheRenderableEntitiesJob); + } + + if (computeableDirty) { + renderBinJobs.push_back(m_computableEntityFilterJob); + renderBinJobs.push_back(m_cacheComputableEntitiesJob); + } + + if (lightsDirty) { + renderBinJobs.push_back(m_lightGathererJob); + renderBinJobs.push_back(m_cacheLightsJob); + } + 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 @@ -1892,11 +2000,7 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() // If we have a new RV (wasn't in the cache before, then it contains no cached data) const bool isNewRV = !m_cache.leafNodeCache.contains(leaf); builder.setLayerCacheNeedsToBeRebuilt(layersCacheNeedsToBeRebuilt || isNewRV); - builder.setRenderableCacheNeedsToBeRebuilt(renderableDirty || isNewRV); - builder.setComputableCacheNeedsToBeRebuilt(computeableDirty || isNewRV); - builder.setLightGathererCacheNeedsToBeRebuilt(lightsDirty || isNewRV); builder.setMaterialGathererCacheNeedsToBeRebuilt(materialCacheNeedsToBeRebuilt || isNewRV); - builder.setLightGathererCacheNeedsToBeRebuilt(lightsDirty || isNewRV); builder.setRenderCommandCacheNeedsToBeRebuilt(renderCommandsDirty || isNewRV); builder.prepareJobs(); diff --git a/src/render/renderers/opengl/renderer/renderer_p.h b/src/render/renderers/opengl/renderer/renderer_p.h index f007ab05c..b2889bb0e 100644 --- a/src/render/renderers/opengl/renderer/renderer_p.h +++ b/src/render/renderers/opengl/renderer/renderer_p.h @@ -82,6 +82,7 @@ #include <Qt3DRender/private/texture_p.h> #include <Qt3DRender/private/glfence_p.h> #include <Qt3DRender/private/shaderbuilder_p.h> +#include <Qt3DRender/private/lightgatherer_p.h> #include <QHash> #include <QMatrix4x4> @@ -158,6 +159,13 @@ typedef QSharedPointer<UpdateLevelOfDetailJob> UpdateLevelOfDetailJobPtr; using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>; using SynchronizerPostFramePtr = GenericLambdaJobAndPostFramePtr<std::function<void ()>, std::function<void (Qt3DCore::QAspectManager *)>>; +template<typename T, typename ... Ts> +class FilterEntityByComponentJob; +template<typename T, typename ... Ts> +using FilterEntityByComponentJobPtr = QSharedPointer<FilterEntityByComponentJob<T, Ts...>>; +using ComputableEntityFilterPtr = FilterEntityByComponentJobPtr<Render::ComputeCommand, Render::Material>; +using RenderableEntityFilterPtr = FilterEntityByComponentJobPtr<Render::GeometryRenderer, Render::Material>; + class Q_3DRENDERSHARED_PRIVATE_EXPORT Renderer : public AbstractRenderer { public: @@ -227,6 +235,12 @@ public: inline Qt3DCore::QAspectJobPtr textureGathererJob() const { return m_textureGathererJob; } inline Qt3DCore::QAspectJobPtr sendTextureChangesToFrontendJob() const { return m_sendTextureChangesToFrontendJob; } inline UpdateEntityLayersJobPtr updateEntityLayersJob() const { return m_updateEntityLayersJob; } + inline LightGathererPtr lightGathererJob() const { return m_lightGathererJob; } + inline RenderableEntityFilterPtr renderableEntityFilterJob() const { return m_renderableEntityFilterJob; } + inline ComputableEntityFilterPtr computableEntityFilterJob() const { return m_computableEntityFilterJob; } + inline SynchronizerJobPtr cacheLightJob() const { return m_cacheLightsJob; } + inline SynchronizerJobPtr cacheRenderableEntitiesJob() const { return m_cacheRenderableEntitiesJob; } + inline SynchronizerJobPtr cacheComputableEntitiesJob() const { return m_cacheComputableEntitiesJob; } Qt3DCore::QAbstractFrameAdvanceService *frameAdvanceService() const override; @@ -369,6 +383,9 @@ private: UpdateMeshTriangleListJobPtr m_updateMeshTriangleListJob; FilterCompatibleTechniqueJobPtr m_filterCompatibleTechniqueJob; UpdateEntityLayersJobPtr m_updateEntityLayersJob; + LightGathererPtr m_lightGathererJob; + RenderableEntityFilterPtr m_renderableEntityFilterJob; + ComputableEntityFilterPtr m_computableEntityFilterJob; QVector<Qt3DCore::QNodeId> m_pendingRenderCaptureSendRequests; @@ -386,6 +403,9 @@ private: SynchronizerPostFramePtr m_sendDisablesToFrontendJob; SynchronizerPostFramePtr m_introspectShaderJob; SynchronizerJobPtr m_syncLoadingJobs; + SynchronizerJobPtr m_cacheRenderableEntitiesJob; + SynchronizerJobPtr m_cacheComputableEntitiesJob; + SynchronizerJobPtr m_cacheLightsJob; void lookForAbandonedVaos(); void lookForDirtyBuffers(); diff --git a/src/render/renderers/opengl/renderer/renderercache_p.h b/src/render/renderers/opengl/renderer/renderercache_p.h index a1298f491..02fe4ff41 100644 --- a/src/render/renderers/opengl/renderer/renderercache_p.h +++ b/src/render/renderers/opengl/renderer/renderercache_p.h @@ -70,13 +70,16 @@ struct RendererCache { QVector<Entity *> filterEntitiesByLayer; MaterialParameterGathererData materialParameterGatherer; - QVector<LightSource> gatheredLights; - QVector<Entity *> renderableEntities; - QVector<Entity *> computeEntities; - EnvironmentLight* environmentLight; - QVector<EntityRenderCommandData> renderCommandData; + EntityRenderCommandData renderCommandData; }; + // Shared amongst all RV cache + QVector<Entity *> renderableEntities; + QVector<Entity *> computeEntities; + QVector<LightSource> gatheredLights; + EnvironmentLight* environmentLight; + + // Per RV cache QHash<FrameGraphNode *, LeafNodeData> leafNodeCache; QMutex *mutex() { return &m_mutex; } diff --git a/src/render/renderers/opengl/renderer/renderview.cpp b/src/render/renderers/opengl/renderer/renderview.cpp index 7fb1c5fb9..97d494370 100644 --- a/src/render/renderers/opengl/renderer/renderview.cpp +++ b/src/render/renderers/opengl/renderer/renderview.cpp @@ -621,11 +621,11 @@ void RenderView::addClearBuffers(const ClearBuffers *cb) { } // If we are there, we know that entity had a GeometryRenderer + Material -QVector<EntityRenderCommandData> RenderView::buildDrawRenderCommands(const QVector<Entity *> &entities) const +EntityRenderCommandData RenderView::buildDrawRenderCommands(const QVector<Entity *> &entities) const { - QVector<EntityRenderCommandData> commands; - commands.reserve(entities.size()); + EntityRenderCommandData commands; + commands.reserve(entities.size()); for (Entity *entity : entities) { GeometryRenderer *geometryRenderer = nullptr; @@ -662,8 +662,9 @@ QVector<EntityRenderCommandData> RenderView::buildDrawRenderCommands(const QVect } command.m_shader = m_manager->lookupHandle<Shader, ShaderManager, HShader>(pass->shaderProgram()); - const EntityRenderCommandData commandData = { entity, command, passData }; - commands.append(commandData); + commands.push_back(entity, + std::move(command), + std::move(passData)); } } } @@ -671,15 +672,17 @@ QVector<EntityRenderCommandData> RenderView::buildDrawRenderCommands(const QVect return commands; } -QVector<EntityRenderCommandData> RenderView::buildComputeRenderCommands(const QVector<Entity *> &entities) const +EntityRenderCommandData RenderView::buildComputeRenderCommands(const QVector<Entity *> &entities) const { // If the RenderView contains only a ComputeDispatch then it cares about // A ComputeDispatch is also implicitely a NoDraw operation // enabled flag // layer component // material/effect/technique/parameters/filters/ - QVector<EntityRenderCommandData> commands; + EntityRenderCommandData commands; + commands.reserve(entities.size()); + for (Entity *entity : entities) { ComputeCommand *computeJob = nullptr; HComputeCommand computeCommandHandle = entity->componentHandle<ComputeCommand>(); @@ -712,8 +715,9 @@ QVector<EntityRenderCommandData> RenderView::buildComputeRenderCommands(const QV command.m_workGroups[1] = std::max(m_workGroups[1], computeJob->y()); command.m_workGroups[2] = std::max(m_workGroups[2], computeJob->z()); - const EntityRenderCommandData commandData = { entity, command, passData }; - commands.append(commandData); + commands.push_back(entity, + std::move(command), + std::move(passData)); } } } @@ -721,7 +725,7 @@ QVector<EntityRenderCommandData> RenderView::buildComputeRenderCommands(const QV return commands; } -void RenderView::updateRenderCommand(QVector<EntityRenderCommandData *> &renderCommandData) +void RenderView::updateRenderCommand(EntityRenderCommandData &renderCommandData) { // Note: since many threads can be building render commands // we need to ensure that the UniformBlockValueBuilder they are using @@ -731,10 +735,10 @@ void RenderView::updateRenderCommand(QVector<EntityRenderCommandData *> &renderC builder->textureManager = m_manager->textureManager(); m_localData.setLocalData(builder); - for (EntityRenderCommandData *commandData : renderCommandData) { - Entity *entity = commandData->entity; - RenderPassParameterData passData = commandData->passData; - RenderCommand &command = commandData->command; + for (int i = 0, m = renderCommandData.size(); i < m; ++i) { + Entity *entity = renderCommandData.entities.at(i); + const RenderPassParameterData passData = renderCommandData.passesData.at(i); + RenderCommand &command = renderCommandData.commands[i]; // Pick which lights to take in to account. // For now decide based on the distance by taking the MAX_LIGHTS closest lights. @@ -1010,7 +1014,8 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, if (lightIdx == MAX_LIGHTS) break; Entity *lightEntity = lightSource.entity; - const Vector3D worldPos = lightEntity->worldBoundingVolume()->center(); + const Matrix4x4 lightWorldTransform = *(lightEntity->worldTransform()); + const Vector3D worldPos = lightWorldTransform * Vector3D(0.0f, 0.0f, 0.0f); for (Light *light : lightSource.lights) { if (!light->isEnabled()) continue; diff --git a/src/render/renderers/opengl/renderer/renderview_p.h b/src/render/renderers/opengl/renderer/renderview_p.h index 7d148118d..1221e7a59 100644 --- a/src/render/renderers/opengl/renderer/renderview_p.h +++ b/src/render/renderers/opengl/renderer/renderview_p.h @@ -227,11 +227,11 @@ public: RenderPassList passesAndParameters(ParameterInfoList *parameter, Entity *node, bool useDefaultMaterials = true); - QVector<EntityRenderCommandData> buildDrawRenderCommands(const QVector<Entity *> &entities) const; - QVector<EntityRenderCommandData> buildComputeRenderCommands(const QVector<Entity *> &entities) const; + EntityRenderCommandData buildDrawRenderCommands(const QVector<Entity *> &entities) const; + EntityRenderCommandData buildComputeRenderCommands(const QVector<Entity *> &entities) const; - void updateRenderCommand(QVector<EntityRenderCommandData *> &renderCommandData); + void updateRenderCommand(EntityRenderCommandData &renderCommandData); void setCommands(const QVector<RenderCommand> &commands) Q_DECL_NOTHROW { m_commands = commands; } diff --git a/src/render/renderers/opengl/renderer/renderviewbuilder.cpp b/src/render/renderers/opengl/renderer/renderviewbuilder.cpp index 3c6521263..40179fbd6 100644 --- a/src/render/renderers/opengl/renderer/renderviewbuilder.cpp +++ b/src/render/renderers/opengl/renderer/renderviewbuilder.cpp @@ -73,9 +73,10 @@ public: // Split commands to build among jobs QMutexLocker lock(m_renderer->cache()->mutex()); // Rebuild RenderCommands for all entities in RV (ignoring filtering) - const RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode]; + RendererCache *cache = m_renderer->cache(); + const RendererCache::LeafNodeData &dataCacheForLeaf = cache->leafNodeCache[m_leafNode]; RenderView *rv = m_renderViewInitializer->renderView(); - const auto entities = !rv->isCompute() ? dataCacheForLeaf.renderableEntities : dataCacheForLeaf.computeEntities; + const auto entities = !rv->isCompute() ? cache->renderableEntities : cache->computeEntities; rv->setMaterialParameterTable(dataCacheForLeaf.materialParameterGatherer); @@ -256,21 +257,18 @@ public: if (!rv->noDraw()) { ///////// CACHE LOCKED //////////// // Retrieve Data from Cache - QMutexLocker lock(m_renderer->cache()->mutex()); - Q_ASSERT(m_renderer->cache()->leafNodeCache.contains(m_leafNode)); + RendererCache *cache = m_renderer->cache(); + QMutexLocker lock(cache->mutex()); + Q_ASSERT(cache->leafNodeCache.contains(m_leafNode)); const bool isDraw = !rv->isCompute(); - const RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode]; + const RendererCache::LeafNodeData &dataCacheForLeaf = cache->leafNodeCache[m_leafNode]; // Rebuild RenderCommands if required // This should happen fairly infrequently (FrameGraph Change, Geometry/Material change) // and allow to skip that step most of the time if (m_fullRebuild) { - // Clear previous cache - RendererCache::LeafNodeData &writableCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode]; - writableCacheForLeaf.renderCommandData.clear(); - - QVector<EntityRenderCommandData> commandData; + EntityRenderCommandData commandData; // Reduction { int totalCommandCount = 0; @@ -280,17 +278,19 @@ public: for (const RenderViewCommandBuilderJobPtr &renderViewCommandBuilder : qAsConst(m_renderViewCommandBuilderJobs)) commandData += std::move(renderViewCommandBuilder->commandData()); } - // Store in cache + + // Store new cache + RendererCache::LeafNodeData &writableCacheForLeaf = cache->leafNodeCache[m_leafNode]; writableCacheForLeaf.renderCommandData = std::move(commandData); } - const QVector<EntityRenderCommandData> commandData = dataCacheForLeaf.renderCommandData; + const EntityRenderCommandData commandData = dataCacheForLeaf.renderCommandData; - QVector<Entity *> renderableEntities = isDraw ? dataCacheForLeaf.renderableEntities : dataCacheForLeaf.computeEntities; const QVector<Entity *> filteredEntities = dataCacheForLeaf.filterEntitiesByLayer; - QVector<LightSource> lightSources = dataCacheForLeaf.gatheredLights; + QVector<Entity *> renderableEntities = isDraw ? cache->renderableEntities : cache->computeEntities; + QVector<LightSource> lightSources = cache->gatheredLights; rv->setMaterialParameterTable(dataCacheForLeaf.materialParameterGatherer); - rv->setEnvironmentLight(dataCacheForLeaf.environmentLight); + rv->setEnvironmentLight(cache->environmentLight); lock.unlock(); ///////// END OF CACHE LOCKED //////////// @@ -315,26 +315,28 @@ public: // Filter out Render commands for which the Entity wasn't selected because // of frustum, proximity or layer filtering - QVector<EntityRenderCommandData *> filteredCommandData; + EntityRenderCommandData filteredCommandData; filteredCommandData.reserve(renderableEntities.size()); // Because dataCacheForLeaf.renderableEntities or computeEntities are sorted // What we get out of EntityRenderCommandData is also sorted by Entity auto eIt = std::cbegin(renderableEntities); - auto cIt = std::cbegin(commandData); const auto eEnd = std::cend(renderableEntities); - const auto cEnd = std::cend(commandData); + int cIt = 0; + const int cEnd = commandData.size(); while (eIt != eEnd) { const Entity *targetEntity = *eIt; // Advance until we have commands whose Entity has a lower address // than the selected filtered entity - while (cIt->entity < targetEntity && cIt != cEnd) + while (cIt != cEnd && commandData.entities.at(cIt) < targetEntity) ++cIt; // Push pointers to command data for all commands that match the // entity - while (cIt->entity == targetEntity && cIt != cEnd) { - filteredCommandData.push_back(const_cast<EntityRenderCommandData *>(&(*cIt))); + while (cIt != cEnd && commandData.entities.at(cIt) == targetEntity) { + filteredCommandData.push_back(commandData.entities.at(cIt), + commandData.commands.at(cIt), + commandData.passesData.at(cIt)); ++cIt; } ++eIt; @@ -441,88 +443,6 @@ private: FrameGraphNode *m_leafNode; }; -class SyncLightsGatherer -{ -public: - explicit SyncLightsGatherer(LightGathererPtr gatherJob, - Renderer *renderer, - FrameGraphNode *leafNode) - : m_gatherJob(gatherJob) - , m_renderer(renderer) - , m_leafNode(leafNode) - { - } - - void operator()() - { - QMutexLocker lock(m_renderer->cache()->mutex()); - RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode]; - dataCacheForLeaf.gatheredLights = m_gatherJob->lights(); - dataCacheForLeaf.environmentLight = m_gatherJob->takeEnvironmentLight(); - } - -private: - LightGathererPtr m_gatherJob; - Renderer *m_renderer; - FrameGraphNode *m_leafNode; -}; - -class SyncRenderableEntities -{ -public: - explicit SyncRenderableEntities(RenderableEntityFilterPtr gatherJob, - Renderer *renderer, - FrameGraphNode *leafNode) - : m_gatherJob(gatherJob) - , m_renderer(renderer) - , m_leafNode(leafNode) - { - } - - void operator()() - { - QVector<Entity *> selectedEntities = m_gatherJob->filteredEntities(); - std::sort(selectedEntities.begin(), selectedEntities.end()); - - QMutexLocker lock(m_renderer->cache()->mutex()); - RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode]; - dataCacheForLeaf.renderableEntities = selectedEntities; - } - -private: - RenderableEntityFilterPtr m_gatherJob; - Renderer *m_renderer; - FrameGraphNode *m_leafNode; -}; - -class SyncComputableEntities -{ -public: - explicit SyncComputableEntities(ComputableEntityFilterPtr gatherJob, - Renderer *renderer, - FrameGraphNode *leafNode) - : m_gatherJob(gatherJob) - , m_renderer(renderer) - , m_leafNode(leafNode) - { - } - - void operator()() - { - QVector<Entity *> selectedEntities = m_gatherJob->filteredEntities(); - std::sort(selectedEntities.begin(), selectedEntities.end()); - - QMutexLocker lock(m_renderer->cache()->mutex()); - RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode]; - dataCacheForLeaf.computeEntities = selectedEntities; - } - -private: - ComputableEntityFilterPtr m_gatherJob; - Renderer *m_renderer; - FrameGraphNode *m_leafNode; -}; - } // anonymous RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int renderViewIndex, Renderer *renderer) @@ -531,9 +451,6 @@ RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int rende , m_renderer(renderer) , m_layerCacheNeedsToBeRebuilt(false) , m_materialGathererCacheNeedsToBeRebuilt(false) - , m_lightsCacheNeedsToBeRebuilt(false) - , m_renderableCacheNeedsToBeRebuilt(false) - , m_computableCacheNeedsToBeRebuilt(false) , m_renderCommandCacheNeedsToBeRebuilt(false) , m_renderViewJob(RenderViewInitializerJobPtr::create()) , m_filterEntityByLayerJob() @@ -555,21 +472,6 @@ FilterLayerEntityJobPtr RenderViewBuilder::filterEntityByLayerJob() const return m_filterEntityByLayerJob; } -LightGathererPtr RenderViewBuilder::lightGathererJob() const -{ - return m_lightGathererJob; -} - -RenderableEntityFilterPtr RenderViewBuilder::renderableEntityFilterJob() const -{ - return m_renderableEntityFilterJob; -} - -ComputableEntityFilterPtr RenderViewBuilder::computableEntityFilterJob() const -{ - return m_computableEntityFilterJob; -} - FrustumCullingJobPtr RenderViewBuilder::frustumCullingJob() const { return m_frustumCullingJob; @@ -638,39 +540,9 @@ FilterProximityDistanceJobPtr RenderViewBuilder::filterProximityJob() const void RenderViewBuilder::prepareJobs() { // Init what we can here - EntityManager *entityManager = m_renderer->nodeManagers()->renderNodesManager(); m_filterProximityJob->setManager(m_renderer->nodeManagers()); m_frustumCullingJob->setRoot(m_renderer->sceneRoot()); - if (m_lightsCacheNeedsToBeRebuilt) { - m_lightGathererJob = Render::LightGathererPtr::create(); - m_lightGathererJob->setManager(entityManager); - - m_cacheLightsJob = SynchronizerJobPtr::create(SyncLightsGatherer(m_lightGathererJob, m_renderer, m_leafNode), - JobTypes::EntityComponentTypeFiltering); - m_cacheLightsJob->addDependency(m_lightGathererJob); - } - - if (m_renderableCacheNeedsToBeRebuilt) { - m_renderableEntityFilterJob = RenderableEntityFilterPtr::create(); - m_renderableEntityFilterJob->setManager(entityManager); - - m_cacheRenderableEntitiesJob = SynchronizerJobPtr::create( - SyncRenderableEntities(m_renderableEntityFilterJob, m_renderer, m_leafNode), - JobTypes::EntityComponentTypeFiltering); - m_cacheRenderableEntitiesJob->addDependency(m_renderableEntityFilterJob); - } - - if (m_computableCacheNeedsToBeRebuilt) { - m_computableEntityFilterJob = ComputableEntityFilterPtr::create(); - m_computableEntityFilterJob->setManager(entityManager); - - m_cacheComputableEntitiesJob = SynchronizerJobPtr::create( - SyncComputableEntities(m_computableEntityFilterJob, m_renderer, m_leafNode), - JobTypes::EntityComponentTypeFiltering); - m_cacheComputableEntitiesJob->addDependency(m_computableEntityFilterJob); - } - if (m_renderCommandCacheNeedsToBeRebuilt) { m_renderViewCommandBuilderJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount); @@ -789,6 +661,7 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const m_syncRenderViewPreCommandUpdateJob->addDependency(m_renderer->introspectShadersJob()); m_syncRenderViewPreCommandUpdateJob->addDependency(m_renderer->bufferGathererJob()); m_syncRenderViewPreCommandUpdateJob->addDependency(m_renderer->textureGathererJob()); + m_syncRenderViewPreCommandUpdateJob->addDependency(m_renderer->cacheLightJob()); for (const auto &renderViewCommandUpdater : qAsConst(m_renderViewCommandUpdaterJobs)) { renderViewCommandUpdater->addDependency(m_syncRenderViewPreCommandUpdateJob); @@ -801,28 +674,11 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const // Add jobs jobs.push_back(m_renderViewJob); // Step 1 - if (m_lightsCacheNeedsToBeRebuilt) { - jobs.push_back(m_lightGathererJob); // Step 1 - jobs.push_back(m_cacheLightsJob); - m_syncRenderViewPreCommandUpdateJob->addDependency(m_cacheLightsJob); - } - - if (m_renderableCacheNeedsToBeRebuilt) { - jobs.push_back(m_renderableEntityFilterJob); // Step 1 - jobs.push_back(m_cacheRenderableEntitiesJob); - } - - if (m_computableCacheNeedsToBeRebuilt) { - // Note: do it only if OpenGL 4.3+ available - jobs.push_back(m_computableEntityFilterJob); // Step 1 - jobs.push_back(m_cacheComputableEntitiesJob); - } - jobs.push_back(m_syncRenderViewPostInitializationJob); // Step 2 if (m_renderCommandCacheNeedsToBeRebuilt) { // Step 3 - m_syncRenderViewPreCommandBuildingJob->addDependency(m_cacheComputableEntitiesJob); - m_syncRenderViewPreCommandBuildingJob->addDependency(m_cacheRenderableEntitiesJob); + m_syncRenderViewPreCommandBuildingJob->addDependency(m_renderer->cacheComputableEntitiesJob()); + m_syncRenderViewPreCommandBuildingJob->addDependency(m_renderer->cacheRenderableEntitiesJob()); m_syncRenderViewPreCommandBuildingJob->addDependency(m_syncRenderViewPostInitializationJob); if (m_materialGathererCacheNeedsToBeRebuilt) @@ -907,36 +763,6 @@ bool RenderViewBuilder::materialGathererCacheNeedsToBeRebuilt() const return m_materialGathererCacheNeedsToBeRebuilt; } -void RenderViewBuilder::setRenderableCacheNeedsToBeRebuilt(bool needsToBeRebuilt) -{ - m_renderableCacheNeedsToBeRebuilt = needsToBeRebuilt; -} - -bool RenderViewBuilder::renderableCacheNeedsToBeRebuilt() const -{ - return m_renderableCacheNeedsToBeRebuilt; -} - -void RenderViewBuilder::setComputableCacheNeedsToBeRebuilt(bool needsToBeRebuilt) -{ - m_computableCacheNeedsToBeRebuilt = needsToBeRebuilt; -} - -bool RenderViewBuilder::computableCacheNeedsToBeRebuilt() const -{ - return m_computableCacheNeedsToBeRebuilt; -} - -void RenderViewBuilder::setLightGathererCacheNeedsToBeRebuilt(bool needsToBeRebuilt) -{ - m_lightsCacheNeedsToBeRebuilt = needsToBeRebuilt; -} - -bool RenderViewBuilder::lightGathererCacheNeedsToBeRebuilt() const -{ - return m_lightsCacheNeedsToBeRebuilt; -} - void RenderViewBuilder::setRenderCommandCacheNeedsToBeRebuilt(bool needsToBeRebuilt) { m_renderCommandCacheNeedsToBeRebuilt = needsToBeRebuilt; diff --git a/src/render/renderers/opengl/renderer/renderviewbuilder_p.h b/src/render/renderers/opengl/renderer/renderviewbuilder_p.h index 66344da11..a2ab80e7e 100644 --- a/src/render/renderers/opengl/renderer/renderviewbuilder_p.h +++ b/src/render/renderers/opengl/renderer/renderviewbuilder_p.h @@ -53,7 +53,6 @@ #include <functional> #include <Qt3DCore/qaspectjob.h> -#include <Qt3DRender/private/filterentitybycomponentjob_p.h> #include <Qt3DRender/private/filterlayerentityjob_p.h> #include <Qt3DRender/private/genericlambdajob_p.h> #include <Qt3DRender/private/materialparametergathererjob_p.h> @@ -62,7 +61,6 @@ #include <Qt3DRender/private/renderviewcommandupdaterjob_p.h> #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 @@ -74,8 +72,6 @@ namespace Render { class Renderer; using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>; -using ComputableEntityFilterPtr = FilterEntityByComponentJobPtr<Render::ComputeCommand, Render::Material>; -using RenderableEntityFilterPtr = FilterEntityByComponentJobPtr<Render::GeometryRenderer, Render::Material>; class Q_AUTOTEST_EXPORT RenderViewBuilder { @@ -84,9 +80,6 @@ public: RenderViewInitializerJobPtr renderViewJob() const; FilterLayerEntityJobPtr filterEntityByLayerJob() const; - LightGathererPtr lightGathererJob() const; - RenderableEntityFilterPtr renderableEntityFilterJob() const; - ComputableEntityFilterPtr computableEntityFilterJob() const; FrustumCullingJobPtr frustumCullingJob() const; QVector<RenderViewCommandBuilderJobPtr> renderViewCommandBuilderJobs() const; QVector<RenderViewCommandUpdaterJobPtr> renderViewCommandUpdaterJobs() const; @@ -111,16 +104,6 @@ public: bool layerCacheNeedsToBeRebuilt() const; void setMaterialGathererCacheNeedsToBeRebuilt(bool needsToBeRebuilt); bool materialGathererCacheNeedsToBeRebuilt() const; - - void setRenderableCacheNeedsToBeRebuilt(bool needsToBeRebuilt); - bool renderableCacheNeedsToBeRebuilt() const; - - void setComputableCacheNeedsToBeRebuilt(bool needsToBeRebuilt); - bool computableCacheNeedsToBeRebuilt() const; - - void setLightGathererCacheNeedsToBeRebuilt(bool needsToBeRebuilt); - bool lightGathererCacheNeedsToBeRebuilt() const; - void setRenderCommandCacheNeedsToBeRebuilt(bool needsToBeRebuilt); bool renderCommandCacheNeedsToBeRebuilt() const; @@ -133,16 +116,10 @@ private: Renderer *m_renderer; bool m_layerCacheNeedsToBeRebuilt; bool m_materialGathererCacheNeedsToBeRebuilt; - bool m_lightsCacheNeedsToBeRebuilt; - bool m_renderableCacheNeedsToBeRebuilt; - bool m_computableCacheNeedsToBeRebuilt; bool m_renderCommandCacheNeedsToBeRebuilt; RenderViewInitializerJobPtr m_renderViewJob; FilterLayerEntityJobPtr m_filterEntityByLayerJob; - LightGathererPtr m_lightGathererJob; - RenderableEntityFilterPtr m_renderableEntityFilterJob; - ComputableEntityFilterPtr m_computableEntityFilterJob; FrustumCullingJobPtr m_frustumCullingJob; QVector<RenderViewCommandBuilderJobPtr> m_renderViewCommandBuilderJobs; QVector<RenderViewCommandUpdaterJobPtr> m_renderViewCommandUpdaterJobs; @@ -158,10 +135,6 @@ private: SynchronizerJobPtr m_syncMaterialGathererJob; FilterProximityDistanceJobPtr m_filterProximityJob; - SynchronizerJobPtr m_cacheRenderableEntitiesJob; - SynchronizerJobPtr m_cacheComputableEntitiesJob; - SynchronizerJobPtr m_cacheLightsJob; - static const int m_optimalParallelJobCount; }; diff --git a/src/render/renderers/opengl/textures/gltexture.cpp b/src/render/renderers/opengl/textures/gltexture.cpp index 1b5a972ec..20e6007a0 100644 --- a/src/render/renderers/opengl/textures/gltexture.cpp +++ b/src/render/renderers/opengl/textures/gltexture.cpp @@ -232,11 +232,9 @@ void GLTexture::loadTextureDataFromImages() GLTexture::TextureUpdateInfo GLTexture::createOrUpdateGLTexture() { TextureUpdateInfo textureInfo; - m_properties.status = QAbstractTexture::Error; m_wasTextureRecreated = false; const bool hasSharedTextureId = m_sharedTextureId > 0; - // Only load texture data if we are not using a sharedTextureId // Check if dataFunctor or images have changed if (!hasSharedTextureId) { @@ -269,17 +267,17 @@ GLTexture::TextureUpdateInfo GLTexture::createOrUpdateGLTexture() // Reset image flag setDirtyFlag(TextureImageData, false); } - } - // Don't try to create the texture if the target or format was still not set - // Format should either be set by user or if Automatic - // by either the dataGenerator of the texture or the first Image - // Target should explicitly be set by the user or the dataGenerator - if (m_properties.target == QAbstractTexture::TargetAutomatic || - m_properties.format == QAbstractTexture::Automatic || - m_properties.format == QAbstractTexture::NoFormat) { - textureInfo.properties.status = QAbstractTexture::Error; - return textureInfo; + // Don't try to create the texture if the target or format was still not set + // Format should either be set by user or if Automatic + // by either the dataGenerator of the texture or the first Image + // Target should explicitly be set by the user or the dataGenerator + if (m_properties.target == QAbstractTexture::TargetAutomatic || + m_properties.format == QAbstractTexture::Automatic || + m_properties.format == QAbstractTexture::NoFormat) { + textureInfo.properties.status = QAbstractTexture::Error; + return textureInfo; + } } // If the properties changed or texture has become a shared texture from a diff --git a/src/render/services/vsyncframeadvanceservice.cpp b/src/render/services/vsyncframeadvanceservice.cpp index b49870e68..d7398e2ce 100644 --- a/src/render/services/vsyncframeadvanceservice.cpp +++ b/src/render/services/vsyncframeadvanceservice.cpp @@ -62,7 +62,7 @@ public: QSemaphore m_semaphore; QElapsedTimer m_elapsed; - quint64 m_elapsedTimeSincePreviousFrame; + qint64 m_elapsedTimeSincePreviousFrame; bool m_drivenByRenderThread; }; @@ -75,14 +75,19 @@ VSyncFrameAdvanceService::~VSyncFrameAdvanceService() { } -// Aspect Thread +// Main Thread qint64 VSyncFrameAdvanceService::waitForNextFrame() { Q_D(VSyncFrameAdvanceService); +#ifdef Q_OS_MACOS + if (!d->m_semaphore.tryAcquire(std::max(d->m_semaphore.available(), 1), 4)) + return -1; +#else d->m_semaphore.acquire(std::max(d->m_semaphore.available(), 1)); +#endif - const quint64 currentTime = d->m_elapsed.nsecsElapsed(); + const qint64 currentTime = d->m_elapsed.nsecsElapsed(); qCDebug(VSyncAdvanceService) << "Elapsed nsecs since last call " << currentTime - d->m_elapsedTimeSincePreviousFrame; d->m_elapsedTimeSincePreviousFrame = currentTime; return currentTime; diff --git a/src/render/texture/qtexture.cpp b/src/render/texture/qtexture.cpp index bca66e630..84a228428 100644 --- a/src/render/texture/qtexture.cpp +++ b/src/render/texture/qtexture.cpp @@ -1125,7 +1125,7 @@ TextureDownloadRequest::TextureDownloadRequest(const QTextureFromSourceGenerator } -// Executed in aspect thread +// Executed in main thread void TextureDownloadRequest::onCompleted() { if (cancelled() || !succeeded()) @@ -1142,16 +1142,11 @@ void TextureDownloadRequest::onCompleted() QTextureFromSourceGeneratorPtr oldGenerator = qSharedPointerCast<QTextureFromSourceGenerator>(texture->dataGenerator()); - // We create a new functor - // Which is a copy of the old one + the downloaded sourceData - auto newGenerator = QTextureFromSourceGeneratorPtr::create(*oldGenerator); - // Set raw data on functor so that it can really load something - newGenerator->m_sourceData = m_data; + oldGenerator->m_sourceData = m_data; - // Set new generator on texture - // it implictely marks the texture as dirty so that the functor runs again with the downloaded data - texture->setDataGenerator(newGenerator); + // Mark the texture as dirty so that the functor runs again with the downloaded data + texture->addDirtyFlag(Render::Texture::DirtyDataGenerator); } /*! @@ -1520,7 +1515,10 @@ QTextureLoader::QTextureLoader(QNode *parent) // Regenerate the texture functor when properties we support overriding // from QAbstractTexture get changed. Q_D(QTextureLoader); - auto regenerate = [=] () { d->updateGenerator(); }; + auto regenerate = [=] () { + if (!notificationsBlocked()) // check the change doesn't come from the backend + d->updateGenerator(); + }; connect(this, &QAbstractTexture::formatChanged, regenerate); } diff --git a/src/render/texture/texture.cpp b/src/render/texture/texture.cpp index 5ebde56b0..1414cd337 100644 --- a/src/render/texture/texture.cpp +++ b/src/render/texture/texture.cpp @@ -149,6 +149,8 @@ void Texture::syncFromFrontEnd(const QNode *frontEnd, bool firstTime) auto newGenerator = node->dataGenerator(); if (newGenerator != m_dataFunctor) { setDataGenerator(newGenerator); + QAbstractTexturePrivate *dTexture = static_cast<QAbstractTexturePrivate *>(QNodePrivate::get(const_cast<QNode *>(frontEnd))); + dTexture->setStatus(QAbstractTexture::Loading); } QAbstractTexturePrivate *dnode = dynamic_cast<QAbstractTexturePrivate *>(QAbstractTexturePrivate::get(const_cast<QAbstractTexture *>(node))); diff --git a/tests/auto/core/nodes/tst_nodes.cpp b/tests/auto/core/nodes/tst_nodes.cpp index 25565d470..b5291cab7 100644 --- a/tests/auto/core/nodes/tst_nodes.cpp +++ b/tests/auto/core/nodes/tst_nodes.cpp @@ -41,6 +41,7 @@ #include <Qt3DCore/private/qnodecreatedchangegenerator_p.h> #include <Qt3DCore/private/qaspectengine_p.h> #include <Qt3DCore/private/qscenechange_p.h> +#include <Qt3DCore/private/qaspectengine_p.h> #include <private/qabstractaspect_p.h> #include <private/qpostman_p.h> @@ -93,6 +94,7 @@ private slots: void checkConstructionWithNonRootParent(); // QTBUG-73986 void checkConstructionAsListElement(); void checkSceneIsSetOnConstructionWithParent(); // QTBUG-69352 + void checkSubNodePostConstructIsCalledWhenReferincingNodeProperty(); // QTBUG-79350 void appendingComponentToEntity(); void appendingParentlessComponentToEntityWithoutScene(); @@ -291,22 +293,15 @@ public slots: if (!attribute->parent()) attribute->setParent(this); - if (d->m_changeArbiter != nullptr) { - const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(id(), attribute); - change->setPropertyName("attribute"); - d->notifyObservers(change); - } + d->updateNode(attribute, "attribute", Qt3DCore::PropertyValueAdded); } } void removeAttribute(MyQNode *attribute) { Qt3DCore::QNodePrivate *d = Qt3DCore::QNodePrivate::get(this); - if (d->m_changeArbiter != nullptr) { - const auto change = Qt3DCore::QPropertyNodeRemovedChangePtr::create(id(), attribute); - change->setPropertyName("attribute"); - d->notifyObservers(change); - } + d->updateNode(attribute, "attribute", Qt3DCore::PropertyValueRemoved); + m_attributes.removeOne(attribute); // Remove bookkeeping connection d->unregisterDestructionHelper(attribute); @@ -385,11 +380,7 @@ public: if (!attribute->parent()) attribute->setParent(this); - if (d->m_changeArbiter != nullptr) { - const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(id(), attribute); - change->setPropertyName("attribute"); - d->notifyObservers(change); - } + d->updateNode(attribute, "attribute", Qt3DCore::PropertyValueRemoved); } } @@ -436,6 +427,29 @@ public: } }; +class MyFakeMaterial : public Qt3DCore::QComponent +{ + Q_OBJECT +public: + explicit MyFakeMaterial(Qt3DCore::QNode *parent = nullptr) + : QComponent(parent) + , m_effect(new MyQNode(this)) + , m_technique(new MyQNode(m_effect)) + , m_renderPass(new MyQNode(m_technique)) + { + } + + void setArbiter(Qt3DCore::QAbstractArbiter *arbiter) + { + Q_ASSERT(arbiter); + Qt3DCore::QComponentPrivate::get(this)->setArbiter(arbiter); + } + + MyQNode *m_effect; + MyQNode *m_technique; + MyQNode *m_renderPass; +}; + class TestAspectPrivate; class TestAspect : public Qt3DCore::QAbstractAspect { @@ -1545,20 +1559,8 @@ void tst_Nodes::checkConstructionAsListElement() QCoreApplication::processEvents(); QCOMPARE(root->children().count(), 1); - QCOMPARE(spy.events.size(), 2); // 1 child added change, 1 property change - - const auto newChildEvent = spy.events.takeFirst().change().dynamicCast<Qt3DCore::QPropertyNodeAddedChange>(); - QVERIFY(!newChildEvent.isNull()); - QCOMPARE(newChildEvent->subjectId(), root->id()); - QCOMPARE(newChildEvent->propertyName(), "children"); - QCOMPARE(newChildEvent->addedNodeId(), node->id()); - - // Ensure second and last event is property set change - const auto propertyEvent = spy.events.takeFirst().change().dynamicCast<Qt3DCore::QPropertyNodeAddedChange>(); - QVERIFY(!propertyEvent.isNull()); - QCOMPARE(propertyEvent->subjectId(), root->id()); - QCOMPARE(propertyEvent->propertyName(), "attribute"); - QCOMPARE(newChildEvent->addedNodeId(), node->id()); + QCOMPARE(spy.dirtyNodes.size(), 1); // 1 property change + QCOMPARE(spy.dirtySubNodes.size(), 1); // 1 child added change } void tst_Nodes::checkSceneIsSetOnConstructionWithParent() @@ -1607,6 +1609,52 @@ void tst_Nodes::checkSceneIsSetOnConstructionWithParent() QCOMPARE(spy.dirtySubNodes.size(), 5); // 5 entities changed } +void tst_Nodes::checkSubNodePostConstructIsCalledWhenReferincingNodeProperty() +{ + // GIVEN + ObserverSpy spy; + Qt3DCore::QAspectEngine engine; + Qt3DCore::QScene scene(&engine); + QScopedPointer<MyQNode> root(new MyQNode()); + + // WHEN + root->setArbiterAndScene(&spy, &scene); + root->setSimulateBackendCreated(true); + + // THEN + QVERIFY(Qt3DCore::QNodePrivate::get(root.data())->scene() != nullptr); + + // WHEN + Qt3DCore::QEntity *subTreeRoot = new Qt3DCore::QEntity(root.data()); + QCoreApplication::processEvents(); + + // THEN + QVERIFY(Qt3DCore::QNodePrivate::get(subTreeRoot)->m_hasBackendNode); + + // WHEN + MyFakeMaterial *material = new MyFakeMaterial(subTreeRoot); + subTreeRoot->addComponent(material); + + // THEN + QVERIFY(Qt3DCore::QNodePrivate::get(material)->m_hasBackendNode); + QVERIFY(Qt3DCore::QNodePrivate::get(material->m_effect)->m_hasBackendNode); + QVERIFY(Qt3DCore::QNodePrivate::get(material->m_technique)->m_hasBackendNode); + QVERIFY(Qt3DCore::QNodePrivate::get(material->m_renderPass)->m_hasBackendNode); + + // WHEN + MyQNode *fakeRenderState = new MyQNode(material); + Qt3DCore::QNodePrivate *dPtr = Qt3DCore::QNodePrivate::get(fakeRenderState); + + // THEN + QVERIFY(!dPtr->m_hasBackendNode); + + // WHEN + material->m_renderPass->addAttribute(fakeRenderState); + + // THEN + QVERIFY(dPtr->m_hasBackendNode); +} + void tst_Nodes::appendingParentlessComponentToEntityWithoutScene() { // GIVEN diff --git a/tests/auto/render/buffer/tst_buffer.cpp b/tests/auto/render/buffer/tst_buffer.cpp index 1b53efd33..fa1491914 100644 --- a/tests/auto/render/buffer/tst_buffer.cpp +++ b/tests/auto/render/buffer/tst_buffer.cpp @@ -157,6 +157,61 @@ private Q_SLOTS: QVERIFY(backendBuffer.pendingBufferUpdates().empty()); } + + void checkForceFullUploadOnFirstTime() + { + // GIVEN + Qt3DRender::Render::Buffer backendBuffer; + Qt3DRender::Render::BufferManager bufferManager; + TestRenderer renderer; + Qt3DRender::QBuffer frontendBuffer; + + QByteArray data("111456789\0"); + + frontendBuffer.setData(data); + frontendBuffer.updateData(1, QByteArray("23\0")); + + // THEN + QCOMPARE(frontendBuffer.data(), QByteArray("123456789\0")); + + // WHEN + backendBuffer.setManager(&bufferManager); + backendBuffer.setRenderer(&renderer); + simulateInitializationSync(&frontendBuffer, &backendBuffer); + + // THEN + QCOMPARE(backendBuffer.pendingBufferUpdates().size(), 1); + Qt3DRender::QBufferUpdate fullUpdate = backendBuffer.pendingBufferUpdates().first(); + QCOMPARE(fullUpdate.offset, -1); + QVERIFY(fullUpdate.data.isEmpty()); + QCOMPARE(frontendBuffer.data(), backendBuffer.data()); + + backendBuffer.pendingBufferUpdates().clear(); + + // WHEN + frontendBuffer.updateData(1, QByteArray("00\0")); + backendBuffer.syncFromFrontEnd(&frontendBuffer, false); + + // THEN + QCOMPARE(frontendBuffer.data(), QByteArray("100456789\0")); + QCOMPARE(backendBuffer.pendingBufferUpdates().size(), 1); + fullUpdate = backendBuffer.pendingBufferUpdates().first(); + QCOMPARE(fullUpdate.offset, 1); + QCOMPARE(fullUpdate.data, QByteArray("00\0")); + QCOMPARE(frontendBuffer.data(), backendBuffer.data()); + + // WHEN + frontendBuffer.updateData(1, QByteArray("22\0")); + backendBuffer.syncFromFrontEnd(&frontendBuffer, true); + + // THEN + QCOMPARE(frontendBuffer.data(), QByteArray("122456789\0")); + fullUpdate = backendBuffer.pendingBufferUpdates().first(); + QCOMPARE(fullUpdate.offset, -1); + QVERIFY(fullUpdate.data.isEmpty()); + QCOMPARE(frontendBuffer.data(), backendBuffer.data()); + } + void checkPropertyChanges() { // GIVEN diff --git a/tests/auto/render/renderer/tst_renderer.cpp b/tests/auto/render/renderer/tst_renderer.cpp index 0940348bd..a343d6e57 100644 --- a/tests/auto/render/renderer/tst_renderer.cpp +++ b/tests/auto/render/renderer/tst_renderer.cpp @@ -223,12 +223,6 @@ private Q_SLOTS: 1 + // updateSkinningPaletteJob 1 + // SyncLoadingJobs 1 + // sendDisablesToFrontend - 1 + // LightGathererJob - 1 + // CacheLightJob - 1 + // RenderableEntityFilterJob - 1 + // CacheRenderableEntitiesJob - 1 + // ComputableEntityFilterJob - 1 + // CacheComputableEntitiesJob singleRenderViewJobCount + singleRenderViewCommandRebuildJobCount + renderViewBuilderMaterialCacheJobCount + diff --git a/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp b/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp index 0fb1f5e24..6024084bd 100644 --- a/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp +++ b/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp @@ -52,6 +52,7 @@ #include <Qt3DRender/private/qrenderaspect_p.h> #include <Qt3DRender/private/nodemanagers_p.h> #include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/filterentitybycomponentjob_p.h> QT_BEGIN_NAMESPACE @@ -280,39 +281,6 @@ private Q_SLOTS: // mark jobs dirty and recheck QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 9 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount()); } - - { - // WHEN - Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); - renderViewBuilder.setLightGathererCacheNeedsToBeRebuilt(true); - renderViewBuilder.prepareJobs(); - - // THEN - QCOMPARE(renderViewBuilder.lightGathererCacheNeedsToBeRebuilt(), true); - QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 10 + 1 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount()); - } - - { - // WHEN - Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); - renderViewBuilder.setRenderableCacheNeedsToBeRebuilt(true); - renderViewBuilder.prepareJobs(); - - // THEN - QCOMPARE(renderViewBuilder.renderableCacheNeedsToBeRebuilt(), true); - QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 10 + 1 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount()); - } - - { - // WHEN - Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); - renderViewBuilder.setComputableCacheNeedsToBeRebuilt(true); - renderViewBuilder.prepareJobs(); - - // THEN - QCOMPARE(renderViewBuilder.computableCacheNeedsToBeRebuilt(), true); - QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 10 + 1 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount()); - } } void checkCheckJobDependencies() @@ -365,13 +333,14 @@ private Q_SLOTS: QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(testAspect.renderer()->expandBoundingVolumeJob())); - QCOMPARE(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().size(), renderViewBuilder.materialGathererJobs().size() + 6); + QCOMPARE(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().size(), renderViewBuilder.materialGathererJobs().size() + 7); QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(renderViewBuilder.syncRenderViewPostInitializationJob())); QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(renderViewBuilder.filterProximityJob())); QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(renderViewBuilder.frustumCullingJob())); QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(testAspect.renderer()->introspectShadersJob())); QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(testAspect.renderer()->bufferGathererJob())); QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(testAspect.renderer()->textureGathererJob())); + QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(testAspect.renderer()->cacheLightJob())); // Step 5 for (const auto &renderViewBuilderJob : renderViewBuilder.renderViewCommandUpdaterJobs()) { @@ -487,21 +456,18 @@ private Q_SLOTS: Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(); Qt3DRender::QClearBuffers *clearBuffer = new Qt3DRender::QClearBuffers(viewport); Qt3DRender::TestAspect testAspect(buildSimpleScene(viewport)); + Qt3DRender::Render::Renderer *renderer = testAspect.renderer(); // THEN Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(clearBuffer->id()); QVERIFY(leafNode != nullptr); // WHEN - Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); - renderViewBuilder.setLightGathererCacheNeedsToBeRebuilt(true); - renderViewBuilder.prepareJobs(); - renderViewBuilder.buildJobHierachy(); - renderViewBuilder.lightGathererJob()->run(); + renderer->lightGathererJob()->run(); // THEN - QCOMPARE(renderViewBuilder.lightGathererJob()->lights().size(), 2); - QVERIFY(renderViewBuilder.lightGathererJob()->takeEnvironmentLight() != nullptr); + QCOMPARE(renderer->lightGathererJob()->lights().size(), 2); + QVERIFY(renderer->lightGathererJob()->takeEnvironmentLight() != nullptr); } void checkRenderableEntitiesFilteringExecution() @@ -510,20 +476,17 @@ private Q_SLOTS: Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(); Qt3DRender::QClearBuffers *clearBuffer = new Qt3DRender::QClearBuffers(viewport); Qt3DRender::TestAspect testAspect(buildSimpleScene(viewport)); + Qt3DRender::Render::Renderer *renderer = testAspect.renderer(); // THEN Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(clearBuffer->id()); QVERIFY(leafNode != nullptr); // WHEN - Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); - renderViewBuilder.setRenderableCacheNeedsToBeRebuilt(true); - renderViewBuilder.prepareJobs(); - renderViewBuilder.buildJobHierachy(); - renderViewBuilder.renderableEntityFilterJob()->run(); + renderer->renderableEntityFilterJob()->run(); // THEN - QCOMPARE(renderViewBuilder.renderableEntityFilterJob()->filteredEntities().size(), 1); + QCOMPARE(renderer->renderableEntityFilterJob()->filteredEntities().size(), 1); } void checkComputableEntitiesFilteringExecution() @@ -532,20 +495,17 @@ private Q_SLOTS: Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(); Qt3DRender::QClearBuffers *clearBuffer = new Qt3DRender::QClearBuffers(viewport); Qt3DRender::TestAspect testAspect(buildSimpleScene(viewport)); + Qt3DRender::Render::Renderer *renderer = testAspect.renderer(); // THEN Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(clearBuffer->id()); QVERIFY(leafNode != nullptr); // WHEN - Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); - renderViewBuilder.setComputableCacheNeedsToBeRebuilt(true); - renderViewBuilder.prepareJobs(); - renderViewBuilder.buildJobHierachy(); - renderViewBuilder.computableEntityFilterJob()->run(); + renderer->computableEntityFilterJob()->run(); // THEN - QCOMPARE(renderViewBuilder.computableEntityFilterJob()->filteredEntities().size(), 1); + QCOMPARE(renderer->computableEntityFilterJob()->filteredEntities().size(), 1); } void checkSyncRenderViewInitializationExecution() @@ -662,24 +622,28 @@ private Q_SLOTS: Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(); layerFilter->addLayer(layer); Qt3DRender::TestAspect testAspect(buildEntityFilterTestScene(viewport, layer)); + Qt3DRender::Render::Renderer *renderer = testAspect.renderer(); // THEN Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(layerFilter->id()); QVERIFY(leafNode != nullptr); // WHEN + renderer->markDirty(Qt3DRender::Render::AbstractRenderer::AllDirty, nullptr); + Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); renderViewBuilder.setLayerCacheNeedsToBeRebuilt(true); - renderViewBuilder.setRenderableCacheNeedsToBeRebuilt(true); renderViewBuilder.prepareJobs(); renderViewBuilder.buildJobHierachy(); + renderer->renderableEntityFilterJob()->run(); + renderer->cacheRenderableEntitiesJob()->run(); + renderViewBuilder.renderViewJob()->run(); - renderViewBuilder.renderableEntityFilterJob()->run(); renderViewBuilder.syncRenderViewPostInitializationJob()->run(); renderViewBuilder.filterEntityByLayerJob()->run(); - QVector<Qt3DRender::Render::Entity *> renderableEntity = renderViewBuilder.renderableEntityFilterJob()->filteredEntities(); + QVector<Qt3DRender::Render::Entity *> renderableEntity = renderer->renderableEntityFilterJob()->filteredEntities(); QVector<Qt3DRender::Render::Entity *> filteredEntity = renderViewBuilder.filterEntityByLayerJob()->filteredEntities(); // THEN diff --git a/tests/manual/sharedtexture/main.cpp b/tests/manual/sharedtexture/main.cpp index a85f90ee6..6f2ef42f2 100644 --- a/tests/manual/sharedtexture/main.cpp +++ b/tests/manual/sharedtexture/main.cpp @@ -137,8 +137,7 @@ int main(int argc, char* argv[]) // Multimedia player TextureWidget textureWidget; - VideoPlayerThread *videoPlayer = new VideoPlayerThread(&textureWidget); - videoPlayer->start(); + VideoPlayer *videoPlayer = new VideoPlayer(&textureWidget); textureWidget.resize(800, 600); textureWidget.show(); diff --git a/tests/manual/sharedtexture/videoplayer.cpp b/tests/manual/sharedtexture/videoplayer.cpp index f970116b5..2e52b85e0 100644 --- a/tests/manual/sharedtexture/videoplayer.cpp +++ b/tests/manual/sharedtexture/videoplayer.cpp @@ -57,8 +57,6 @@ TextureWidget::TextureWidget(QWidget *parent) : QOpenGLWidget(parent) , m_texture(QOpenGLTexture::Target2D) { - // Lock mutex so that we never process a frame until we have been initialized - m_mutex.lock(); } // Main thread @@ -104,14 +102,11 @@ void TextureWidget::initializeGL() qDebug() << Q_FUNC_INFO << context()->shareContext(); m_vao.create(); - // Allow rendering/frame acquisition to go on - m_mutex.unlock(); } // Main thread void TextureWidget::paintGL() { - QMutexLocker lock(&m_mutex); glViewport(0, 0, width(), height()); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); @@ -131,12 +126,8 @@ void TextureWidget::paintGL() m_shader.release(); } -// Video Player thread void TextureWidget::setVideoFrame(const QVideoFrame &frame) { - // Ensure we won't be rendering while we are processing the frame - QMutexLocker lock(&m_mutex); - QVideoFrame f = frame; // Map frame @@ -194,16 +185,14 @@ bool GLVideoSurface::present(const QVideoFrame &frame) return true; } -VideoPlayerThread::VideoPlayerThread(TextureWidget *textureWidget) - : QThread(textureWidget) +VideoPlayer::VideoPlayer(TextureWidget *textureWidget) + : QObject(textureWidget) , m_player(new QMediaPlayer(nullptr, QMediaPlayer::VideoSurface)) , m_surface(new GLVideoSurface()) { - m_player->moveToThread(this); - m_player->setMedia(QUrl("https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4")); + m_player->setMedia(QUrl("https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4")); // Tell player to render on GLVideoSurface - m_surface->moveToThread(this); m_player->setVideoOutput(m_surface.get()); // Display errors @@ -218,16 +207,13 @@ VideoPlayerThread::VideoPlayerThread(TextureWidget *textureWidget) m_player->play(); }); - // Start playing when thread starts - QObject::connect(this, &QThread::started, this, [this] { m_player->play(); }); - - // Direct connection between 2 objects living in different threads QObject::connect(m_surface.get(), &GLVideoSurface::onNewFrame, textureWidget, &TextureWidget::setVideoFrame, Qt::DirectConnection); + + // Start playing + m_player->play(); } -VideoPlayerThread::~VideoPlayerThread() +VideoPlayer::~VideoPlayer() { - exit(0); - wait(); } diff --git a/tests/manual/sharedtexture/videoplayer.h b/tests/manual/sharedtexture/videoplayer.h index 377ea57fe..a96cb16b1 100644 --- a/tests/manual/sharedtexture/videoplayer.h +++ b/tests/manual/sharedtexture/videoplayer.h @@ -48,9 +48,6 @@ ** ****************************************************************************/ -#include <QThread> -#include <QMutex> - #include <QOpenGLWidget> #include <QOpenGLFunctions> #include <QOpenGLVertexArrayObject> @@ -90,7 +87,6 @@ private: QOpenGLVertexArrayObject m_vao; QOpenGLShaderProgram m_shader; QOpenGLTexture m_texture; - QMutex m_mutex; }; @@ -108,12 +104,12 @@ Q_SIGNALS: }; -class VideoPlayerThread : public QThread +class VideoPlayer : public QObject { Q_OBJECT public: - VideoPlayerThread(TextureWidget *textureWidget); - ~VideoPlayerThread(); + VideoPlayer(TextureWidget *textureWidget); + ~VideoPlayer(); private: TextureWidget *m_textureWidget; diff --git a/tests/manual/sharedtextureqml/main.cpp b/tests/manual/sharedtextureqml/main.cpp index 5c7ae9cff..c0a79e6f8 100644 --- a/tests/manual/sharedtextureqml/main.cpp +++ b/tests/manual/sharedtextureqml/main.cpp @@ -108,8 +108,7 @@ int main(int argc, char* argv[]) // Multimedia player TextureWidget textureWidget; - VideoPlayerThread *videoPlayer = new VideoPlayerThread(&textureWidget); - videoPlayer->start(); + VideoPlayer *videoPlayer = new VideoPlayer(&textureWidget); textureWidget.resize(800, 600); textureWidget.show(); |