Bug 1852144 - Disable remote canvas globally in case of unrecoverable error. r=gfx-reviewers,lsalzman

This patch makes the remote canvas enabled state global. If we failed to
create a context, then it cannot recover, so we should never try again.
In the event of stream errors, it is likely due to virtual memory
shortages.

Differential Revision: https://phabricator.services.mozilla.com/D187718
This commit is contained in:
Andrew Osmond 2023-09-25 16:18:35 +00:00
Родитель c31b4c1af9
Коммит 620833163a
14 изменённых файлов: 110 добавлений и 8 удалений

Просмотреть файл

@ -52,6 +52,7 @@ namespace gfx {
_(ACCELERATED_CANVAS2D, Feature, "Accelerated Canvas2D") \
_(H264_HW_DECODE, Feature, "H.264 hardware decoding") \
_(AV1_HW_DECODE, Feature, "AV1 hardware decoding") \
_(REMOTE_CANVAS, Feature, "Remote canvas") \
/* Add new entries above this comment */
enum class Feature : uint32_t {

Просмотреть файл

@ -5,9 +5,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CanvasManagerParent.h"
#include "gfxPlatform.h"
#include "mozilla/dom/WebGLParent.h"
#include "mozilla/gfx/CanvasRenderThread.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/GPUParent.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/webgpu/WebGPUParent.h"
@ -80,6 +82,17 @@ CanvasManagerParent::ManagerSet CanvasManagerParent::sManagers;
}
}
/* static */ void CanvasManagerParent::DisableRemoteCanvas() {
NS_DispatchToMainThread(
NS_NewRunnableFunction("CanvasManagerParent::DisableRemoteCanvas", [] {
if (XRE_IsGPUProcess()) {
GPUParent::GetSingleton()->NotifyDisableRemoteCanvas();
} else {
gfxPlatform::DisableRemoteCanvas();
}
}));
}
CanvasManagerParent::CanvasManagerParent() = default;
CanvasManagerParent::~CanvasManagerParent() = default;

Просмотреть файл

@ -19,6 +19,8 @@ class CanvasManagerParent final : public PCanvasManagerParent {
static void Shutdown();
static void DisableRemoteCanvas();
CanvasManagerParent();
void Bind(Endpoint<PCanvasManagerParent>&& aEndpoint);

Просмотреть файл

@ -236,6 +236,11 @@ mozilla::ipc::IPCResult GPUChild::RecvNotifySwapChainInfo(
return IPC_OK();
}
mozilla::ipc::IPCResult GPUChild::RecvNotifyDisableRemoteCanvas() {
gfxPlatform::DisableRemoteCanvas();
return IPC_OK();
}
mozilla::ipc::IPCResult GPUChild::RecvFlushMemory(const nsString& aReason) {
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {

Просмотреть файл

@ -73,6 +73,7 @@ class GPUChild final : public ipc::CrashReporterHelper<GeckoProcessType_GPU>,
mozilla::ipc::IPCResult RecvNotifyDeviceReset(const GPUDeviceData& aData);
mozilla::ipc::IPCResult RecvNotifyOverlayInfo(const OverlayInfo aInfo);
mozilla::ipc::IPCResult RecvNotifySwapChainInfo(const SwapChainInfo aInfo);
mozilla::ipc::IPCResult RecvNotifyDisableRemoteCanvas();
mozilla::ipc::IPCResult RecvFlushMemory(const nsString& aReason);
mozilla::ipc::IPCResult RecvAddMemoryReport(const MemoryReport& aReport);
mozilla::ipc::IPCResult RecvUpdateFeature(const Feature& aFeature,

Просмотреть файл

@ -252,6 +252,17 @@ void GPUParent::NotifySwapChainInfo(layers::SwapChainInfo aInfo) {
Unused << SendNotifySwapChainInfo(aInfo);
}
void GPUParent::NotifyDisableRemoteCanvas() {
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(NS_NewRunnableFunction(
"gfx::GPUParent::NotifyDisableRemoteCanvas", []() -> void {
GPUParent::GetSingleton()->NotifyDisableRemoteCanvas();
}));
return;
}
Unused << SendNotifyDisableRemoteCanvas();
}
mozilla::ipc::IPCResult GPUParent::RecvInit(
nsTArray<GfxVarUpdate>&& vars, const DevicePrefs& devicePrefs,
nsTArray<LayerTreeIdMapping>&& aMappings,

Просмотреть файл

@ -45,6 +45,7 @@ class GPUParent final : public PGPUParent {
void NotifyDeviceReset();
void NotifyOverlayInfo(layers::OverlayInfo aInfo);
void NotifySwapChainInfo(layers::SwapChainInfo aInfo);
void NotifyDisableRemoteCanvas();
mozilla::ipc::IPCResult RecvInit(nsTArray<GfxVarUpdate>&& vars,
const DevicePrefs& devicePrefs,

Просмотреть файл

@ -162,6 +162,7 @@ child:
async NotifyDeviceReset(GPUDeviceData status);
async NotifyOverlayInfo(OverlayInfo info);
async NotifySwapChainInfo(SwapChainInfo info);
async NotifyDisableRemoteCanvas();
async FlushMemory(nsString reason);
async AddMemoryReport(MemoryReport aReport);

Просмотреть файл

@ -8,12 +8,15 @@
#include "gfxGradientCache.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/CanvasManagerParent.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/GPUParent.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/layers/SharedSurfacesParent.h"
#include "mozilla/layers/TextureClient.h"
#include "mozilla/SyncRunnable.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/Telemetry.h"
#include "nsTHashSet.h"
#include "RecordedCanvasEventImpl.h"
@ -171,7 +174,7 @@ ipc::IPCResult CanvasTranslator::RecvNewBuffer(
}
ipc::IPCResult CanvasTranslator::RecvResumeTranslation() {
if (mDeactivated) {
if (CheckDeactivated()) {
// The other side might have sent a resume message before we deactivated.
return IPC_OK();
}
@ -236,6 +239,18 @@ void CanvasTranslator::FinishShutdown() {
canvasTranslators.Remove(this);
}
bool CanvasTranslator::CheckDeactivated() {
if (mDeactivated) {
return true;
}
if (NS_WARN_IF(!gfx::gfxVars::RemoteCanvasEnabled())) {
Deactivate();
}
return mDeactivated;
}
void CanvasTranslator::Deactivate() {
if (mDeactivated) {
return;
@ -257,6 +272,9 @@ void CanvasTranslator::Deactivate() {
// Also notify anyone waiting for a surface descriptor. This must be done
// after mDeactivated is set to true.
mSurfaceDescriptorsMonitor.NotifyAll();
// Disable remote canvas for all.
gfx::CanvasManagerParent::DisableRemoteCanvas();
}
bool CanvasTranslator::TranslateRecording() {

Просмотреть файл

@ -20,6 +20,8 @@
#include "mozilla/UniquePtr.h"
namespace mozilla {
class TaskQueue;
namespace layers {
class TextureData;
@ -262,6 +264,8 @@ class CanvasTranslator final : public gfx::InlineTranslator,
void FinishShutdown();
bool CheckDeactivated();
void Deactivate();
TextureData* CreateTextureData(TextureType aTextureType,

Просмотреть файл

@ -2475,8 +2475,24 @@ void gfxPlatform::InitAcceleration() {
"media.hardware-video-decoding.failed");
InitGPUProcessPrefs();
gfxVars::SetRemoteCanvasEnabled(StaticPrefs::gfx_canvas_remote() &&
gfxConfig::IsEnabled(Feature::GPU_PROCESS));
FeatureState& feature = gfxConfig::GetFeature(Feature::REMOTE_CANVAS);
feature.SetDefault(StaticPrefs::gfx_canvas_remote_AtStartup(),
FeatureStatus::Disabled, "Disabled via pref");
if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS) &&
!StaticPrefs::gfx_canvas_remote_allow_in_parent_AtStartup()) {
feature.Disable(FeatureStatus::UnavailableNoGpuProcess,
"Disabled without GPU process",
"FEATURE_REMOTE_CANVAS_NO_GPU_PROCESS"_ns);
}
#ifndef XP_WIN
gfxConfig::ForceDisable(Feature::REMOTE_CANVAS, FeatureStatus::Blocked,
"Platform not supported",
"FEATURE_REMOTE_CANVAS_NOT_WINDOWS"_ns);
#endif
gfxVars::SetRemoteCanvasEnabled(feature.IsEnabled());
}
}
@ -3815,7 +3831,15 @@ bool gfxPlatform::FallbackFromAcceleration(FeatureStatus aStatus,
/* static */
void gfxPlatform::DisableGPUProcess() {
gfxVars::SetRemoteCanvasEnabled(false);
if (gfxVars::RemoteCanvasEnabled() &&
!StaticPrefs::gfx_canvas_remote_allow_in_parent_AtStartup()) {
gfxConfig::Disable(
Feature::REMOTE_CANVAS, FeatureStatus::UnavailableNoGpuProcess,
"Disabled by GPU process disabled",
"FEATURE_REMOTE_CANVAS_DISABLED_BY_GPU_PROCESS_DISABLED"_ns);
gfxVars::SetRemoteCanvasEnabled(false);
}
if (kIsAndroid) {
// On android, enable out-of-process WebGL only when GPU process exists.
gfxVars::SetAllowWebglOop(false);
@ -3836,6 +3860,16 @@ void gfxPlatform::DisableGPUProcess() {
image::ImageMemoryReporter::InitForWebRender();
}
/* static */ void gfxPlatform::DisableRemoteCanvas() {
if (!gfxVars::RemoteCanvasEnabled()) {
return;
}
gfxConfig::ForceDisable(Feature::REMOTE_CANVAS, FeatureStatus::Failed,
"Disabled by runtime error",
"FEATURE_REMOTE_CANVAS_RUNTIME_ERROR"_ns);
gfxVars::SetRemoteCanvasEnabled(false);
}
void gfxPlatform::FetchAndImportContentDeviceData() {
MOZ_ASSERT(XRE_IsContentProcess());

Просмотреть файл

@ -777,6 +777,8 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener {
mSwapChainInfo = mozilla::Some(aInfo);
}
static void DisableRemoteCanvas();
static bool HasVariationFontSupport();
// you probably want to use gfxVars::UseWebRender() instead of this

Просмотреть файл

@ -5653,13 +5653,18 @@
mirror: always
- name: gfx.canvas.remote
type: RelaxedAtomicBool
type: bool
#if defined(XP_WIN)
value: true
#else
value: false
#endif
mirror: always
mirror: once
- name: gfx.canvas.remote.allow-in-parent
type: bool
value: false
mirror: once
- name: gfx.canvas.willreadfrequently.enabled
type: bool

Просмотреть файл

@ -4100,13 +4100,15 @@ gfx.canvas.remote:
- 1672582
- 1706844
- 1739290
- 1852144
description: >
Number of times remote canvas 2D has been deactivated due to device creation failure.
kind: uint
expires: "103"
expires: "130"
notification_emails:
- gfx-telemetry-alerts@mozilla.com
- bowen@mozilla.com
- aosmond@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'
@ -4119,13 +4121,15 @@ gfx.canvas.remote:
- 1672582
- 1706844
- 1739290
- 1852144
description: >
Number of times remote canvas 2D has been deactivated due to a stream read failure.
kind: uint
expires: "103"
expires: "130"
notification_emails:
- gfx-telemetry-alerts@mozilla.com
- bowen@mozilla.com
- aosmond@mozilla.com
release_channel_collection: opt-out
products:
- 'firefox'