summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2019-08-08 14:55:52 +0200
committerPaul Lemire <paul.lemire@kdab.com>2019-08-27 12:20:45 +0200
commitf9306d34bde648975b2a3e24eea01aaa4b6bd679 (patch)
treee12be72927cd94ad1beb86b3170a1aa11b32a234
parent1fcbcf06da29a1fadd64f1fd53f6cac27f417fe1 (diff)
Refactor Scene3D internals prior to Scene3DView introduction
Change-Id: I6c9313616587c7930560a5abd962ad73d0bfff70 Reviewed-by: Mike Krus <mike.krus@kdab.com>
-rw-r--r--src/quick3d/imports/scene3d/scene3ditem.cpp51
-rw-r--r--src/quick3d/imports/scene3d/scene3drenderer.cpp70
-rw-r--r--src/quick3d/imports/scene3d/scene3drenderer_p.h2
3 files changed, 68 insertions, 55 deletions
diff --git a/src/quick3d/imports/scene3d/scene3ditem.cpp b/src/quick3d/imports/scene3d/scene3ditem.cpp
index 54f1554fd..8f3d0b9a6 100644
--- a/src/quick3d/imports/scene3d/scene3ditem.cpp
+++ b/src/quick3d/imports/scene3d/scene3ditem.cpp
@@ -365,12 +365,15 @@ bool Scene3DItem::needsRender()
// The QtQuick SG proceeds like indicated below:
// afterAnimating (Main Thread)
// beforeSynchronizing (SG Thread and MainThread locked)
-// afterSynchronizing (SG Thread)
+// afterSynchronizing (SG Thread and MainThread locked)
// beforeRendering (SG Thread)
// Note: we connect to afterAnimating rather than beforeSynchronizing as a
// direct connection on beforeSynchronizing is executed within the SG Render
-// Thread context
+// Thread context. This is executed before the RenderThread is asked to
+// synchronize and render
+// Note: we might still not be done rendering when this is called but
+// processFrame will block and wait for renderer to have been finished
void Scene3DItem::onBeforeSync()
{
// Has anything in the 3D scene actually changed that requires us to render?
@@ -381,9 +384,13 @@ void Scene3DItem::onBeforeSync()
// Since we are in manual mode, trigger jobs for the next frame
Qt3DCore::QAspectEnginePrivate *aspectEnginePriv = static_cast<Qt3DCore::QAspectEnginePrivate *>(QObjectPrivate::get(m_aspectEngine));
- if (!aspectEnginePriv->m_initialized)
+ if (!aspectEnginePriv->m_initialized || !m_renderer)
return;
+ // Set compositing mode on renderer
+ m_renderer->setCompositingMode(m_compositingMode);
+ const bool usesFBO = m_compositingMode == FBO;
+
Q_ASSERT(m_aspectEngine->runMode() == Qt3DCore::QAspectEngine::Manual);
m_aspectEngine->processFrame();
// The above essentially sets the number of RV for the RenderQueue and
@@ -399,14 +406,13 @@ 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
- if (m_renderer)
- m_renderer->allowRender();
+ m_renderer->allowRender();
// Request refresh for next frame
// When using the FBO mode, only the QQuickItem needs to be updated
// When using the Underlay mode, the whole windows needs updating
- if (m_compositingMode == FBO)
+ if (usesFBO)
QQuickItem::update();
else
window()->update();
@@ -532,24 +538,12 @@ QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNode
m_renderer = new Scene3DRenderer(this, m_aspectEngine, m_renderAspect);
m_renderer->setCleanerHelper(m_rendererCleaner);
}
- m_renderer->setCompositingMode(m_compositingMode);
-
- Scene3DSGNode *fboNode = static_cast<Scene3DSGNode *>(node);
const bool usesFBO = m_compositingMode == FBO;
- if (usesFBO) {
- if (fboNode == nullptr) {
- fboNode = new Scene3DSGNode();
- m_renderer->setSGNode(fboNode);
- }
- fboNode->setRect(boundingRect());
+ Scene3DSGNode *fboNode = static_cast<Scene3DSGNode *>(node);
- // Reset clear flag if we've set it to false it's still set to that
- if (m_disableClearWindow && !window()->clearBeforeRendering())
- window()->setClearBeforeRendering(m_clearsWindowByDefault);
- m_disableClearWindow = false;
- } else {
- // In FBOLess node the Scene3DItem doesn't have any QSGNode to actually
- // manager
+ // When usin Scene3DViews or Scene3D in Underlay mode
+ // we shouldn't be managing a Scene3DSGNode
+ if (!usesFBO) {
if (fboNode != nullptr) {
delete fboNode;
fboNode = nullptr;
@@ -560,6 +554,19 @@ QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNode
m_disableClearWindow = true;
if (m_clearsWindowByDefault)
window()->setClearBeforeRendering(false);
+ } else {
+ // Regular Scene3D only case
+ // Create SGNode if using FBO and no Scene3DViews
+ if (fboNode == nullptr) {
+ fboNode = new Scene3DSGNode();
+ m_renderer->setSGNode(fboNode);
+ }
+ fboNode->setRect(boundingRect());
+
+ // Reset clear flag if we've set it to false it's still set to that
+ if (m_disableClearWindow && !window()->clearBeforeRendering())
+ window()->setClearBeforeRendering(m_clearsWindowByDefault);
+ m_disableClearWindow = false;
}
return fboNode;
diff --git a/src/quick3d/imports/scene3d/scene3drenderer.cpp b/src/quick3d/imports/scene3d/scene3drenderer.cpp
index da63c32d8..bc75e0861 100644
--- a/src/quick3d/imports/scene3d/scene3drenderer.cpp
+++ b/src/quick3d/imports/scene3d/scene3drenderer.cpp
@@ -165,7 +165,7 @@ Scene3DRenderer::Scene3DRenderer(Scene3DItem *item, Qt3DCore::QAspectEngine *asp
Q_CHECK_PTR(m_item->window());
m_window = m_item->window();
- QObject::connect(m_item->window(), &QQuickWindow::afterSynchronizing, this, &Scene3DRenderer::synchronize, Qt::DirectConnection);
+ QObject::connect(m_item->window(), &QQuickWindow::beforeSynchronizing, this, &Scene3DRenderer::beforeSynchronize, Qt::DirectConnection);
QObject::connect(m_item->window(), &QQuickWindow::beforeRendering, this, &Scene3DRenderer::render, Qt::DirectConnection);
QObject::connect(m_item->window(), &QQuickWindow::sceneGraphInvalidated, this, &Scene3DRenderer::onSceneGraphInvalidated, Qt::DirectConnection);
// So that we can schedule the cleanup
@@ -266,7 +266,8 @@ void Scene3DRenderer::onWindowChanged(QQuickWindow *w)
}
}
-void Scene3DRenderer::synchronize()
+// Render Thread, GUI locked
+void Scene3DRenderer::beforeSynchronize()
{
if (m_item && m_window) {
@@ -274,20 +275,19 @@ void Scene3DRenderer::synchronize()
// We could otherwise enter a deadlock state
if (!m_allowRendering.tryAcquire(std::max(m_allowRendering.available(), 1)))
return;
-
m_shouldRender = true;
+ // Check size / multisampling
m_multisample = m_item->multisample();
-
- if (m_aspectEngine->rootEntity() != m_item->entity()) {
- scheduleRootEntityChange();
- }
-
const QSize boundingRectSize = m_item->boundingRect().size().toSize();
const QSize currentSize = boundingRectSize * m_window->effectiveDevicePixelRatio();
const bool sizeHasChanged = currentSize != m_lastSize;
const bool multisampleHasChanged = m_multisample != m_lastMultisample;
- m_forceRecreate |= sizeHasChanged || multisampleHasChanged;
+ const bool forceRecreate = sizeHasChanged || multisampleHasChanged;
+ // Store the current size as a comparison
+ // point for the next frame
+ m_lastSize = currentSize;
+ m_lastMultisample = m_multisample;
if (sizeHasChanged) {
static const QMetaMethod setItemAreaAndDevicePixelRatio = setItemAreaAndDevicePixelRatioMethod();
@@ -295,13 +295,37 @@ void Scene3DRenderer::synchronize()
Q_ARG(qreal, m_window->effectiveDevicePixelRatio()));
}
- // Store the current size as a comparison
- // point for the next frame
- m_lastSize = currentSize;
- m_lastMultisample = m_multisample;
+ // Rebuild FBO if size/multisampling has changed
+ const bool usesFBO = m_compositingMode == Scene3DItem::FBO;
+ if (usesFBO) {
+ // Rebuild FBO and textures if never created or a resize has occurred
+ if ((m_multisampledFBO.isNull() || forceRecreate) && m_multisample) {
+ m_multisampledFBO.reset(createMultisampledFramebufferObject(m_lastSize));
+ if (m_multisampledFBO->format().samples() == 0 || !QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) {
+ m_multisample = false;
+ m_multisampledFBO.reset(nullptr);
+ }
+ }
+
+ const bool generateNewTexture = m_finalFBO.isNull() || forceRecreate;
+ if (generateNewTexture) {
+ m_finalFBO.reset(createFramebufferObject(m_lastSize));
+ m_texture.reset(m_window->createTextureFromId(m_finalFBO->texture(), m_finalFBO->size(), QQuickWindow::TextureHasAlphaChannel));
+ }
+
+ // Set texture on node
+ if (m_node && (!m_node->texture() || generateNewTexture))
+ m_node->setTexture(m_texture.data());
+ }
+
+ if (m_aspectEngine->rootEntity() != m_item->entity()) {
+ scheduleRootEntityChange();
+ }
+ // Mark SGNodes as dirty so that QQuick will trigger some rendering
if (m_node)
m_node->markDirty(QSGNode::DirtyMaterial);
+
m_item->update();
}
}
@@ -321,13 +345,13 @@ void Scene3DRenderer::setSGNode(Scene3DSGNode *node)
m_node = node;
}
+// Render Thread, Main Thread is unlocked at this point
void Scene3DRenderer::render()
{
QMutexLocker l(&m_windowMutex);
// Lock to ensure the window doesn't change while we are rendering
if (!m_window || !m_shouldRender)
return;
-
m_shouldRender = false;
ContextSaver saver;
@@ -339,24 +363,6 @@ void Scene3DRenderer::render()
// Create and bind FBO if using the FBO compositing mode
const bool usesFBO = m_compositingMode == Scene3DItem::FBO;
if (usesFBO) {
- // Rebuild FBO and textures if never created or a resize has occurred
- if ((m_multisampledFBO.isNull() || m_forceRecreate) && m_multisample) {
- m_multisampledFBO.reset(createMultisampledFramebufferObject(m_lastSize));
- if (m_multisampledFBO->format().samples() == 0 || !QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) {
- m_multisample = false;
- m_multisampledFBO.reset(nullptr);
- }
- }
-
- if (m_finalFBO.isNull() || m_forceRecreate) {
- m_finalFBO.reset(createFramebufferObject(m_lastSize));
- m_texture.reset(m_window->createTextureFromId(m_finalFBO->texture(), m_finalFBO->size(), QQuickWindow::TextureHasAlphaChannel));
- m_node->setTexture(m_texture.data());
- }
-
-
- m_forceRecreate = false;
-
// Bind FBO
if (m_multisample) //Only try to use MSAA when available
m_multisampledFBO->bind();
diff --git a/src/quick3d/imports/scene3d/scene3drenderer_p.h b/src/quick3d/imports/scene3d/scene3drenderer_p.h
index a2deed61e..11dfef77d 100644
--- a/src/quick3d/imports/scene3d/scene3drenderer_p.h
+++ b/src/quick3d/imports/scene3d/scene3drenderer_p.h
@@ -96,7 +96,7 @@ public Q_SLOTS:
private:
QOpenGLFramebufferObject *createMultisampledFramebufferObject(const QSize &size);
QOpenGLFramebufferObject *createFramebufferObject(const QSize &size);
- void synchronize();
+ void beforeSynchronize();
void scheduleRootEntityChange();
Scene3DItem *m_item; // Will be released by the QQuickWindow/QML Engine