Closed Bug 1943517 Opened 19 days ago Closed 12 days ago

Window transparency doesn't work with gpu process disabled (which causes issues when mica is enabled and the gpu process dies repeatedly)

Categories

(Core :: Graphics, defect)

defect

Tracking

()

VERIFIED FIXED
136 Branch
Tracking Status
firefox-esr128 --- unaffected
firefox134 --- wontfix
firefox135 --- fix-optional
firefox136 --- verified

People

(Reporter: mayankleoboy1, Assigned: emilio)

References

(Blocks 1 open bug, Regression)

Details

(Keywords: regression)

Attachments

(6 files)

  1. Create new firefox profile
  2. set widget.windows.mica = true
  3. restart firefox and go to https://en.wikipedia.org/wiki/Barack_Obama
  4. in a new window, open about:support
  5. Make both the windows as foreground
  6. Click on "terminate gpu process" once. The obama page will go black. Click inside the page to restore it.
  7. Now repeatedly and rapidly start clicking on "terminate gpu process"
  8. If you dont repro, restart from step 3 and repeat step6 2-3 times.

AR: After maybe 30 clicks, the browser UI will stop responding to mouse clicks.
ER: not so.

Attached file about:support
Flags: needinfo?(emilio)
Summary: With mica enabled, repeatedly manually terminating the gpu process will cause the whole UI to freeze → With mica enabled, repeatedly manually terminating the gpu process will cause the whole UI to freeze/disappear

I cant get a log as all UI elements in the the about:logging tab (including the "capture the profile") get blank during the STR.

Set release status flags based on info from the regressing bug 1764822

May be easier to repro if you force enable software-wr by setting gfx.webrender.software=TRUE, restarting browser, and then going to town on the "trigger gpu reset" button.

I mean, if I hammer that button I can also get full browser crashes like:

[Parent 25312, Compositor] WARNING: Invalid to register the same layer tree twice: file D:/moz/gecko/gfx/layers/ipc/CompositorBridgeParent.cpp:891
[25312] Hit MOZ_CRASH(Use IPC_FAIL only in an unrecoverable, unexpected state: RecvNotifyChildRecreated

even with Mica disabled... So I'm a bit skeptic this is mica-specific. That said this is a debug assert

Sotaro, do you know how to best debug this?

Component: Widget: Win32 → Graphics
Flags: needinfo?(emilio) → needinfo?(sotaro.ikeda.g)

Another assert, also with mica disabled:

[18680] Assertion failure: state.mApzcTreeManagerParent == parent, at D:/moz/gecko/gfx/layers/ipc/ContentCompositorBridgeParent.cpp:99

I'm pretty sure this is not mica-specific at this point, though it might be easier to hit? Not sure.

FWIW, without being mica-specific, its easy to get errors in gfx-critical notes in about:support by hammering that button. But that doesnt necessarily make the UI unusable. This bug is specific about the UI going blank and/or not responding.
I didnt get any crash with that button though, and i was trying really hard to get it to crash or hang :)

With the log, it seemed that the problem seemed to happen since Firefox fallbacked to no gpu process with software webrender.

Assignee: nobody → sotaro.ikeda.g
Flags: needinfo?(sotaro.ikeda.g)

With the following pref, Firefox window did not updated. mica might not work without gpu process

  • pref widget.windows.mica = true
  • pref layers.gpu-process.enabled = false

Hmm, I see... The only difference mica introduces is window transparency and this bit to add the backdrop.

I'm not on windows right now, but does the same happen with only layers.gpu-process.enabled = false and something like:

diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css
index f49604e537807..e261339684efe 100644
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -25,6 +25,10 @@
   }
 }

+:root[customtitlebar] {
+  background-color: transparent;
+}
+
 @media (-moz-windows-accent-color-in-titlebar) or (-moz-windows-mica) {
   :root[customtitlebar] {
     @media (-moz-windows-mica) {

Yeah, confirmed Comment 11 caused the rendering problem.

Assignee: sotaro.ikeda.g → nobody
Flags: needinfo?(emilio)
Summary: With mica enabled, repeatedly manually terminating the gpu process will cause the whole UI to freeze/disappear → Window transparency doesn't work with gpu process disabled (which causes issues when mica is enabled and the gpu process dies repeatedly)

So AIUI, this is because we're using the transparency code in InProcessWinCompositorWidget, which draws to a memory DC, but we're not using the memory DC thing in here, because we're not using the fallback renderer (I think?).

But avoiding the whole memory DC stuff and drawing directly to the window DC seems to work just fine (tried early-returning in InProcessWinCompositorWindow::UpdateTransparency). Chris, you seem the most familiar with this, do you have the context for what the InProcessWinCompositorWidget is trying to do with transparency?

Flags: needinfo?(emilio) → needinfo?(cmartin)

With the following prefs, save window rendering to png files. With the patch, rendering to window seemed to work as expected.

  • pref gfx.webrender.software = true
  • gfx.webrender.software.d3d11 = false
  • layers.gpu-process.enabled = false

Change Change TransparencyModeIs() as to TransparencyMode::Transparent check return false.
With the change, I see UI rendering.

Even when gpu process is enabled, the following pref change caused the problem.

  • pref gfx.webrender.dcomp-win.enabled = false

The change disables DirectComposition usage. And RenderCompositorANGLE does swap chain present to windows. And the problem happened with mica. When RenderCompositorANGLE::ShouldUseAlpha() returned false, ui was rendered as expected.

By the way, with the following pref change, WebRender does swap chain present with DirectComposition. In this case, UI was rendered as expected.

  • pref gfx.webrender.compositor = false

Chris, you seem the most familiar with this, do you have the context for what the InProcessWinCompositorWidget is trying to do with transparency?

Hey Emilio,

It's possible that we've completely changed the way this works by now, but it used to be that when we are drawing with the GDI and we need alpha blending we would create the window as a Layered Window by adding the WS_EX_LAYERED window style to it.

When you do that, you stop receiving WM_PAINT messages and you're expected to render to an in-memory DC and call UpdateLayeredWindow to actually define the window pixels.

It's possible that it might incidentally work to draw directly to the DC of a layered window, but AFAIK the behavior is unspecified by Microsoft and not guaranteed to work.

I believe that the use-cases for these transparent windows have really decreased over the years -- They may not be used for anything anymore! They used to be used for rendering XUL Panel controls, for example. This was the cause of Bug 1604412 all those years ago, where the Hamburger Menu disappeared when the GPU sandbox was enabled due to it using XULPanel.

If the backend that's being used to draw the window no longer uses the StartRemoteDrawing() and EndRemoteDrawing() calls, it's possible that this window doesn't need to be transparent (in the sense of being a layered window). It would be interesting to see if things work if you simply set the window to TransparencyMode::Opaque.

EDIT: nsMenuPopupFrame seems to be the code we have that still uses window transparency, and it looks like it is only used by the SWGL backend.

Flags: needinfo?(cmartin)

Ah, yeah, so... For toplevel transparent windows (e.g. if you enable widget.windows.mica=true, but also if you use something like comment 11) we no longer use WS_EX_LAYERED (see the IsPopup() here). That seems to work for DCOMP, see bug 1911763 and company.

We do have existing transparent windows that don't rely on these tho, like the nonnative notifications (alerts.useSystemBackend=false).

So then... Does that mean that the problem is that you're using the SWGL backend but without the WS_EX_LAYERED style? If so, that would mean that UpdateLayeredWindow (which the SWGL backend uses) wouldn't do anything. It would also explain why you're saying that it works fine if you just render directly with the window DC.

We do have existing transparent windows that don't rely on these tho, like the nonnative notifications (alerts.useSystemBackend=false).

I wonder if we accomplish that using Direct2D? IIUC with a lot of the newer GFX apis, there's really no need for this "layered window" stuff anymore, and a window can support transparency directly via its swapchain. TBH I'm not really sure in what circumstances we still fall back to the SWGL path.

So, it looks like overall the issue is that this patch created a mismatch between WinCompositorWidget::mTransparencyMode and WS_EX_LAYERED. Previously, all the code in InProcessWinCompositorWidget assumed that mTransparencyMode == TransparencyMode::Transparent always implied WS_EX_LAYERED. But now, that's not true for anything but WindowType::Popup.

That patch (correctly) fixed the code in RemoteBackbuffer.cpp to ignore mTransparencyMode and only consider whether or not the window is layered or not. I think the fix would be to have InProcessWinCompositorWidget basically do the same thing.

As I'm saying this, I'm actually realizing that there's probably not any point anymore to even passing mTransparencyMode to the CompositorWidgetDelegate anymore -- Unless I'm missing something, it serves no purpose other than to act as a proxy for layering (which - as you know - can just be determined using GetWindowLongPtr()).

If you don't think you'll have time to work on this soon, I can make a patch for it?

Flags: needinfo?(emilio.alvarez96)
Assignee: nobody → emilio
Status: NEW → ASSIGNED

(In reply to Chris Martin [:cmartin] from comment #20)

So then... Does that mean that the problem is that you're using the SWGL backend but without the WS_EX_LAYERED style? If so, that would mean that UpdateLayeredWindow (which the SWGL backend uses) wouldn't do anything. It would also explain why you're saying that it works fine if you just render directly with the window DC.

Yeah that is correct. Indeed, if I go to https://www.bennish.net/web-notifications.html with gfx.webrender.dcomp-win.enabled=false and alerts.useSystemBackend=false the window doesn't show at all.

I wonder if we accomplish that using Direct2D? IIUC with a lot of the newer GFX apis, there's really no need for this "layered window" stuff anymore, and a window can support transparency directly via its swapchain. TBH I'm not really sure in what circumstances we still fall back to the SWGL path.

RenderCompositorANGLE does add an alpha swapchain. I figured out some of the bits here, I think, see above.

Flags: needinfo?(emilio.alvarez96)
Pushed by ealvarez@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/6de850359c38 Fix window transparency in some configurations. r=cmartin,win-reviewers
Blocks: 1945221
Status: ASSIGNED → RESOLVED
Closed: 12 days ago
Resolution: --- → FIXED
Target Milestone: --- → 136 Branch
Flags: qe-verify+

I've reproduced this issue by opening and reloading the site https://en.wikipedia.org/wiki/Barack_Obama for a couple of times. The prefs widget.windows.mica and layers.gpu-process.enabled were set to false on Win 11 on an affected Nightly build (2025-01-23).

The issue is verified as fixed on the latest Beta 136.0b3 build, under Win 11.

Status: RESOLVED → VERIFIED
Flags: qe-verify+
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: