diff --git a/Client/cefweb/CWebView.cpp b/Client/cefweb/CWebView.cpp index 28b6100d97..11d51b4f9b 100644 --- a/Client/cefweb/CWebView.cpp +++ b/Client/cefweb/CWebView.cpp @@ -41,8 +41,11 @@ CWebView::~CWebView() g_pCore->GetWebCore()->SetFocusedWebView(nullptr); } + // Make sure we don't dead lock the CEF render thread + ResumeCefThread(); + // Ensure that CefRefPtr::~CefRefPtr doesn't try to release it twice (it has already been released in CWebView::OnBeforeClose) - m_pWebView = nullptr; + m_pWebView = nullptr; OutputDebugLine("CWebView::~CWebView"); } @@ -77,6 +80,9 @@ void CWebView::CloseBrowser() // CefBrowserHost::CloseBrowser calls the destructor after the browser has been destroyed m_bBeingDestroyed = true; + // Make sure we don't dead lock the CEF render thread + ResumeCefThread(); + if (m_pWebView) m_pWebView->GetHost()->CloseBrowser(true); } @@ -200,7 +206,7 @@ void CWebView::UpdateTexture() auto pSurface = m_pWebBrowserRenderItem->m_pD3DRenderTargetSurface; if (m_bBeingDestroyed || !pSurface) - return; + m_RenderData.changed = m_RenderData.popupShown = false; // Discard current buffer if size doesn't match // This happens when resizing the browser as OnPaint is called asynchronously @@ -281,6 +287,9 @@ void CWebView::UpdateTexture() pSurface->UnlockRect(); } } + + m_RenderData.cefThreadState = ECefThreadState::Running; + m_RenderData.cefThreadCv.notify_all(); } void CWebView::ExecuteJavascript(const SString& strJavascriptCode) @@ -447,6 +456,8 @@ void CWebView::Resize(const CVector2D& size) // Send resize event to CEF if (m_pWebView) m_pWebView->GetHost()->WasResized(); + + ResumeCefThread(); } CVector2D CWebView::GetSize() @@ -709,6 +720,10 @@ void CWebView::OnPaint(CefRefPtr browser, CefRenderHandler::PaintEle m_RenderData.height = height; m_RenderData.dirtyRects = dirtyRects; m_RenderData.changed = true; + + // Wait for the main thread to handle drawing the texture + m_RenderData.cefThreadState = ECefThreadState::Wait; + m_RenderData.cefThreadCv.wait(lock, [&](){ return m_RenderData.cefThreadState == ECefThreadState::Running; }); } //////////////////////////////////////////////////////////////////// @@ -1069,3 +1084,14 @@ void CWebView::OnBeforeContextMenu(CefRefPtr browser, CefRefPtrClear(); } + +void CWebView::ResumeCefThread() +{ + { + // It's recommended to unlock a mutex before the cv notifying to avoid a possible pessimization + std::unique_lock lock(m_RenderData.dataMutex); + m_RenderData.cefThreadState = ECefThreadState::Running; + } + + m_RenderData.cefThreadCv.notify_all(); +} diff --git a/Client/cefweb/CWebView.h b/Client/cefweb/CWebView.h index 2583163e50..3096462c14 100644 --- a/Client/cefweb/CWebView.h +++ b/Client/cefweb/CWebView.h @@ -30,6 +30,12 @@ #define MTA_CEF_USERAGENT "Multi Theft Auto: San Andreas Client " MTA_DM_BUILDTAG_LONG +enum class ECefThreadState +{ + Running = 0, // CEF thread is currently running + Wait // CEF thread is waiting for the main thread +}; + class CWebView : public CWebViewInterface, private CefClient, private CefRenderHandler, @@ -173,6 +179,8 @@ class CWebView : public CWebViewInterface, CefRefPtr model) override; private: + void ResumeCefThread(); + CefRefPtr m_pWebView; CWebBrowserItem* m_pWebBrowserRenderItem; @@ -192,6 +200,8 @@ class CWebView : public CWebViewInterface, { bool changed = false; std::mutex dataMutex; + ECefThreadState cefThreadState = ECefThreadState::Running; + std::condition_variable cefThreadCv; const void* buffer; int width, height;