summaryrefslogtreecommitdiffstats
path: root/src/render/frontend
diff options
context:
space:
mode:
authorSvenn-Arne Dragly <svenn-arne.dragly@qt.io>2018-01-22 10:42:55 +0100
committerSvenn-Arne Dragly <svenn-arne.dragly@qt.io>2018-02-02 10:20:11 +0000
commit46319648436814afb5a77755dde6681e304befaf (patch)
tree9a608913dd9be2ac99bb8e5ebf446dddd69c4c4f /src/render/frontend
parent30abe028f9a95fa32fbb77cb60063d062e13f7ff (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.cpp69
-rw-r--r--src/render/frontend/qrenderaspect_p.h4
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;