New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 895423 link

Starred by 1 user

Issue metadata

Status: Verified
Owner:
OOO until 2019-01-24
Closed: Oct 18
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Mac
Pri: 1
Type: Bug

Blocking:
issue 895528
issue 897140



Sign in to add a comment

Canvas sometimes freezes with requestAnimationFrame and setTimeout

Project Member Reported by hajimehoshi@chromium.org, Oct 15

Issue description

Chrome Version: Version 69.0.3497.100 (Official Build) (64-bit)
OS: macOS 10.14 Mojave

What steps will reproduce the problem?
(1) Open the below HTML

<!DOCTYPE html>                                                                                                                                                                                                                              

<canvas id="canvas" width="512" height="512"></canvas>
<script>
  window.addEventListener('load', () => {
    const canvas = document.getElementById('canvas');
    const gl = canvas.getContext('webgl');
    gl.viewport(0, 0, 512, 512);
    var i = 0;
    let f = () => {
      setTimeout(() => {
        i++
        const c = (i % 64) / 64
        gl.clearColor(c, c, c, 1);
        gl.clear(gl.COLOR_BUFFER_BIT);
        requestAnimationFrame(f);
      }, 0);
    };
    f();
  });
</script>

(2) Switch the desktops several times (this might require 10 or more switching to reproduce)

What is the expected result?
The canvas never stops updating.

What happens instead?
The canvas freezes. The JavaScript doesn't stop but only the rendering stops.

Without setTimeout, it looks like the canvas never freezes.


Please use labels and text to provide additional information.
On 10.13 High Sierra, probably I could not reproduce this.

If this is a regression (i.e., worked before), please consider using the
bisect tool (https://www.chromium.org/developers/bisect-builds-py) to help
us identify the root cause and more rapidly triage the issue.

For graphics-related bugs, please copy/paste the contents of the about:gpu
page at the end of this report.


 
Owner: kbr@chromium.org
Attached the profile when the canvas freezes.

JavaScript continues to run but frames are not updated.

profile.tar.gz
221 KB Download
profile.png
74.6 KB View Download
Cc: ccameron@chromium.org
Can reproduce on a dual-GPU MacBook Pro with AMD and Intel GPUs running 10.14 by putting one Chrome window with this test on one Space (via Mission Control), another Chrome window on another Space, and switching rapidly back and forth between the Spaces.

I was able to reproduce this (once, with more difficulty) on 10.13, so this is not an issue completely new to 10.14 and doesn't appear to be a new regression in Chrome - although I haven't tried searching back to see if this was working reliably at some point.

Submitter: how did you find this? Is real-world content affected by this? I wasn't able to reproduce this with either a sample using 2D canvas (freeze-canvas.html), or a WebGL sample that didn't include both setTimeout and requestAnimationFrame (freeze-webgl-no-settimeout.html). (All three variants, and about:gpu from the machine, are attached.) Most applications should be using solely requestAnimationFrame so it's not clear to me how widespread an issue this is and whether it warrants P1.

freeze-webgl.html
732 bytes View Download
freeze-canvas2d.html
735 bytes View Download
freeze-webgl-no-settimeout.html
705 bytes View Download
about-gpu.html
36.7 KB View Download
It's not DescheduleUntilFinishedCHROMIUM - that mechanism appears to be working correctly, and the command buffer seems to be getting rescheduled properly.

Setting a breakpoint in DevTools, and resuming, causes the canvas to start updating again correctly.

Cc: danakj@chromium.org enne@chromium.org fs...@chromium.org
Components: Blink>Canvas Internals>Compositing
Status: Started (was: Untriaged)
When this happens, DrawingBuffer::PrepareTransferableResource stops getting called, so the cc::TextureLayer containing the WebGL back buffer's texture stops asking for updates.

https://chromium-review.googlesource.com/1282225 adds some logging in this area. When the problem happens, this is the sequence of calls:

[1532:775:1015/165147.560038:ERROR:webgl_rendering_context_base.cc(1352)] WebGLRenderingContextBase::MarkContextChanged already-dirty early-out
[1532:775:1015/165147.560077:ERROR:webgl_rendering_context_base.cc(1375)] WebGLRenderingContextBase::MarkContextChanged full invalidation
[1532:775:1015/165147.560149:ERROR:webgl_rendering_context_base.cc(1404)] WebGLRenderingContextBase::FinalizeFrame
[1532:775:1015/165147.575550:ERROR:drawing_buffer.cc(309)] DrawingBuffer::PrepareTransferableResource
[1532:775:1015/165147.576259:ERROR:webgl_rendering_context_base.cc(1352)] WebGLRenderingContextBase::MarkContextChanged already-dirty early-out
[1532:775:1015/165147.576295:ERROR:webgl_rendering_context_base.cc(1375)] WebGLRenderingContextBase::MarkContextChanged full invalidation
[1532:775:1015/165147.576357:ERROR:webgl_rendering_context_base.cc(1404)] WebGLRenderingContextBase::FinalizeFrame
[1532:775:1015/165147.595715:ERROR:drawing_buffer.cc(309)] DrawingBuffer::PrepareTransferableResource
[1532:775:1015/165147.596544:ERROR:webgl_rendering_context_base.cc(1352)] WebGLRenderingContextBase::MarkContextChanged already-dirty early-out
[1532:775:1015/165147.596580:ERROR:webgl_rendering_context_base.cc(1375)] WebGLRenderingContextBase::MarkContextChanged full invalidation
[1532:775:1015/165147.596643:ERROR:webgl_rendering_context_base.cc(1404)] WebGLRenderingContextBase::FinalizeFrame
[1532:775:1015/165147.879562:ERROR:webgl_rendering_context_base.cc(1352)] WebGLRenderingContextBase::MarkContextChanged already-dirty early-out
[1532:775:1015/165147.893315:ERROR:webgl_rendering_context_base.cc(1352)] WebGLRenderingContextBase::MarkContextChanged already-dirty early-out
[1532:775:1015/165147.915791:ERROR:webgl_rendering_context_base.cc(1352)] WebGLRenderingContextBase::MarkContextChanged already-dirty early-out
[1532:775:1015/165147.932169:ERROR:webgl_rendering_context_base.cc(1352)] WebGLRenderingContextBase::MarkContextChanged already-dirty early-out
[1532:775:1015/165147.949040:ERROR:webgl_rendering_context_base.cc(1352)] WebGLRenderingContextBase::MarkContextChanged already-dirty early-out
[1532:775:1015/165147.966331:ERROR:webgl_rendering_context_base.cc(1352)] WebGLRenderingContextBase::MarkContextChanged already-dirty early-out
[1532:775:1015/165147.983216:ERROR:webgl_rendering_context_base.cc(1352)] WebGLRenderingContextBase::MarkContextChanged already-dirty early-out
...

Basically, one call to DrawingBuffer::PrepareTransferableResource is skipped, and this makes the WebGL context think that it never needs to notify the outside world again that it's produced a frame. The WebGL context attempts to optimize things so that back-to-back draw calls don't send dirty notifications all the way up the stack.

It looks like perhaps the contract is that if FinalizeFrame is called, the rendering context must assume that it must notify the outside world about future draw calls which have caused it to become dirty.

https://chromium-review.googlesource.com/1281963 up for review simplifying these dirty notifications and fixing the bug.

> Submitter: how did you find this? Is real-world content affected by this? 

I found this in my game with Go/Wasm + WebGL. Go/Wasm runtime uses setTimeout to emulate concurrency even if Go users don't want to do. A callback set at rAF is called via setTimeout since all callbacks are treated in a different special goroutine: https://golang.org/pkg/syscall/js/?GOOS=js&GOARCH=wasm#NewCallback

Thus I don't think it is a major problem so far in the real world, but this will be a serious problem when Go/Wasm game development gets more popular.

Thank you for taking a very quick look!
Project Member

Comment 9 by bugdroid1@chromium.org, Oct 17

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/a614021bc653b35bef12c80407b2c3b92dad3839

commit a614021bc653b35bef12c80407b2c3b92dad3839
Author: Kenneth Russell <kbr@chromium.org>
Date: Wed Oct 17 21:12:51 2018

Simplify WebGL dirty notifications.

The WebGL context attempts to optimize dirty notifications to the
canvas and compositor, but the logic was fragile if the compositor
skips a frame due to policy decisions. There were two almost-redundant
state variables governing this.

Remove animation_frame_in_progress_, and reuse marked_canvas_dirty_
for its purpose, clearing marked_canvas_dirty_ in FinalizeFrame.

Verified with the test case from the bug and switching spaces 30 times
on macOS Mojave.

Bug:  895423 
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I456194746a1d20f4f2874b13c6cf6ba54dcf4ea1
Reviewed-on: https://chromium-review.googlesource.com/c/1281963
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Kenneth Russell <kbr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#600553}
[modify] https://crrev.com/a614021bc653b35bef12c80407b2c3b92dad3839/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
[modify] https://crrev.com/a614021bc653b35bef12c80407b2c3b92dad3839/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h

Status: Fixed (was: Started)
This should be fixed by the CL above. I hope it doesn't result in performance regressions for OffscreenCanvas.

Labels: Needs-Feedback
Tried testing the issue on the build without fix #69.0.3497.100 using Mac OS 10.13.3 as the primary monitor and Ubuntu 17.10 as secondary monitor by following the below steps.

Steps:
=====
1.Launched chrome.
2.Copied the whole code snippet from comment#0(Step 1) and saved with ".html" extension.
3.Opened the HTML file and switched between the two desktops several times.
4.Unable to see the canvas getting frozen.

Attached screencast and file for reference.
@Kenneth Russell: Could you please review attached screencast and let us know if anything is being missed from our end and help us in verifying the fix on the latest M-72 build.
Thanks.!
895423.html
733 bytes View Download
895423.mp4
5.2 MB View Download
swarnasree.mukkala@: to reproduce the original bug you need to be running macOS 10.14, and create two Spaces (three-finger swipe up on trackpad). Put one browser window containing the test case on one screen and another browser window on the other. Then use two-finger swipe back and forth to switch between the two Spaces.

Blocking: 897140
Blocking: 895528
Project Member

Comment 15 by bugdroid1@chromium.org, Oct 30

Labels: merge-merged-3578
The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/b0d076ed460fc404ffbec486a01c0d5e535aea85

commit b0d076ed460fc404ffbec486a01c0d5e535aea85
Author: Kenneth Russell <kbr@chromium.org>
Date: Tue Oct 30 19:52:13 2018

Simplify WebGL dirty notifications.

The WebGL context attempts to optimize dirty notifications to the
canvas and compositor, but the logic was fragile if the compositor
skips a frame due to policy decisions. There were two almost-redundant
state variables governing this.

Remove animation_frame_in_progress_, and reuse marked_canvas_dirty_
for its purpose, clearing marked_canvas_dirty_ in FinalizeFrame.

Verified with the test case from the bug and switching spaces 30 times
on macOS Mojave.

TBR=kbr@chromium.org

(cherry picked from commit a614021bc653b35bef12c80407b2c3b92dad3839)

Bug:  895423 , 895528
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I456194746a1d20f4f2874b13c6cf6ba54dcf4ea1
Reviewed-on: https://chromium-review.googlesource.com/c/1281963
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Kenneth Russell <kbr@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#600553}
Reviewed-on: https://chromium-review.googlesource.com/c/1308666
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Cr-Commit-Position: refs/branch-heads/3578@{#414}
Cr-Branched-From: 4226ddf99103e493d7afb23a4c7902ee496108b6-refs/heads/master@{#599034}
[modify] https://crrev.com/b0d076ed460fc404ffbec486a01c0d5e535aea85/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
[modify] https://crrev.com/b0d076ed460fc404ffbec486a01c0d5e535aea85/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h

Labels: Merge-Merged-71-3578
The following revision refers to this bug: 
https://chromium.googlesource.com/chromium/src.git/+/b0d076ed460fc404ffbec486a01c0d5e535aea85

Commit: b0d076ed460fc404ffbec486a01c0d5e535aea85
Author: kbr@chromium.org
Commiter: kbr@chromium.org
Date: 2018-10-30 19:52:13 +0000 UTC

Simplify WebGL dirty notifications.

The WebGL context attempts to optimize dirty notifications to the
canvas and compositor, but the logic was fragile if the compositor
skips a frame due to policy decisions. There were two almost-redundant
state variables governing this.

Remove animation_frame_in_progress_, and reuse marked_canvas_dirty_
for its purpose, clearing marked_canvas_dirty_ in FinalizeFrame.

Verified with the test case from the bug and switching spaces 30 times
on macOS Mojave.

TBR=kbr@chromium.org

(cherry picked from commit a614021bc653b35bef12c80407b2c3b92dad3839)

Bug:  895423 , 895528
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I456194746a1d20f4f2874b13c6cf6ba54dcf4ea1
Reviewed-on: https://chromium-review.googlesource.com/c/1281963
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Kenneth Russell <kbr@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#600553}
Reviewed-on: https://chromium-review.googlesource.com/c/1308666
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Cr-Commit-Position: refs/branch-heads/3578@{#414}
Cr-Branched-From: 4226ddf99103e493d7afb23a4c7902ee496108b6-refs/heads/master@{#599034}
Tried testing the issue on reported chrome version #69.0.3497.100 using Mac 10.14 by following below steps, but could not reproduce the issue.
Note: Tried with freeze-canvas2d.html and  895423.html files.

Steps:
=====
1.Launched chrome.
2.Opened freeze-canvas2d.html on one Space, another Chrome window on another Space.
3.By using the two finger back and forth switched between the spaces rapidly, observed that the canvas did not freeze (tried more than 30 times by switching both desktops).

Attached screencast for reference.
@kenneth: As the issue is not getting reproduced from TE end, hence request you to help us in verifying the fix from your end.
Thanks.!
895423(1).mp4
7.1 MB View Download
Status: Verified (was: Fixed)
Verified fixed on 10.14 with 71.0.3578.30 (Official Build) beta (64-bit). Test case from c#0 above survives 30 desktop switches with this version, and froze within 5 iterations on 70.0.3538.77.

Sign in to add a comment