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.
This commit is contained in:
Anthony J. Thibault 2019-05-06 08:07:18 -07:00 committed by Anthony Thibault
parent 86f562de1b
commit c33ad93a55
4 changed files with 24 additions and 8 deletions

View file

@ -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;
}

View file

@ -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
#endif

View file

@ -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));
}

View file

@ -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);