summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick3d/imports/scene3d/scene3ditem.cpp23
-rw-r--r--src/quick3d/imports/scene3d/scene3drenderer.cpp19
-rw-r--r--src/quick3d/imports/scene3d/scene3drenderer_p.h3
-rw-r--r--src/render/backend/abstractrenderer_p.h2
-rw-r--r--src/render/renderers/opengl/renderer/renderer.cpp3
-rw-r--r--src/render/renderers/opengl/renderer/renderer_p.h2
-rw-r--r--tests/auto/render/commons/testrenderer.h2
7 files changed, 42 insertions, 12 deletions
diff --git a/src/quick3d/imports/scene3d/scene3ditem.cpp b/src/quick3d/imports/scene3d/scene3ditem.cpp
index 5a1cec495..f0ebfbc38 100644
--- a/src/quick3d/imports/scene3d/scene3ditem.cpp
+++ b/src/quick3d/imports/scene3d/scene3ditem.cpp
@@ -433,12 +433,26 @@ void Scene3DItem::applyRootEntityChange()
bool Scene3DItem::needsRender()
{
+ // We need the dirty flag which is connected to the change arbiter
+ // receiving updates to know whether something in the scene has changed
+
+ // Ideally we would use shouldRender() alone but given that it becomes true
+ // only after the arbiter has sync the changes and might be reset before
+ // process jobs is completed, we cannot fully rely on it. It would require
+ // splitting processFrame in 2 parts.
+
+ // We only use it for cases where Qt3D render may require several loops of
+ // the simulation to fully process a frame (e.g shaders are loaded in frame
+ // n and we can only build render commands for the new shader at frame n +
+ // This is where renderer->shouldRender() comes into play as it knows
+ // whether some states remain dirty or not (even after processFrame is
+ // called)
+
auto renderAspectPriv = static_cast<QRenderAspectPrivate*>(QRenderAspectPrivate::get(m_renderAspect));
const bool dirty = m_dirty
|| (renderAspectPriv
&& renderAspectPriv->m_renderer
- && renderAspectPriv->m_renderer->settings()
- && renderAspectPriv->m_renderer->settings()->renderPolicy() == QRenderSettings::Always);
+ && renderAspectPriv->m_renderer->shouldRender());
m_dirty = false;
return dirty;
}
@@ -466,10 +480,6 @@ void Scene3DItem::onBeforeSync()
if (!isVisible())
return;
- // Has anything in the 3D scene actually changed that requires us to render?
- if (!needsRender())
- return;
-
Q_ASSERT(QThread::currentThread() == thread());
// Since we are in manual mode, trigger jobs for the next frame
@@ -510,6 +520,7 @@ void Scene3DItem::onBeforeSync()
// start rendering before this function has been called
// We add in a safety to skip such frames as this could otherwise
// make Qt3D enter a locked state
+ m_renderer->setSkipFrame(!needsRender());
m_renderer->allowRender();
// Note: it's too early to request an update at this point as
diff --git a/src/quick3d/imports/scene3d/scene3drenderer.cpp b/src/quick3d/imports/scene3d/scene3drenderer.cpp
index 1e322a615..fafeeedf4 100644
--- a/src/quick3d/imports/scene3d/scene3drenderer.cpp
+++ b/src/quick3d/imports/scene3d/scene3drenderer.cpp
@@ -161,6 +161,7 @@ Scene3DRenderer::Scene3DRenderer(Scene3DItem *item, Qt3DCore::QAspectEngine *asp
, m_forceRecreate(false)
, m_shouldRender(false)
, m_dirtyViews(false)
+ , m_skipFrame(false)
, m_allowRendering(0)
, m_compositingMode(Scene3DItem::FBO)
{
@@ -278,6 +279,19 @@ void Scene3DRenderer::beforeSynchronize()
// We could otherwise enter a deadlock state
if (!m_allowRendering.tryAcquire(std::max(m_allowRendering.available(), 1)))
return;
+
+ // In the case of OnDemand rendering, we still need to get to this
+ // point to ensure we have processed jobs for all aspects.
+ // We also still need to call render() to allow proceeding with the
+ // next frame. However it won't be performing any 3d rendering at all
+ // so we do it here and return early. This prevents a costly QtQuick
+ // SceneGraph update for nothing
+ if (m_skipFrame) {
+ m_skipFrame = false;
+ static_cast<QRenderAspectPrivate*>(QRenderAspectPrivate::get(m_renderAspect))->renderSynchronous(false);
+ return;
+ }
+
m_shouldRender = true;
// Check size / multisampling
@@ -360,6 +374,11 @@ void Scene3DRenderer::setCompositingMode(Scene3DItem::CompositingMode mode)
m_compositingMode = mode;
}
+void Scene3DRenderer::setSkipFrame(bool skip)
+{
+ m_skipFrame = skip;
+}
+
// Main Thread, Render Thread locked
void Scene3DRenderer::setScene3DViews(const QVector<Scene3DView *> views)
{
diff --git a/src/quick3d/imports/scene3d/scene3drenderer_p.h b/src/quick3d/imports/scene3d/scene3drenderer_p.h
index 4f3651cd3..08a2c60a3 100644
--- a/src/quick3d/imports/scene3d/scene3drenderer_p.h
+++ b/src/quick3d/imports/scene3d/scene3drenderer_p.h
@@ -87,7 +87,7 @@ public:
void setCleanerHelper(Scene3DCleaner *cleaner);
void allowRender();
void setCompositingMode(Scene3DItem::CompositingMode mode);
-
+ void setSkipFrame(bool skip);
void setScene3DViews(const QVector<Scene3DView *> views);
public Q_SLOTS:
@@ -119,6 +119,7 @@ private:
bool m_forceRecreate;
bool m_shouldRender;
bool m_dirtyViews;
+ bool m_skipFrame;
QSemaphore m_allowRendering;
Scene3DItem::CompositingMode m_compositingMode;
QVector<Scene3DView *> m_views;
diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h
index b618eda55..c8dd537c7 100644
--- a/src/render/backend/abstractrenderer_p.h
+++ b/src/render/backend/abstractrenderer_p.h
@@ -151,7 +151,7 @@ public:
#if defined(QT_BUILD_INTERNAL)
virtual void clearDirtyBits(BackendNodeDirtySet changes) = 0;
#endif
- virtual bool shouldRender() = 0;
+ virtual bool shouldRender() const = 0;
virtual void skipNextFrame() = 0;
virtual QVector<Qt3DCore::QAspectJobPtr> preRenderingJobs() = 0;
diff --git a/src/render/renderers/opengl/renderer/renderer.cpp b/src/render/renderers/opengl/renderer/renderer.cpp
index a530c26b0..bf9230079 100644
--- a/src/render/renderers/opengl/renderer/renderer.cpp
+++ b/src/render/renderers/opengl/renderer/renderer.cpp
@@ -1821,12 +1821,11 @@ void Renderer::clearDirtyBits(BackendNodeDirtySet changes)
}
#endif
-bool Renderer::shouldRender()
+bool Renderer::shouldRender() const
{
// Only render if something changed during the last frame, or the last frame
// was not rendered successfully (or render-on-demand is disabled)
return (m_settings->renderPolicy() == QRenderSettings::Always
- || m_renderThread == nullptr // <==> we use Scene3D
|| m_dirtyBits.marked != 0
|| m_dirtyBits.remaining != 0
|| !m_lastFrameCorrect.loadRelaxed());
diff --git a/src/render/renderers/opengl/renderer/renderer_p.h b/src/render/renderers/opengl/renderer/renderer_p.h
index b2889bb0e..ee01754d3 100644
--- a/src/render/renderers/opengl/renderer/renderer_p.h
+++ b/src/render/renderers/opengl/renderer/renderer_p.h
@@ -207,7 +207,7 @@ public:
#if defined(QT_BUILD_INTERNAL)
void clearDirtyBits(BackendNodeDirtySet changes) override;
#endif
- bool shouldRender() override;
+ bool shouldRender() const override;
void skipNextFrame() override;
QVector<Qt3DCore::QAspectJobPtr> preRenderingJobs() override;
diff --git a/tests/auto/render/commons/testrenderer.h b/tests/auto/render/commons/testrenderer.h
index 8d27998a0..e1ee329f4 100644
--- a/tests/auto/render/commons/testrenderer.h
+++ b/tests/auto/render/commons/testrenderer.h
@@ -55,7 +55,7 @@ public:
void doRender(bool swapBuffers) override { Q_UNUSED(swapBuffers); }
void cleanGraphicsResources() override {}
bool isRunning() const override { return true; }
- bool shouldRender() override { return true; }
+ bool shouldRender() const override { return true; }
void skipNextFrame() override {}
QVector<Qt3DCore::QAspectJobPtr> preRenderingJobs() override { return QVector<Qt3DCore::QAspectJobPtr>(); }
QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() override { return QVector<Qt3DCore::QAspectJobPtr>(); }