Merge pull request #7439 from jherico/deadlock_qml

Fix potential deadlock in QML
This commit is contained in:
Brad Hefta-Gaub 2016-03-23 14:16:37 -07:00
commit dbfea6ec82
2 changed files with 29 additions and 9 deletions

View file

@ -23,6 +23,7 @@
#include <PerfStat.h> #include <PerfStat.h>
#include <DependencyManager.h> #include <DependencyManager.h>
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <Finally.h>
#include "OffscreenGLCanvas.h" #include "OffscreenGLCanvas.h"
#include "GLEscrow.h" #include "GLEscrow.h"
@ -84,6 +85,7 @@ protected:
Queue _queue; Queue _queue;
QMutex _mutex; QMutex _mutex;
QWaitCondition _waitCondition; QWaitCondition _waitCondition;
std::atomic<bool> _rendering { false };
private: private:
// Event-driven methods // Event-driven methods
@ -271,15 +273,25 @@ void OffscreenQmlRenderThread::resize() {
} }
void OffscreenQmlRenderThread::render() { void OffscreenQmlRenderThread::render() {
if (_surface->_paused) { // Ensure we always release the main thread
Finally releaseMainThread([this] {
_waitCondition.wakeOne(); _waitCondition.wakeOne();
});
if (_surface->_paused) {
return; return;
} }
QMutexLocker locker(&_mutex); _rendering = true;
_renderControl->sync(); Finally unmarkRenderingFlag([this] {
_waitCondition.wakeOne(); _rendering = false;
locker.unlock(); });
{
QMutexLocker locker(&_mutex);
_renderControl->sync();
releaseMainThread.trigger();
}
using namespace oglplus; using namespace oglplus;
@ -292,6 +304,7 @@ void OffscreenQmlRenderThread::render() {
_fbo->AttachTexture(Framebuffer::Target::Draw, FramebufferAttachment::Color, *texture, 0); _fbo->AttachTexture(Framebuffer::Target::Draw, FramebufferAttachment::Color, *texture, 0);
_fbo->Complete(Framebuffer::Target::Draw); _fbo->Complete(Framebuffer::Target::Draw);
{ {
PROFILE_RANGE("qml_render->rendercontrol")
_renderControl->render(); _renderControl->render();
// FIXME The web browsers seem to be leaving GL in an error state. // FIXME The web browsers seem to be leaving GL in an error state.
// Need a debug context with sync logging to figure out why. // Need a debug context with sync logging to figure out why.
@ -380,8 +393,6 @@ void OffscreenQmlSurface::resize(const QSize& newSize_) {
std::max(static_cast<int>(scale * newSize.height()), 10)); std::max(static_cast<int>(scale * newSize.height()), 10));
} }
QSize currentSize = _renderer->_quickWindow->geometry().size(); QSize currentSize = _renderer->_quickWindow->geometry().size();
if (newSize == currentSize) { if (newSize == currentSize) {
return; return;
@ -492,7 +503,12 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QOb
} }
void OffscreenQmlSurface::updateQuick() { void OffscreenQmlSurface::updateQuick() {
if (!_renderer || !_renderer->allowNewFrame(_maxFps)) { // If we're
// a) not set up
// b) already rendering a frame
// c) rendering too fast
// then skip this
if (!_renderer || _renderer->_rendering || !_renderer->allowNewFrame(_maxFps)) {
return; return;
} }
@ -502,11 +518,11 @@ void OffscreenQmlSurface::updateQuick() {
} }
if (_render) { if (_render) {
PROFILE_RANGE(__FUNCTION__);
// Lock the GUI size while syncing // Lock the GUI size while syncing
QMutexLocker locker(&(_renderer->_mutex)); QMutexLocker locker(&(_renderer->_mutex));
_renderer->_queue.add(RENDER); _renderer->_queue.add(RENDER);
_renderer->_waitCondition.wait(&(_renderer->_mutex)); _renderer->_waitCondition.wait(&(_renderer->_mutex));
_render = false; _render = false;
} }

View file

@ -20,6 +20,10 @@ public:
template <typename F> template <typename F>
Finally(F f) : _f(f) {} Finally(F f) : _f(f) {}
~Finally() { _f(); } ~Finally() { _f(); }
void trigger() {
_f();
_f = [] {};
}
private: private:
std::function<void()> _f; std::function<void()> _f;
}; };