Repository: electron/electron
Pull request: fix: software compositing infinite loop

#### Description of Change

On virtual desktop machines, such as Citrix, GPU compositing may not be available. In certain cases, we're seeing a race condition where the renderer process will get stuck in an infinite loop when calling `LayerTreeView::RequestNewLayerTreeFrameSink`. This aligns with what's reported in https://issues.chromium.org/issues/345275130

1. [LayerTreeView::RequestNewLayerTreeFrameSink](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc;l=319;drc=1bae8be84df46ae0825621f386870b2640cbc751) is called.
2. An attempt to [initialize cc::RasterContextProviderWrapper](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/widget/widget_base.cc;l=799-807;drc=a1c86f5b66b3c8430f2ab39e65a519cd31452a92) fails [due to the GPU being disabled.](https://source.chromium.org/chromium/chromium/src/+/main:services/viz/public/cpp/gpu/context_provider_command_buffer.cc;l=133-141;drc=e35c86a08334445bec5b81cdc7a8b8ffa67529f8)
3. `LayerTreeView::DidFailToInitializeLayerTreeFrameSink` is called which [posts a task to try again.](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc;l=377-379;drc=1bae8be84df46ae0825621f386870b2640cbc751) The task is performed in an infinite loop without time to process others.
4. [CompositingModeFallbackToSoftware IPC is sent](https://source.chromium.org/chromium/chromium/src/+/main:components/viz/host/compositing_mode_reporter_impl.cc;l=21;drc=e35c86a08334445bec5b81cdc7a8b8ffa67529f8) from the main/browser process, but the infinite task loop starves the RenderThread from ever receiving it.

Credit to @clavin for his thorough work in debugging the flow which leads to the task starvation bug.

Preview of trace where infinite loop occurs. `LayerTreeView::RequestNewLayerTreeFrameSink` is repeatedly called towards the right, leading to an unresponsive renderer.
<img width="1175" alt="Screenshot 2024-10-18 at 11 19 40 AM" src="https://github.com/user-attachments/assets/2da73468-a234-472c-ab5d-b22a2c1be51b">

The patch introduced adds a delay to posting the `LayerTreeView::RequestNewLayerTreeFrameSink` task. This allows the RenderThread time to receive the `CompositingModeFallbackToSoftware` IPC. We'll attempt to upstream this patch soon.

#### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->

- [x] PR description included and stakeholders cc'd
- [x] `npm test` passes
- [ ] tests are [changed or added](https://github.com/electron/electron/blob/main/docs/development/testing.md)
- [ ] relevant documentation, tutorials, templates and examples are changed or added
- [x] [PR release notes](https://github.com/electron/clerk/blob/main/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/main/README.md#examples).

#### Release Notes

Notes: Fix race condition in which WebContents appears as white screen on VDI machines without hardware acceleration capabilities.

Changed files:
filename: patches/chromium/.patches
patch: @@ -132,4 +132,5 @@ build_expose_webplugininfo_interface_to_electron.patch
 osr_shared_texture_remove_keyed_mutex_on_win_dxgi.patch
 feat_allow_usage_of_sccontentsharingpicker_on_supported_platforms.patch
 chore_partial_revert_of.patch
+fix_software_compositing_infinite_loop.patch
 ui_add_missing_shortcut_text_for_vkey_command_on_linux.patch

filename: patches/chromium/fix_software_compositing_infinite_loop.patch
patch: @@ -0,0 +1,31 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Samuel Maddock <smaddock@slack-corp.com>
+Date: Fri, 18 Oct 2024 11:11:11 -0400
+Subject: fix: software compositing infinite loop
+
+When GPU compositing is unavailable, LayerTreeView::RequestNewLayerTreeFrameSink
+may run in an infinite loop due to a race condition. Need to allow time to
+process CompositingModeFallbackToSoftware IPC to disable GPU compositing.
+
+https://issues.chromium.org/345275130
+
+diff --git a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
+index 9497ab591864295231db47fdc526e59935e6aa31..635fa41649db41800f99da2683cc955b2e1e935f 100644
+--- a/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
++++ b/third_party/blink/renderer/platform/widget/compositing/layer_tree_view.cc
+@@ -374,9 +374,13 @@ void LayerTreeView::DidFailToInitializeLayerTreeFrameSink() {
+   // unable to be killed after Chrome is closed.
+   // https://issues.chromium.org/336164423
+   if (!Platform::Current()->IsGpuRemoteDisconnected()) {
+-    layer_tree_host_->GetTaskRunnerProvider()->MainThreadTaskRunner()->PostTask(
++    // CompositingModeFallbackToSoftware IPC will disable GPU compositing in
++    // RenderThread. Post task with delay to give time to receive this IPC and
++    // prevent infinite loop of retries for software renderers.
++    // https://issues.chromium.org/345275130
++    layer_tree_host_->GetTaskRunnerProvider()->MainThreadTaskRunner()->PostDelayedTask(
+         FROM_HERE, base::BindOnce(&LayerTreeView::RequestNewLayerTreeFrameSink,
+-                                  weak_factory_.GetWeakPtr()));
++                                  weak_factory_.GetWeakPtr()), base::Milliseconds(10));
+   }
+ }
+