diff options
author | Svenn-Arne Dragly <svenn-arne.dragly@qt.io> | 2018-01-22 10:42:55 +0100 |
---|---|---|
committer | Svenn-Arne Dragly <svenn-arne.dragly@qt.io> | 2018-02-02 10:20:11 +0000 |
commit | 46319648436814afb5a77755dde6681e304befaf (patch) | |
tree | 9a608913dd9be2ac99bb8e5ebf446dddd69c4c4f /src/render/frontend | |
parent | 30abe028f9a95fa32fbb77cb60063d062e13f7ff (diff) |
Keep rendering in sync with aspect jobs by adding barriers
This makes sure that jobs that depend on a specific state of the
renderer (such as context being initialized) never run before this
is the case. This reduces the number of possible race conditions
and checks we need to do to ensure the jobs and the renderer are in
the correct state.
This way we no longer swap buffers when nothing has been rendered,
which in turn makes sure that we only draw one frame when the
render policy is OnDemand and there are no changes.
This change also adds a number of assertions on pointers to
resources to make it easier to detect missing job dependencies.
Finally, this change overhauls the job dependencies in
Renderer and RenderViewBuilder.
Task-number: QTBUG-66024
Change-Id: I3e4e9dd0dd53b5c88f5c1b17d68df42f28eae794
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Diffstat (limited to 'src/render/frontend')
-rw-r--r-- | src/render/frontend/qrenderaspect.cpp | 69 | ||||
-rw-r--r-- | src/render/frontend/qrenderaspect_p.h | 4 |
2 files changed, 39 insertions, 34 deletions
diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index 2847bf29b..360aef100 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -150,6 +150,8 @@ #include <private/qrenderpluginfactory_p.h> #include <private/qrenderplugin_p.h> +#include <private/framegraphvisitor_p.h> +#include <private/platformsurfacefilter_p.h> #include <Qt3DCore/qentity.h> #include <Qt3DCore/qtransform.h> @@ -185,7 +187,12 @@ QRenderAspectPrivate::QRenderAspectPrivate(QRenderAspect::RenderType type) , m_initialized(false) , m_renderType(type) , m_offscreenHelper(nullptr) + , m_blockingRendermode(false) { + // The blocking mode can be enabled to make sure we render even while + // waiting for geometries to load. This is necessary if we want + // to call doRender for every QtQuick frame when using Scene3D frame. + m_blockingRendermode = !qgetenv("SCENE3D_BLOCKING_RENDERMODE").isEmpty(); m_instances.append(this); loadSceneParsers(); } @@ -367,6 +374,11 @@ void QRenderAspectPrivate::registerBackendType(const QMetaObject &obj, q->registerBackendType(obj, functor); } +void QRenderAspectPrivate::abortRenderJobs() +{ + m_renderer->abortRenderJobs(); +} + /*! * The constructor creates a new QRenderAspect::QRenderAspect instance with the * specified \a parent. @@ -405,9 +417,17 @@ void QRenderAspectPrivate::renderInitialize(QOpenGLContext *context) } /*! \internal */ -void QRenderAspectPrivate::renderSynchronous(bool blocking) +void QRenderAspectPrivate::tryRenderSynchronous() { - m_renderer->doRender(blocking); + // If the render aspect is slow for some reason and does not build jobs + // immediately, we might want to wait for it to make sure we render + // one Qt3D frame for each QtQuick frame. If blocking mode is enabled, + // we will wait a short time. + // TODO By allowing the aspect thread to skip a couple of frames that + // are not rendered without being in sync with the QtQuick scene graph, + // we can make this into a blocking call and get rid of the timeout. + if (m_renderer->tryWaitForRenderJobs(m_blockingRendermode ? 20 : 0)) + m_renderer->lockSurfaceAndRender(); } /*! @@ -443,36 +463,16 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time) // asked for jobs to execute (this function). If that is the case, the RenderSettings will // be null and we should not generate any jobs. if (d->m_renderer->isRunning() && d->m_renderer->settings()) { - Render::NodeManagers *manager = d->m_renderer->nodeManagers(); - QAspectJobPtr textureLoadingSync = d->m_renderer->syncTextureLoadingJob(); - textureLoadingSync->removeDependency(QWeakPointer<QAspectJob>()); - - // Launch texture generator jobs - const QVector<QTextureImageDataGeneratorPtr> pendingImgGen = manager->textureImageDataManager()->pendingGenerators(); - for (const QTextureImageDataGeneratorPtr &imgGen : pendingImgGen) { - auto loadTextureJob = Render::LoadTextureDataJobPtr::create(imgGen); - textureLoadingSync->addDependency(loadTextureJob); - loadTextureJob->setNodeManagers(manager); - jobs.append(loadTextureJob); - } - const QVector<QTextureGeneratorPtr> pendingTexGen = manager->textureDataManager()->pendingGenerators(); - for (const QTextureGeneratorPtr &texGen : pendingTexGen) { - auto loadTextureJob = Render::LoadTextureDataJobPtr::create(texGen); - textureLoadingSync->addDependency(loadTextureJob); - loadTextureJob->setNodeManagers(manager); - jobs.append(loadTextureJob); - } - - // Launch skeleton loader jobs. We join on the syncTextureLoadingJob for now - // which should likely be renamed to something more generic or we introduce - // another synchronizing job for skeleton loading + QAspectJobPtr assetLoadingSync = d->m_renderer->syncSkeletonLoadingJob(); + assetLoadingSync->removeDependency(QWeakPointer<QAspectJob>()); + // Launch skeleton loader jobs const QVector<Render::HSkeleton> skeletonsToLoad = manager->skeletonManager()->dirtySkeletons(Render::SkeletonManager::SkeletonDataDirty); for (const auto &skeletonHandle : skeletonsToLoad) { auto loadSkeletonJob = Render::LoadSkeletonJobPtr::create(skeletonHandle); loadSkeletonJob->setNodeManagers(manager); - textureLoadingSync->addDependency(loadSkeletonJob); + assetLoadingSync->addDependency(loadSkeletonJob); jobs.append(loadSkeletonJob); } @@ -489,7 +489,6 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time) const QVector<QAspectJobPtr> geometryJobs = d->createGeometryRendererJobs(); jobs.append(geometryJobs); - // Add all jobs to queue const Qt3DCore::QAspectJobPtr pickBoundingVolumeJob = d->m_renderer->pickBoundingVolumeJob(); // Note: the getter is also responsible for returning a job ready to run @@ -505,12 +504,16 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time) return jobs; } - // Traverse the current framegraph and create jobs to populate - // RenderBins with RenderCommands - // All jobs needed to create the frame and their dependencies are set by - // renderBinJobs() - const QVector<QAspectJobPtr> renderBinJobs = d->m_renderer->renderBinJobs(); - jobs.append(renderBinJobs); + // Let the rendering thread know that we are ready to spawn jobs if it + // can promise us that it will in fact call doRender. + if (d->m_renderer->releaseRendererAndRequestPromiseToRender()) { + // Traverse the current framegraph and create jobs to populate + // RenderBins with RenderCommands + // All jobs needed to create the frame and their dependencies are set by + // renderBinJobs() + const QVector<QAspectJobPtr> renderBinJobs = d->m_renderer->renderBinJobs(); + jobs.append(renderBinJobs); + } } return jobs; } diff --git a/src/render/frontend/qrenderaspect_p.h b/src/render/frontend/qrenderaspect_p.h index 26ca091f6..d18ce8b4f 100644 --- a/src/render/frontend/qrenderaspect_p.h +++ b/src/render/frontend/qrenderaspect_p.h @@ -90,9 +90,10 @@ public: void loadSceneParsers(); void loadRenderPlugin(const QString &pluginName); void renderInitialize(QOpenGLContext *context); - void renderSynchronous(bool blocking = false); + void tryRenderSynchronous(); void renderShutdown(); void registerBackendType(const QMetaObject &, const Qt3DCore::QBackendNodeMapperPtr &functor); + void abortRenderJobs(); QVector<Qt3DCore::QAspectJobPtr> createGeometryRendererJobs(); Render::NodeManagers *m_nodeManagers; @@ -104,6 +105,7 @@ public: QVector<Render::QRenderPlugin *> m_renderPlugins; QRenderAspect::RenderType m_renderType; Render::OffscreenSurfaceHelper *m_offscreenHelper; + bool m_blockingRendermode; static QMutex m_pluginLock; static QVector<QString> m_pluginConfig; |