From c33ad93a55645784aa04fcf9baa579bc20771c3e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 6 May 2019 08:07:18 -0700 Subject: [PATCH] SharedObject::onRender deadlock fix Call gl::globalRelease() for paused surfaces, this fixes a very common deadlock on mac. But for PC, by inspection, a race condition could occur over the _syncRequested boolean, between the main and qml rendering thread. To fix this, we split render and renderSync into separate messages. --- libraries/qml/src/qml/impl/RenderEventHandler.cpp | 15 ++++++++++++++- libraries/qml/src/qml/impl/RenderEventHandler.h | 5 ++++- libraries/qml/src/qml/impl/SharedObject.cpp | 10 +++++----- libraries/qml/src/qml/impl/SharedObject.h | 2 +- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/libraries/qml/src/qml/impl/RenderEventHandler.cpp b/libraries/qml/src/qml/impl/RenderEventHandler.cpp index 97c222337b..a1edfd6789 100644 --- a/libraries/qml/src/qml/impl/RenderEventHandler.cpp +++ b/libraries/qml/src/qml/impl/RenderEventHandler.cpp @@ -31,6 +31,10 @@ bool RenderEventHandler::event(QEvent* e) { onRender(); return true; + case OffscreenEvent::RenderSync: + onRenderSync(); + return true; + case OffscreenEvent::Initialize: onInitalize(); return true; @@ -106,6 +110,14 @@ void RenderEventHandler::resize() { } void RenderEventHandler::onRender() { + qmlRender(false); +} + +void RenderEventHandler::onRenderSync() { + qmlRender(true); +} + +void RenderEventHandler::qmlRender(bool sceneGraphSync) { if (_shared->isQuit()) { return; } @@ -117,7 +129,8 @@ void RenderEventHandler::onRender() { PROFILE_RANGE(render_qml_gl, __FUNCTION__); gl::globalLock(); - if (!_shared->preRender()) { + if (!_shared->preRender(sceneGraphSync)) { + gl::globalRelease(); return; } diff --git a/libraries/qml/src/qml/impl/RenderEventHandler.h b/libraries/qml/src/qml/impl/RenderEventHandler.h index 86046c3721..139f062d0d 100644 --- a/libraries/qml/src/qml/impl/RenderEventHandler.h +++ b/libraries/qml/src/qml/impl/RenderEventHandler.h @@ -25,6 +25,7 @@ public: enum Type { Initialize = QEvent::User + 1, Render, + RenderSync, Quit }; @@ -45,6 +46,8 @@ private: void onInitalize(); void resize(); void onRender(); + void onRenderSync(); + void qmlRender(bool sceneGraphSync); void onQuit(); SharedObject* const _shared; @@ -59,4 +62,4 @@ private: }}} // namespace hifi::qml::impl -#endif \ No newline at end of file +#endif diff --git a/libraries/qml/src/qml/impl/SharedObject.cpp b/libraries/qml/src/qml/impl/SharedObject.cpp index a064be79bd..b72f37481b 100644 --- a/libraries/qml/src/qml/impl/SharedObject.cpp +++ b/libraries/qml/src/qml/impl/SharedObject.cpp @@ -344,17 +344,17 @@ void SharedObject::setSize(const QSize& size) { #endif } -bool SharedObject::preRender() { +bool SharedObject::preRender(bool sceneGraphSync) { #ifndef DISABLE_QML QMutexLocker lock(&_mutex); if (_paused) { - if (_syncRequested) { + if (sceneGraphSync) { wake(); } return false; } - if (_syncRequested) { + if (sceneGraphSync) { bool syncResult = true; if (!nsightActive()) { PROFILE_RANGE(render_qml_gl, "sync") @@ -364,7 +364,6 @@ bool SharedObject::preRender() { if (!syncResult) { return false; } - _syncRequested = false; } #endif @@ -475,9 +474,10 @@ void SharedObject::onRender() { lock.unlock(); _renderControl->polishItems(); lock.relock(); - QCoreApplication::postEvent(_renderObject, new OffscreenEvent(OffscreenEvent::Render)); + QCoreApplication::postEvent(_renderObject, new OffscreenEvent(OffscreenEvent::RenderSync)); // sync and render request, main and render threads must be synchronized wait(); + _syncRequested = false; } else { QCoreApplication::postEvent(_renderObject, new OffscreenEvent(OffscreenEvent::Render)); } diff --git a/libraries/qml/src/qml/impl/SharedObject.h b/libraries/qml/src/qml/impl/SharedObject.h index ce9fcd46d2..c9c0ef7bd0 100644 --- a/libraries/qml/src/qml/impl/SharedObject.h +++ b/libraries/qml/src/qml/impl/SharedObject.h @@ -71,7 +71,7 @@ public: private: bool event(QEvent* e) override; - bool preRender(); + bool preRender(bool sceneGraphSync); void shutdownRendering(OffscreenGLCanvas& canvas, const QSize& size); // Called by the render event handler, from the render thread void initializeRenderControl(QOpenGLContext* context);