diff options
-rw-r--r-- | src/core/aspects/qaspectengine.cpp | 4 | ||||
-rw-r--r-- | src/core/aspects/qaspectmanager.cpp | 9 | ||||
-rw-r--r-- | src/core/aspects/qaspectmanager_p.h | 2 | ||||
-rw-r--r-- | src/core/jobs/qaspectjob.cpp | 1 | ||||
-rw-r--r-- | src/core/jobs/qaspectjob_p.h | 14 | ||||
-rw-r--r-- | src/core/qscheduler.cpp | 39 | ||||
-rw-r--r-- | src/core/qscheduler_p.h | 2 | ||||
-rw-r--r-- | src/plugins/renderers/opengl/debug/imguirenderer.cpp | 5 | ||||
-rw-r--r-- | src/plugins/renderers/opengl/renderer/renderer.cpp | 28 | ||||
-rw-r--r-- | src/plugins/renderers/opengl/renderer/renderer_p.h | 2 | ||||
-rw-r--r-- | src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp | 16 | ||||
-rw-r--r-- | src/plugins/renderers/opengl/renderer/renderviewbuilder_p.h | 2 | ||||
-rw-r--r-- | src/render/jobs/genericlambdajob_p.h | 8 | ||||
-rw-r--r-- | tests/auto/core/qscheduler/tst_qscheduler.cpp | 2 |
14 files changed, 102 insertions, 32 deletions
diff --git a/src/core/aspects/qaspectengine.cpp b/src/core/aspects/qaspectengine.cpp index d28306197..e52435eed 100644 --- a/src/core/aspects/qaspectengine.cpp +++ b/src/core/aspects/qaspectengine.cpp @@ -412,6 +412,10 @@ QVariant QAspectEngine::executeCommand(const QString &command) const QStringList names = d->m_aspectManager->serviceLocator()->systemInformation()->aspectNames(); return names.join(QLatin1String("\n")); } + if (command == QLatin1String("dump jobs")) { + d->m_aspectManager->dumpJobsOnNextFrame(); + return QLatin1String("Dump in next frame in working directory"); + } QStringList args = command.split(QLatin1Char(' ')); QString aspectName = args.takeFirst(); diff --git a/src/core/aspects/qaspectmanager.cpp b/src/core/aspects/qaspectmanager.cpp index f0dc366b2..66475c615 100644 --- a/src/core/aspects/qaspectmanager.cpp +++ b/src/core/aspects/qaspectmanager.cpp @@ -128,6 +128,7 @@ QAspectManager::QAspectManager(QAspectEngine *parent) , m_simulationAnimation(nullptr) #endif , m_jobsInLastFrame(0) + , m_dumpJobs(false) { qRegisterMetaType<QSurface *>("QSurface*"); qCDebug(Aspects) << Q_FUNC_INFO; @@ -434,6 +435,11 @@ QVector<QNode *> QAspectManager::lookupNodes(const QVector<QNodeId> &ids) const return d->m_scene ? d->m_scene->lookupNodes(ids) : QVector<QNode *>{}; } +void QAspectManager::dumpJobsOnNextFrame() +{ + m_dumpJobs = true; +} + #if !QT_CONFIG(animation) /*! \internal @@ -537,7 +543,8 @@ void QAspectManager::processFrame() // For each Aspect // Ask them to launch set of jobs for the current frame // Updates matrices, bounding volumes, render bins ... - m_jobsInLastFrame = m_scheduler->scheduleAndWaitForFrameAspectJobs(t); + m_jobsInLastFrame = m_scheduler->scheduleAndWaitForFrameAspectJobs(t, m_dumpJobs); + m_dumpJobs = false; // Tell the aspect the frame is complete (except rendering) for (QAbstractAspect *aspect : qAsConst(m_aspects)) diff --git a/src/core/aspects/qaspectmanager_p.h b/src/core/aspects/qaspectmanager_p.h index 2038e0822..e3d978ee2 100644 --- a/src/core/aspects/qaspectmanager_p.h +++ b/src/core/aspects/qaspectmanager_p.h @@ -116,6 +116,7 @@ public: QVector<QNode *> lookupNodes(const QVector<QNodeId> &ids) const; int jobsInLastFrame() const { return m_jobsInLastFrame; } + void dumpJobsOnNextFrame(); private: #if !QT_CONFIG(animation) @@ -140,6 +141,7 @@ private: RequestFrameAnimation *m_simulationAnimation; #endif int m_jobsInLastFrame; + bool m_dumpJobs; }; } // namespace Qt3DCore diff --git a/src/core/jobs/qaspectjob.cpp b/src/core/jobs/qaspectjob.cpp index 44efc2c0b..0a2ee9841 100644 --- a/src/core/jobs/qaspectjob.cpp +++ b/src/core/jobs/qaspectjob.cpp @@ -56,6 +56,7 @@ bool isDependencyNull(const QWeakPointer<QAspectJob> &dep) } // anonymous QAspectJobPrivate::QAspectJobPrivate() + : m_jobName(QLatin1String("UnknowJob")) { } diff --git a/src/core/jobs/qaspectjob_p.h b/src/core/jobs/qaspectjob_p.h index 5b72e64ee..63a2cc572 100644 --- a/src/core/jobs/qaspectjob_p.h +++ b/src/core/jobs/qaspectjob_p.h @@ -77,14 +77,26 @@ public: QVector<QWeakPointer<QAspectJob> > m_dependencies; JobId m_jobId; + QString m_jobName; }; } // Qt3D #define SET_JOB_RUN_STAT_TYPE(job, type, instance) \ { \ - auto &jobId = Qt3DCore::QAspectJobPrivate::get(job)->m_jobId; \ + auto djob = Qt3DCore::QAspectJobPrivate::get(job); \ + auto &jobId = djob->m_jobId; \ jobId.typeAndInstance[0] = type; \ jobId.typeAndInstance[1] = instance; \ + djob->m_jobName = QLatin1String(#type); \ + } + +#define SET_JOB_RUN_STAT_TYPE_AND_NAME(job, type, name, instance) \ + { \ + auto djob = Qt3DCore::QAspectJobPrivate::get(job); \ + auto &jobId = djob->m_jobId; \ + jobId.typeAndInstance[0] = type; \ + jobId.typeAndInstance[1] = instance; \ + djob->m_jobName = QLatin1String(name); \ } QT_END_NAMESPACE diff --git a/src/core/qscheduler.cpp b/src/core/qscheduler.cpp index 9ff8a54f3..872b3ccd6 100644 --- a/src/core/qscheduler.cpp +++ b/src/core/qscheduler.cpp @@ -46,8 +46,42 @@ #include <Qt3DCore/private/qaspectjob_p.h> #include <Qt3DCore/private/qabstractaspectjobmanager_p.h> +#include <QtCore/QCoreApplication> +#include <QtCore/QDateTime> +#include <QtCore/QRegularExpression> + QT_BEGIN_NAMESPACE +namespace { + +// Creates a graphviz dot file. To view online: https://dreampuf.github.io/GraphvizOnline/ +void dumpJobs(QVector<Qt3DCore::QAspectJobPtr> jobs) { + const QString fileName = QStringLiteral("qt3djobs_") + QCoreApplication::applicationName() + + QDateTime::currentDateTime().toString(QStringLiteral("_yyMMdd-hhmmss")) + QStringLiteral(".dot"); + + QFile f(fileName); + if (!f.open(QFile::WriteOnly)) + return; + + auto formatJob = [](Qt3DCore::QAspectJob *job) -> QString { + auto jobId = Qt3DCore::QAspectJobPrivate::get(job)->m_jobId; + auto type = Qt3DCore::QAspectJobPrivate::get(job)->m_jobName.replace(QRegularExpression(QLatin1String("(^.*::)")), QLatin1String("")); + return QString(QLatin1String("\"%1_%2\"")).arg(type).arg(jobId.typeAndInstance[1]); + }; + + QTextStream stream(&f); + stream << "digraph qt3d_jobs {" << Qt::endl; + for (const auto &job: jobs) { + auto dependencies = job->dependencies(); + for (const auto &dependency: dependencies) + stream << QLatin1String("\t") << formatJob(job.data()) << QLatin1String(" -> ") << formatJob(dependency.toStrongRef().data()) << Qt::endl; + } + + stream << "}" << Qt::endl; +} + +} + namespace Qt3DCore { QScheduler::QScheduler(QObject *parent) @@ -70,7 +104,7 @@ QAspectManager *QScheduler::aspectManager() const return m_aspectManager; } -int QScheduler::scheduleAndWaitForFrameAspectJobs(qint64 time) +int QScheduler::scheduleAndWaitForFrameAspectJobs(qint64 time, bool dumpJobs) { QVector<QAspectJobPtr> jobQueue; @@ -86,6 +120,9 @@ int QScheduler::scheduleAndWaitForFrameAspectJobs(qint64 time) jobQueue << aspectJobs; } + if (dumpJobs) + ::dumpJobs(jobQueue); + m_aspectManager->jobManager()->enqueueJobs(jobQueue); // Do any other work here that the aspect thread can usefully be doing diff --git a/src/core/qscheduler_p.h b/src/core/qscheduler_p.h index 92e8e04fb..a781e1cbb 100644 --- a/src/core/qscheduler_p.h +++ b/src/core/qscheduler_p.h @@ -70,7 +70,7 @@ public: void setAspectManager(QAspectManager *aspectManager); QAspectManager *aspectManager() const; - virtual int scheduleAndWaitForFrameAspectJobs(qint64 time); + virtual int scheduleAndWaitForFrameAspectJobs(qint64 time, bool dumpJobs); private: QAspectManager *m_aspectManager; diff --git a/src/plugins/renderers/opengl/debug/imguirenderer.cpp b/src/plugins/renderers/opengl/debug/imguirenderer.cpp index 449ec65b0..687f5e4fc 100644 --- a/src/plugins/renderers/opengl/debug/imguirenderer.cpp +++ b/src/plugins/renderers/opengl/debug/imguirenderer.cpp @@ -289,7 +289,10 @@ void ImGuiRenderer::renderDebugOverlay(const QVector<RenderView *> &renderViews, if (ImGui::Button("FrameGraph Paths##1")) QMetaObject::invokeMethod(m_renderer->services()->systemInformation(), "dumpCommand", Qt::QueuedConnection, Q_ARG(QString, QLatin1String("render framepaths"))); - + ImGui::SameLine(); + if (ImGui::Button("JobsGraph##1")) + QMetaObject::invokeMethod(m_renderer->services()->systemInformation(), "dumpCommand", + Qt::QueuedConnection, Q_ARG(QString, QLatin1String("dump jobs"))); ImGui::End(); if (m_showGLInfoWindow) diff --git a/src/plugins/renderers/opengl/renderer/renderer.cpp b/src/plugins/renderers/opengl/renderer/renderer.cpp index e385a264e..ddff21a96 100644 --- a/src/plugins/renderers/opengl/renderer/renderer.cpp +++ b/src/plugins/renderers/opengl/renderer/renderer.cpp @@ -266,20 +266,20 @@ Renderer::Renderer(QRenderAspect::RenderType type) , 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)) - , m_sendSetFenceHandlesToFrontendJob(SynchronizerJobPtr::create([this] { sendSetFenceHandlesToFrontend(); }, JobTypes::SendSetFenceHandlesToFrontend)) - , m_introspectShaderJob(SynchronizerPostFramePtr::create([this] { reloadDirtyShaders(); }, - [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_bufferGathererJob(CreateSynchronizerJobPtr([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering)) + , m_vaoGathererJob(CreateSynchronizerJobPtr([this] { lookForAbandonedVaos(); }, JobTypes::DirtyVaoGathering)) + , m_textureGathererJob(CreateSynchronizerJobPtr([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering)) + , m_sendSetFenceHandlesToFrontendJob(CreateSynchronizerJobPtr([this] { sendSetFenceHandlesToFrontend(); }, JobTypes::SendSetFenceHandlesToFrontend)) + , m_introspectShaderJob(CreateSynchronizerPostFramePtr([this] { reloadDirtyShaders(); }, + [this] (Qt3DCore::QAspectManager *m) { sendShaderChangesToFrontend(m); }, + JobTypes::DirtyShaderGathering)) + , m_syncLoadingJobs(CreateSynchronizerJobPtr([] {}, JobTypes::SyncLoadingJobs)) + , m_cacheRenderableEntitiesJob(CreateSynchronizerJobPtr(SyncRenderableEntities(m_renderableEntityFilterJob, &m_cache), + JobTypes::EntityComponentTypeFiltering)) + , m_cacheComputableEntitiesJob(CreateSynchronizerJobPtr(SyncComputableEntities(m_computableEntityFilterJob, &m_cache), + JobTypes::EntityComponentTypeFiltering)) + , m_cacheLightsJob(CreateSynchronizerJobPtr(SyncLightsGatherer(m_lightGathererJob, &m_cache), + JobTypes::EntityComponentTypeFiltering)) , m_ownedContext(false) , m_offscreenHelper(nullptr) , m_glResourceManagers(nullptr) diff --git a/src/plugins/renderers/opengl/renderer/renderer_p.h b/src/plugins/renderers/opengl/renderer/renderer_p.h index aa3b26961..cf76e1b8a 100644 --- a/src/plugins/renderers/opengl/renderer/renderer_p.h +++ b/src/plugins/renderers/opengl/renderer/renderer_p.h @@ -165,6 +165,8 @@ using RenderableEntityFilterPtr = FilterEntityByComponentJobPtr<Render::Geometry using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>; using SynchronizerPostFramePtr = GenericLambdaJobAndPostFramePtr<std::function<void ()>, std::function<void (Qt3DCore::QAspectManager *)>>; +#define CreateSynchronizerPostFramePtr(lambda, postlambda, type) \ + SynchronizerPostFramePtr::create(lambda, postlambda, type, #type) namespace Debug { class ImGuiRenderer; diff --git a/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp b/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp index 1e16209c6..a80fbe445 100644 --- a/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp +++ b/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp @@ -463,8 +463,8 @@ RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int rende , m_renderViewJob(RenderViewInitializerJobPtr::create()) , m_filterEntityByLayerJob() , m_frustumCullingJob(new Render::FrustumCullingJob()) - , m_syncPreFrustumCullingJob(SynchronizerJobPtr::create(SyncPreFrustumCulling(m_renderViewJob, m_frustumCullingJob), JobTypes::SyncFrustumCulling)) - , m_setClearDrawBufferIndexJob(SynchronizerJobPtr::create(SetClearDrawBufferIndex(m_renderViewJob), JobTypes::ClearBufferDrawIndex)) + , m_syncPreFrustumCullingJob(CreateSynchronizerJobPtr(SyncPreFrustumCulling(m_renderViewJob, m_frustumCullingJob), JobTypes::SyncFrustumCulling)) + , m_setClearDrawBufferIndexJob(CreateSynchronizerJobPtr(SetClearDrawBufferIndex(m_renderViewJob), JobTypes::ClearBufferDrawIndex)) , m_syncFilterEntityByLayerJob() , m_filterProximityJob(Render::FilterProximityDistanceJobPtr::create()) { @@ -558,7 +558,7 @@ void RenderViewBuilder::prepareJobs() auto renderViewCommandBuilder = Render::OpenGL::RenderViewCommandBuilderJobPtr::create(); m_renderViewCommandBuilderJobs.push_back(renderViewCommandBuilder); } - m_syncRenderViewPreCommandBuildingJob = SynchronizerJobPtr::create(SyncPreCommandBuilding(m_renderViewJob, + m_syncRenderViewPreCommandBuildingJob = CreateSynchronizerJobPtr(SyncPreCommandBuilding(m_renderViewJob, m_renderViewCommandBuilderJobs, m_renderer, m_leafNode), @@ -593,7 +593,7 @@ void RenderViewBuilder::prepareJobs() materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob)); m_materialGathererJobs.push_back(materialGatherer); } - m_syncMaterialGathererJob = SynchronizerJobPtr::create(SyncMaterialParameterGatherer(m_materialGathererJobs, + m_syncMaterialGathererJob = CreateSynchronizerJobPtr(SyncMaterialParameterGatherer(m_materialGathererJobs, m_renderer, m_leafNode), JobTypes::SyncMaterialGatherer); @@ -602,13 +602,13 @@ void RenderViewBuilder::prepareJobs() if (m_layerCacheNeedsToBeRebuilt) { m_filterEntityByLayerJob = Render::FilterLayerEntityJobPtr::create(); m_filterEntityByLayerJob->setManager(m_renderer->nodeManagers()); - m_syncFilterEntityByLayerJob = SynchronizerJobPtr::create(SyncFilterEntityByLayer(m_filterEntityByLayerJob, + m_syncFilterEntityByLayerJob = CreateSynchronizerJobPtr(SyncFilterEntityByLayer(m_filterEntityByLayerJob, m_renderer, m_leafNode), JobTypes::SyncFilterEntityByLayer); } - m_syncRenderViewPreCommandUpdateJob = SynchronizerJobPtr::create(SyncRenderViewPreCommandUpdate(m_renderViewJob, + m_syncRenderViewPreCommandUpdateJob = CreateSynchronizerJobPtr(SyncRenderViewPreCommandUpdate(m_renderViewJob, m_frustumCullingJob, m_filterProximityJob, m_materialGathererJobs, @@ -619,12 +619,12 @@ void RenderViewBuilder::prepareJobs() m_renderCommandCacheNeedsToBeRebuilt), JobTypes::SyncRenderViewPreCommandUpdate); - m_syncRenderViewPostCommandUpdateJob = SynchronizerJobPtr::create(SyncRenderViewPostCommandUpdate(m_renderViewJob, + m_syncRenderViewPostCommandUpdateJob = CreateSynchronizerJobPtr(SyncRenderViewPostCommandUpdate(m_renderViewJob, m_renderViewCommandUpdaterJobs, m_renderer), JobTypes::SyncRenderViewPostCommandUpdate); - m_syncRenderViewPostInitializationJob = SynchronizerJobPtr::create(SyncRenderViewPostInitialization(m_renderViewJob, + m_syncRenderViewPostInitializationJob = CreateSynchronizerJobPtr(SyncRenderViewPostInitialization(m_renderViewJob, m_frustumCullingJob, m_filterEntityByLayerJob, m_filterProximityJob, diff --git a/src/plugins/renderers/opengl/renderer/renderviewbuilder_p.h b/src/plugins/renderers/opengl/renderer/renderviewbuilder_p.h index 98202670e..54fc98352 100644 --- a/src/plugins/renderers/opengl/renderer/renderviewbuilder_p.h +++ b/src/plugins/renderers/opengl/renderer/renderviewbuilder_p.h @@ -75,6 +75,8 @@ namespace OpenGL { class Renderer; using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>; +#define CreateSynchronizerJobPtr(lambda, type) \ + SynchronizerJobPtr::create(lambda, type, #type) class Q_AUTOTEST_EXPORT RenderViewBuilder { diff --git a/src/render/jobs/genericlambdajob_p.h b/src/render/jobs/genericlambdajob_p.h index 8cf4276f6..994cd3a14 100644 --- a/src/render/jobs/genericlambdajob_p.h +++ b/src/render/jobs/genericlambdajob_p.h @@ -64,11 +64,11 @@ template<typename T> class GenericLambdaJob : public Qt3DCore::QAspectJob { public: - explicit GenericLambdaJob(T callable, JobTypes::JobType type = JobTypes::GenericLambda) + explicit GenericLambdaJob(T callable, JobTypes::JobType type = JobTypes::GenericLambda, const char *name = "GenericLambda") : Qt3DCore::QAspectJob() , m_callable(callable) { - SET_JOB_RUN_STAT_TYPE(this, type, 0) + SET_JOB_RUN_STAT_TYPE_AND_NAME(this, type, name, 0) } // QAspectJob interface @@ -107,11 +107,11 @@ template<typename T, typename U> class GenericLambdaJobAndPostFrame : public Qt3DCore::QAspectJob { public: - explicit GenericLambdaJobAndPostFrame(T runCallable, U postFrameCallable, JobTypes::JobType type = JobTypes::GenericLambda) + explicit GenericLambdaJobAndPostFrame(T runCallable, U postFrameCallable, JobTypes::JobType type = JobTypes::GenericLambda, const char *name = "GenericLambda") : Qt3DCore::QAspectJob(*new GenericLambdaJobAndPostFramePrivate<T, U>(postFrameCallable)) , m_runCallable(runCallable) { - SET_JOB_RUN_STAT_TYPE(this, type, 0) + SET_JOB_RUN_STAT_TYPE_AND_NAME(this, type, name, 0) } // QAspectJob interface diff --git a/tests/auto/core/qscheduler/tst_qscheduler.cpp b/tests/auto/core/qscheduler/tst_qscheduler.cpp index d1afb5aac..5d858a77a 100644 --- a/tests/auto/core/qscheduler/tst_qscheduler.cpp +++ b/tests/auto/core/qscheduler/tst_qscheduler.cpp @@ -181,7 +181,7 @@ private Q_SLOTS: QVERIFY(!second->postFrameCalled()); // WHEN - const int count = scheduler.scheduleAndWaitForFrameAspectJobs(0); + const int count = scheduler.scheduleAndWaitForFrameAspectJobs(0, false); // THEN QCOMPARE(count, 2); |