tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 2f8d18d9bd7b85620ddc58a25fe36c6b1c87c860
parent d33b4c513b87f48a62169adf23896d350a798d02
Author: Andrew Osmond <aosmond@gmail.com>
Date:   Wed,  5 Nov 2025 12:51:27 +0000

Bug 1998068 - Streamline device reset handling to avoid duplicates and incompletes. r=gfx-reviewers,bradwerth

This patch simplifies that device reset logic to ensure that we always
finish completing a device reset, regardless of our present state. This
is because once we are in the middle of a device reset, we fail to
create new compositor sessions. So even if we managed to somehow
partially recover (particularly from the Windows perspective) or never
had a full reset, we should always complete the transaction to make the
parent process recreate all of its compositor sessions, in process or
remote.

We also now unify that device reset handling from nsWindow::Paint on
Windows so that if there are multiple pathways we trigger the same
device reset, we will always complete handling it properly.

Differential Revision: https://phabricator.services.mozilla.com/D271126

Diffstat:
Mgfx/ipc/GPUChild.cpp | 3---
Mgfx/ipc/GPUParent.cpp | 17-----------------
Mgfx/ipc/GPUProcessManager.cpp | 49++++++++++++++++++++++++++++++-------------------
Mgfx/webrender_bindings/RenderThread.cpp | 56++++++++++++++++----------------------------------------
Mgfx/webrender_bindings/RenderThread.h | 4++++
Mwidget/windows/nsWindowGfx.cpp | 7+++----
6 files changed, 53 insertions(+), 83 deletions(-)

diff --git a/gfx/ipc/GPUChild.cpp b/gfx/ipc/GPUChild.cpp @@ -26,9 +26,6 @@ #include "mozilla/dom/MemoryReportRequest.h" #include "mozilla/gfx/Logging.h" #include "mozilla/gfx/gfxVars.h" -#if defined(XP_WIN) -# include "mozilla/gfx/DeviceManagerDx.h" -#endif #include "mozilla/HangDetails.h" #include "mozilla/RemoteMediaManagerChild.h" // For RemoteMediaIn #include "mozilla/ipc/Endpoint.h" diff --git a/gfx/ipc/GPUParent.cpp b/gfx/ipc/GPUParent.cpp @@ -233,23 +233,6 @@ bool GPUParent::Init(mozilla::ipc::UntypedEndpoint&& aEndpoint, void GPUParent::NotifyDeviceReset(DeviceResetReason aReason, DeviceResetDetectPlace aPlace) { - if (!NS_IsMainThread()) { - NS_DispatchToMainThread(NS_NewRunnableFunction( - "gfx::GPUParent::NotifyDeviceReset", [aReason, aPlace]() -> void { - GPUParent::GetSingleton()->NotifyDeviceReset(aReason, aPlace); - })); - return; - } - - // Reset and reinitialize the compositor devices -#ifdef XP_WIN - if (!DeviceManagerDx::Get()->MaybeResetAndReacquireDevices()) { - // If the device doesn't need to be reset then the device - // has already been reset by a previous NotifyDeviceReset message. - return; - } -#endif - // Notify the main process that there's been a device reset // and that they should reset their compositors and repaint GPUDeviceData data; diff --git a/gfx/ipc/GPUProcessManager.cpp b/gfx/ipc/GPUProcessManager.cpp @@ -71,6 +71,7 @@ #if defined(XP_WIN) # include "gfxWindowsPlatform.h" +# include "mozilla/gfx/DeviceManagerDx.h" #endif namespace mozilla { @@ -826,29 +827,39 @@ void GPUProcessManager::RecordDeviceReset(DeviceResetReason aReason) { /* static */ void GPUProcessManager::NotifyDeviceReset(DeviceResetReason aReason, DeviceResetDetectPlace aPlace) { + if (!NS_IsMainThread()) { + NS_DispatchToMainThread(NS_NewRunnableFunction( + "gfx::GPUProcessManager::NotifyDeviceReset", + [aReason, aPlace]() -> void { + gfx::GPUProcessManager::NotifyDeviceReset(aReason, aPlace); + })); + return; + } + +#ifdef XP_WIN + // Reset and reinitialize the compositor devices + if (auto* deviceManager = DeviceManagerDx::Get()) { + deviceManager->MaybeResetAndReacquireDevices(); + } +#else + gfx::GPUProcessManager::RecordDeviceReset(aReason); +#endif + if (XRE_IsGPUProcess()) { - if (!GPUParent::GetSingleton()) { - MOZ_ASSERT_UNREACHABLE("unexpected to be called"); - return; - } - // End up to GPUProcessManager::OnRemoteProcessDeviceReset() - GPUParent::GetSingleton()->NotifyDeviceReset(aReason, aPlace); - } else { - if (!GPUProcessManager::Get()) { + if (auto* gpuParent = GPUParent::GetSingleton()) { + // End up to GPUProcessManager::OnRemoteProcessDeviceReset() + gpuParent->NotifyDeviceReset(aReason, aPlace); + } else { MOZ_ASSERT_UNREACHABLE("unexpected to be called"); - return; } + return; + } - if (NS_IsMainThread()) { - GPUProcessManager::Get()->OnInProcessDeviceReset(aReason, aPlace); - } else { - NS_DispatchToMainThread(NS_NewRunnableFunction( - "gfx::GPUProcessManager::OnInProcessDeviceReset", - [aReason, aPlace]() -> void { - gfx::GPUProcessManager::Get()->OnInProcessDeviceReset(aReason, - aPlace); - })); - } + MOZ_ASSERT(XRE_IsParentProcess()); + if (auto* gpm = GPUProcessManager::Get()) { + gpm->OnInProcessDeviceReset(aReason, aPlace); + } else { + MOZ_ASSERT_UNREACHABLE("unexpected to be called"); } } diff --git a/gfx/webrender_bindings/RenderThread.cpp b/gfx/webrender_bindings/RenderThread.cpp @@ -1315,41 +1315,31 @@ void RenderThread::PostRunnable(already_AddRefed<nsIRunnable> aRunnable) { mThread->Dispatch(runnable.forget()); } +/* static */ void RenderThread::PostHandleDeviceReset( + gfx::DeviceResetDetectPlace aPlace, gfx::DeviceResetReason aReason) { + MOZ_ASSERT(!IsInRenderThread()); + auto* renderThread = Get(); + if (!renderThread) { + gfx::GPUProcessManager::NotifyDeviceReset(aReason, aPlace); + return; + } + + renderThread->PostRunnable( + NewRunnableMethod<gfx::DeviceResetDetectPlace, gfx::DeviceResetReason>( + "wr::RenderThread::HandleDeviceReset", renderThread, + &RenderThread::HandleDeviceReset, aPlace, aReason)); +} + void RenderThread::HandleDeviceReset(gfx::DeviceResetDetectPlace aPlace, gfx::DeviceResetReason aReason) { MOZ_ASSERT(IsInRenderThread()); - // This happens only on simulate device reset. - if (aReason == gfx::DeviceResetReason::FORCED_RESET) { - if (!mHandlingDeviceReset) { - mHandlingDeviceReset = true; - - MutexAutoLock lock(mRenderTextureMapLock); - mRenderTexturesDeferred.clear(); - for (const auto& entry : mRenderTextures) { - entry.second->ClearCachedResources(); - } - - // All RenderCompositors will be destroyed by the GPUProcessManager in - // either OnRemoteProcessDeviceReset via the GPUChild, or - // OnInProcessDeviceReset here directly. - gfx::GPUProcessManager::GPUProcessManager::NotifyDeviceReset( - gfx::DeviceResetReason::FORCED_RESET, aPlace); - } - return; - } - if (mHandlingDeviceReset) { return; } mHandlingDeviceReset = true; -#ifndef XP_WIN - // On Windows, see DeviceManagerDx::MaybeResetAndReacquireDevices. - gfx::GPUProcessManager::RecordDeviceReset(aReason); -#endif - { MutexAutoLock lock(mRenderTextureMapLock); mRenderTexturesDeferred.clear(); @@ -1358,21 +1348,7 @@ void RenderThread::HandleDeviceReset(gfx::DeviceResetDetectPlace aPlace, } } - // All RenderCompositors will be destroyed by the GPUProcessManager in - // either OnRemoteProcessDeviceReset via the GPUChild, or - // OnInProcessDeviceReset here directly. - // On Windows, device will be re-created before sessions re-creation. - if (XRE_IsGPUProcess()) { - gfx::GPUProcessManager::GPUProcessManager::NotifyDeviceReset(aReason, - aPlace); - } else { -#ifndef XP_WIN - // FIXME(aosmond): Do we need to do this on Windows? nsWindow::OnPaint - // seems to do its own detection for the parent process. - gfx::GPUProcessManager::GPUProcessManager::NotifyDeviceReset(aReason, - aPlace); -#endif - } + gfx::GPUProcessManager::NotifyDeviceReset(aReason, aPlace); } bool RenderThread::IsHandlingDeviceReset() { diff --git a/gfx/webrender_bindings/RenderThread.h b/gfx/webrender_bindings/RenderThread.h @@ -182,6 +182,10 @@ class RenderThread final { static RefPtr<MemoryReportPromise> AccumulateMemoryReport( MemoryReport aInitial); + /// Can only be called from the main thread. + static void PostHandleDeviceReset(gfx::DeviceResetDetectPlace aPlace, + gfx::DeviceResetReason aReason); + /// Can only be called from the render thread. void AddRenderer(wr::WindowId aWindowId, UniquePtr<RendererOGL> aRenderer); diff --git a/widget/windows/nsWindowGfx.cpp b/widget/windows/nsWindowGfx.cpp @@ -45,9 +45,9 @@ #include "mozilla/layers/WebRenderLayerManager.h" #include "ImageRegion.h" -#include "mozilla/gfx/GPUProcessManager.h" #include "mozilla/layers/CompositorBridgeParent.h" #include "mozilla/layers/CompositorBridgeChild.h" +#include "mozilla/webrender/RenderThread.h" #include "InProcessWinCompositorWidget.h" using namespace mozilla; @@ -147,9 +147,8 @@ bool nsWindow::OnPaint() { gfxCriticalNote << "(nsWindow) Detected device reset: " << (int)resetReason; gfxWindowsPlatform::GetPlatform()->UpdateRenderMode(); - - GPUProcessManager::GPUProcessManager::NotifyDeviceReset( - resetReason, gfx::DeviceResetDetectPlace::WIDGET); + wr::RenderThread::PostHandleDeviceReset(gfx::DeviceResetDetectPlace::WIDGET, + resetReason); gfxCriticalNote << "(nsWindow) Finished device reset."; return false;