diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index b56de957d2..6ff0a7d416 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -566,19 +566,22 @@ void OffscreenQmlSurface::render() { glBindTexture(GL_TEXTURE_2D, texture); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); - glFinish(); { // If the most recent texture was unused, we can directly recycle it - if (_latestTextureAndFence.first) { - offscreenTextures.releaseTexture(_latestTextureAndFence); - _latestTextureAndFence = { 0, 0 }; - } - - _latestTextureAndFence = { texture, glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0) }; + auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); // Fence will be used in another thread / context, so a flush is required glFlush(); + + { + Lock lock(_latestTextureAndFenceMutex); + if (_latestTextureAndFence.first) { + offscreenTextures.releaseTexture(_latestTextureAndFence); + _latestTextureAndFence = { 0, 0 }; + } + _latestTextureAndFence = { texture, fence}; + } } _quickWindow->resetOpenGLState(); @@ -590,13 +593,21 @@ void OffscreenQmlSurface::render() { bool OffscreenQmlSurface::fetchTexture(TextureAndFence& textureAndFence) { textureAndFence = { 0, 0 }; + // Lock free early check if (0 == _latestTextureAndFence.first) { return false; } // Ensure writes to the latest texture are complete before before returning it for reading - textureAndFence = _latestTextureAndFence; - _latestTextureAndFence = { 0, 0 }; + { + Lock lock(_latestTextureAndFenceMutex); + // Double check inside the lock + if (0 == _latestTextureAndFence.first) { + return false; + } + textureAndFence = _latestTextureAndFence; + _latestTextureAndFence = { 0, 0 }; + } return true; } @@ -815,10 +826,13 @@ void OffscreenQmlSurface::resize(const QSize& newSize_, bool forceResize) { // Release hold on the textures of the old size if (uvec2() != _size) { - // If the most recent texture was unused, we can directly recycle it - if (_latestTextureAndFence.first) { - offscreenTextures.releaseTexture(_latestTextureAndFence); - _latestTextureAndFence = { 0, 0 }; + { + Lock lock(_latestTextureAndFenceMutex); + // If the most recent texture was unused, we can directly recycle it + if (_latestTextureAndFence.first) { + offscreenTextures.releaseTexture(_latestTextureAndFence); + _latestTextureAndFence = { 0, 0 }; + } } offscreenTextures.releaseSize(_size); } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 7aeac8d7c3..08c7ca6bf8 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -167,6 +167,9 @@ public slots: bool handlePointerEvent(const PointerEvent& event, class QTouchDevice& device, bool release = false); private: + using Mutex = std::mutex; + using Lock = std::unique_lock; + QQuickWindow* _quickWindow { nullptr }; QQmlContext* _qmlContext { nullptr }; QQuickItem* _rootItem { nullptr }; @@ -188,6 +191,7 @@ private: #endif // Texture management + Mutex _latestTextureAndFenceMutex; TextureAndFence _latestTextureAndFence { 0, 0 }; bool _render { false };