chromiumembedded / cef

Chromium Embedded Framework (CEF). A simple framework for embedding Chromium-based browsers in other applications.
https://bitbucket.org/chromiumembedded/cef/
Other
3.24k stars 455 forks source link

OSR: Invalidate does not generate frame after hiding/showing browser #2483

Closed magreenblatt closed 2 years ago

magreenblatt commented 6 years ago

Original report by me.


What steps will reproduce the problem?

Run ceftests.exe --gtest_filter=OSRTest.NavigateWhileHidden

What is the expected output? What do you see instead?

The test should succeed. Instead, the test fails because OnPaint() is not called after OnNavigate() despite the call to Invalidate():

    // Show the browser.
    status_ = SHOW;
    GetBrowser()->GetHost()->WasHidden(false);

    // Force a call to OnPaint.
    GetBrowser()->GetHost()->Invalidate(PET_VIEW);

What version of the product are you using? On what operating system?

Chromium version 70.0.3507.0 (#578961) on Windows 10.

The problem does not reproduce with older versions. The problem does not reproduce with software rendering (add --disable-gpu to the ceftests command-line).

Related graphics-dev thread: https://groups.google.com/a/chromium.org/d/msg/graphics-dev/9C1NF43aPa8/Qv0jyzDACQAJ

magreenblatt commented 5 years ago

Original comment by Matt Gajownik (Bitbucket: WizardCM, GitHub: WizardCM).


Just wanted to document this for posterity:

Ran across a manifestation of this bug in OBS Studio v24 RC1, which we built with 75.0.3770.100, but also saw it with 73.0.3683.75 (these were the builds I had on hand). Might help in troubleshooting.

Weirdly, it primarily happened when we had >5 browsers loaded. Any less, and the issue was far less prevalent (near non-existent).

Our solution for the moment was to remove the WasHidden(true) and WasHidden(false), but that’s a temporary fix at best.

Source: https://github.com/obsproject/obs-browser/blob/master/obs-browser-source.cpp#L318-L328

Edit: Bummer, this also disables the ability for webpages to use the Page Visibility API. Hmm.

Edit 2: Hugh (the other commenter) also tested with Spotify’s 3809 build and says the issue persists in that build too.

magreenblatt commented 5 years ago

Original comment by Hugh Bailey (Bitbucket: jp9000, GitHub: jp9000).


OBS Studio is getting this with the latest spotify builds as of this writing, and it happens with both software rendering and hardware accelerated rendering OSR. We were still on 3440 and decided to upgrade, and noticed this started happening. If we have enough browsers active at once, then we use WasHidden(true) to hide them, and then later use WasHidden(false) and Invalidate(PET_VIEW) to show them, the sources will no longer render. Again, both hardware/software rendering, and again it seems to only happen when there’s a lot of browsers active at once.

Just putting this here to make note of this behavior. We have a pretty solid reproducible scene collection file that exhibits this behavior. This behavior does not occur on the prior 3440 build.

magreenblatt commented 5 years ago

Original comment by elad bahar (Bitbucket: eBahar).


did you try calling WasResized() before calling WasHidden(false)?

magreenblatt commented 5 years ago

Original comment by Hugh Bailey (Bitbucket: jp9000, GitHub: jp9000).


Interesting, that does appear to get a frame again, but only the last frame before the first WasHidden(true) call, and only in conjunction with external_begin_frame_enabled/SendExternalBeginFrame() usage. In other words, the browsers do render, but they are frozen and do not render any new frames, just the last frame before the WasHidden(true) call.

If external_begin_frame_enabled/SendExternalBeginFrame() is not used and windowless_frame_rate is set, then there is no change and they do not render anything.

But it did have an effect at least, even if not the desired effect yet.

magreenblatt commented 5 years ago

Original comment by elad bahar (Bitbucket: eBahar).


Are you using shared texture OSR path?

magreenblatt commented 5 years ago

Original comment by Hugh Bailey (Bitbucket: jp9000, GitHub: jp9000).


I made an error in my last post -- WasResized() has no effect. Sorry, my code changed recently so I was confused about the behavior I was seeing. Let me try this again a bit more thoroughly and properly tested. This is all with OSR. I'm unsure if this happens when not using OSR, but I don't really have an easy way to test that at the moment.

Calling WasHidden(true), then calling WasHidden(false) (with or without the Invalidate(PET_VIEW) call) on a whole bunch of OSR browsers at once causes all those browsers to stop rendering until fully recreated. It does not matter if software rendering (OnPaint()) or hardware (shared_texture_enabled/OnAcceleratedPaint()) rendering is used, both exhibit the same exact behavior.

The only different behavior I've seen is if external_begin_frame_enabled/SendExternalBeginFrame() is used, versus if it's off with a constant framerate with windowless_frame_rate. If it is used, the last frame will render from before the first hide, otherwise the browsers will be blank. That behavior was not caused by WasResized(); that has no effect. It was just caused by external_begin_frame_enabled/SendExternalBeginFrame(). And again, same exact behavior regardless of software/hardware rendering.

magreenblatt commented 5 years ago

Do you start receiving OnPaint calls again if you resize the browser (call WasResized and return modified dimensions in GetViewRect)?

magreenblatt commented 5 years ago

Original comment by Hugh Bailey (Bitbucket: jp9000, GitHub: jp9000).


Interesting, I should have realized that you must have switched to use a size change check in CEF now that you have no return boolean. If I use different dimension and then use WasResized(), they start rendering again. Apologies to @{557058:6a93a677-f796-4161-93d5-37463172e888} – I should have checked that. This works on both shared texture OSR and software rendered OSR.

magreenblatt commented 5 years ago

Original comment by Alex Maitland (Bitbucket: a-maitland).


Resizing the browser by 1px smaller, then resizing it back to it's original size is the workaround we've implemented in CefSharp. Ignoring the frames until the resize has complete.

This proved to be much more difficult than I had originally hoped, the problem being resizing the browser in rapid succession in combination with a WasHidden call, it's fairly easy to trigger a breakpoint/assertion in Chromium. Think users switching between tabs in rapid succession.

I believe Chromium is going to remove the breakpoint/assertion. For reference the issue was raised at https://bugs.chromium.org/p/chromium/issues/detail?id=983862#c15 (wasn't raised by me obviously)

Adding as reference for anyone else attempting a workaround.

I was hoping the changes to support the Viz Compositor would resolve this issue, unfortunately OSR Rendering is broken in entirely different ways.

magreenblatt commented 5 years ago

Original comment by Hugh Bailey (Bitbucket: jp9000, GitHub: jp9000).


We simulate the javascript visibility API rather than resize. That breakpoint is a bit annoying. We stop calling WasHidden at all and instead execute the javascript to simulate it. Seems to produce the same effect, relatively.

magreenblatt commented 4 years ago

Original comment by Alex Maitland (Bitbucket: a-maitland).


@{557058:2f2a2aee-b500-4023-9734-037e9897c3ab} Whilst you are busy fixing #2733/viz-osr-might-be-causing-some-graphic I was wondering if you had any further insight into this particular issue?

magreenblatt commented 4 years ago

I believe this is resolved by the above PR. If not, we can re-open.

magreenblatt commented 4 years ago

Original comment by Alex Maitland (Bitbucket: a-maitland).


Unfortunately I can reproduce this with 80.0.4+g74f7b0c+chromium-80.0.3987.122 with gpu enabled on Win 10 x64 1903

Please let me know if you require any further information.

magreenblatt commented 4 years ago

Original comment by Dara Hak (Bitbucket: dara, GitHub: dara).


@{557058:5abcbcf9-b372-4ecb-830e-ddb451b76481} Any info or call stack with that crash? Do we know if it is related with what was done in https://chromium-review.googlesource.com/c/chromium/src/+/1792459 ?

magreenblatt commented 4 years ago

Original comment by Alex Maitland (Bitbucket: a-maitland).


There is no crash, the browser simply stops repainting.

magreenblatt commented 4 years ago

Original comment by Dara Hak (Bitbucket: dara, GitHub: dara).


@{557058:5abcbcf9-b372-4ecb-830e-ddb451b76481} Ah sorry, I mixed the original CEF issue with the Chromium crash. But the resizing workaround you talked about is still valid, right?

magreenblatt commented 4 years ago

Original comment by 牛叉 (Bitbucket: 牛叉).


FrameEvictionManager

// This class is responsible for globally managing which renderers keep their
// compositor frame when offscreen. We actively discard compositor frames for
// offscreen tabs, but keep a minimum amount, as an LRU cache, to make switching
// between a small set of tabs faster. The limit is a soft limit, because
// clients can lock their frame to prevent it from being discarded, e.g. if the
// tab is visible, or while capturing a screenshot.

magreenblatt commented 3 years ago

Original comment by Mathieu Lafon (Bitbucket: mlafon, GitHub: mlafon).


Is there any update or (usable) workaround on this issue, which seems important to me?

My issue is not related to Invalidate() but to the fact that the rendering can be blank after a WasHidden(false) call, once enough browser views have been created. This is surely related to the FrameEvictionManager as mentioned in the previous comment. When the frame has been evicted and shown again, OnPaint() is called but with a blank buffer (width*heigth*4 0xff bytes). I think this is what is discussed in that issue, tell me if there is a more appropriate issue or if a new one should be created.

Calling WasResized(), Invalidate() or NotifyScreenInfoChanged() before or after WasHidden() has no effect. The only way to show the view again is to resize it (with a different size) but this is not a usable workaround.

This issue can be somehow reproduced in cefclient:

@a-maitland, can you tell me where is your related workaround in CefSharp, I can’t find it.

magreenblatt commented 3 years ago

Original comment by Alex Maitland (Bitbucket: a-maitland).


The current CefSharp workaround is https://github.com/cefsharp/CefSharp/commit/9140c08a34e113b8865a80a7ac9f8b4aa19631c4

magreenblatt commented 2 years ago

Original comment by Mathieu Lafon (Bitbucket: mlafon, GitHub: mlafon).


I have a Pull request which fixes the empty-rendering issue after the view has been evicted and shown again. Implementing the InvalidateLocalSurfaceIdOnEviction callback fixes the issue.

I’m unsure if this is the same issue than the one initially reported but this is the issue discussed in the last messages since reopen.

https://bitbucket.org/chromiumembedded/cef/pull-requests/409/

magreenblatt commented 2 years ago

osr: Implement InvalidateLocalSurfaceIdOnEviction (fixes issue #2483)

This fixes an empty-rendering issue when the view is shown after being evicted.

→ <<cset 6dad2c45eebb (bb)>>

magreenblatt commented 2 years ago

osr: Implement InvalidateLocalSurfaceIdOnEviction (fixes issue #2483)

This fixes an empty-rendering issue when the view is shown after being evicted.

→ <<cset b156d790e35e (bb)>>

magreenblatt commented 1 year ago

Original comment by Michael Davies (Bitbucket: Michael Davies).


i find that it still happens in M87(4280). I have six osr window(display the same gif) in one process. I call WasHidden(true) and then call WasHidden(false), but only four of them behave normally. Other two stop refresh.

magreenblatt commented 1 year ago

Original comment by Valentin Wuppinger (Bitbucket: Valentin Wuppinger).


As mentioned by the previous comment, the issue still persists in a similar way, so I created a new issue for this #3427/osr-rendering-bug-when-minimizing-and

magreenblatt commented 5 years ago
magreenblatt commented 4 years ago
magreenblatt commented 4 years ago
magreenblatt commented 2 years ago