From e73a5b9a7c31e267528c3f5b91af2e7953d05574 Mon Sep 17 00:00:00 2001 From: Andrew Osmond Date: Thu, 10 Dec 2020 14:26:32 +0000 Subject: [PATCH] Bug 1681563 - Record WebRender device resets in telemetry and crash reports on non-Windows. r=jrmuizel Differential Revision: https://phabricator.services.mozilla.com/D99346 --- gfx/ipc/GPUProcessManager.cpp | 11 ++++++++++ gfx/ipc/GPUProcessManager.h | 4 ++++ gfx/thebes/DeviceManagerDx.cpp | 11 +++------- gfx/thebes/gfxPlatform.h | 20 +++++++++--------- gfx/webrender_bindings/RenderThread.cpp | 27 +++++++++++++++++++++++++ 5 files changed, 56 insertions(+), 17 deletions(-) diff --git a/gfx/ipc/GPUProcessManager.cpp b/gfx/ipc/GPUProcessManager.cpp index 020109b41259..db6692e45047 100644 --- a/gfx/ipc/GPUProcessManager.cpp +++ b/gfx/ipc/GPUProcessManager.cpp @@ -7,6 +7,7 @@ #include "GPUProcessManager.h" #include "gfxConfig.h" +#include "gfxPlatform.h" #include "GPUProcessHost.h" #include "GPUProcessListener.h" #include "mozilla/MemoryReportingProcess.h" @@ -526,6 +527,16 @@ void GPUProcessManager::NotifyWebRenderError(wr::WebRenderError aError) { DisableWebRender(aError, nsCString()); } +/* static */ void GPUProcessManager::RecordDeviceReset( + DeviceResetReason aReason) { + if (aReason != DeviceResetReason::FORCED_RESET) { + Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(aReason)); + } + + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::DeviceResetReason, int(aReason)); +} + bool GPUProcessManager::OnDeviceReset(bool aTrackThreshold) { #ifdef XP_WIN // Disable double buffering when device reset happens. diff --git a/gfx/ipc/GPUProcessManager.h b/gfx/ipc/GPUProcessManager.h index da51b7075efb..5d65c011cbf6 100644 --- a/gfx/ipc/GPUProcessManager.h +++ b/gfx/ipc/GPUProcessManager.h @@ -21,6 +21,7 @@ #include "nsIObserver.h" #include "nsThreadUtils.h" class nsBaseWidget; +enum class DeviceResetReason; namespace mozilla { class MemoryReportingProcess; @@ -148,6 +149,9 @@ class GPUProcessManager final : public GPUProcessHost::Listener { // Destroy and recreate all of the compositors void ResetCompositors(); + // Record the device reset in telemetry / annotate the crash report. + static void RecordDeviceReset(DeviceResetReason aReason); + void OnProcessLaunchComplete(GPUProcessHost* aHost) override; void OnProcessUnexpectedShutdown(GPUProcessHost* aHost) override; void SimulateDeviceReset(); diff --git a/gfx/thebes/DeviceManagerDx.cpp b/gfx/thebes/DeviceManagerDx.cpp index 6121e89c7682..c62f6b39f93d 100644 --- a/gfx/thebes/DeviceManagerDx.cpp +++ b/gfx/thebes/DeviceManagerDx.cpp @@ -14,6 +14,7 @@ #include "mozilla/Telemetry.h" #include "mozilla/WindowsVersion.h" #include "mozilla/gfx/GPUParent.h" +#include "mozilla/gfx/GPUProcessManager.h" #include "mozilla/gfx/GraphicsMessages.h" #include "mozilla/gfx/Logging.h" #include "mozilla/gfx/gfxVars.h" @@ -1044,13 +1045,7 @@ bool DeviceManagerDx::MaybeResetAndReacquireDevices() { return false; } - if (resetReason != DeviceResetReason::FORCED_RESET) { - Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, - uint32_t(resetReason)); - } - - CrashReporter::AnnotateCrashReport( - CrashReporter::Annotation::DeviceResetReason, int(resetReason)); + GPUProcessManager::RecordDeviceReset(resetReason); bool createCompositorDevice = !!mCompositorDevice; bool createContentDevice = !!mContentDevice; @@ -1115,7 +1110,7 @@ static DeviceResetReason HResultToResetReason(HRESULT hr) { default: MOZ_ASSERT(false); } - return DeviceResetReason::UNKNOWN; + return DeviceResetReason::OTHER; } bool DeviceManagerDx::HasDeviceReset(DeviceResetReason* aOutReason) { diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 919992d852ed..4487347c9b18 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -146,16 +146,18 @@ inline const char* GetBackendName(mozilla::gfx::BackendType aBackend) { } enum class DeviceResetReason { - OK = 0, - HUNG, - REMOVED, - RESET, - DRIVER_ERROR, - INVALID_CALL, + OK = 0, // No reset. + HUNG, // Windows specific, guilty device reset. + REMOVED, // Windows specific, device removed or driver upgraded. + RESET, // Guilty device reset. + DRIVER_ERROR, // Innocent device reset. + INVALID_CALL, // Windows specific, guilty device reset. OUT_OF_MEMORY, - FORCED_RESET, - UNKNOWN, - D3D9_RESET + FORCED_RESET, // Simulated device reset. + OTHER, // Unrecognized reason for device reset. + D3D9_RESET, // Windows specific, not used. + NVIDIA_VIDEO, // Linux specific, NVIDIA video memory was reset. + UNKNOWN, // GL specific, unknown if guilty or innocent. }; enum class ForcedDeviceResetReason { diff --git a/gfx/webrender_bindings/RenderThread.cpp b/gfx/webrender_bindings/RenderThread.cpp index 37918df1d939..08a6d9ec09e8 100644 --- a/gfx/webrender_bindings/RenderThread.cpp +++ b/gfx/webrender_bindings/RenderThread.cpp @@ -6,6 +6,7 @@ #include "base/task.h" #include "GeckoProfiler.h" +#include "gfxPlatform.h" #include "GLContext.h" #include "RenderThread.h" #include "nsThreadUtils.h" @@ -791,6 +792,27 @@ void RenderThread::InitDeviceTask() { SharedGL(); } +#ifndef XP_WIN +static DeviceResetReason GLenumToResetReason(GLenum aReason) { + switch (aReason) { + case LOCAL_GL_NO_ERROR: + return DeviceResetReason::FORCED_RESET; + case LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB: + return DeviceResetReason::DRIVER_ERROR; + case LOCAL_GL_PURGED_CONTEXT_RESET_NV: + return DeviceResetReason::NVIDIA_VIDEO; + case LOCAL_GL_GUILTY_CONTEXT_RESET_ARB: + return DeviceResetReason::RESET; + case LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB: + return DeviceResetReason::UNKNOWN; + case LOCAL_GL_OUT_OF_MEMORY: + return DeviceResetReason::OUT_OF_MEMORY; + default: + return DeviceResetReason::OTHER; + } +} +#endif + void RenderThread::HandleDeviceReset(const char* aWhere, layers::CompositorBridgeParent* aBridge, GLenum aReason) { @@ -800,6 +822,11 @@ void RenderThread::HandleDeviceReset(const char* aWhere, return; } +#ifndef XP_WIN + // On Windows, see DeviceManagerDx::MaybeResetAndReacquireDevices. + gfx::GPUProcessManager::RecordDeviceReset(GLenumToResetReason(aReason)); +#endif + // On some platforms (i.e. Linux), we may get a device reset just for purging // video memory with NVIDIA devices, because the driver has edge cases it // needs to clear all of it.