1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121

content / test / data / gpu / worker-webgl-raf-after-gpu-crash.html [blame]

<!DOCTYPE HTML>

<html>
<head>
<title>Worker requestAnimationFrame with WebGLcontext after GPU crash</title>

<script id="worker" type="text/worker">
self.onmessage = msg => {
  const canvas = msg.data.canvas;
  const gl = canvas.getContext('webgl');
  let restored = false;
  canvas.addEventListener('webglcontextlost', evt => {
    self.postMessage("context lost");
    // To allow restore event to be fired:
    evt.preventDefault();
  });
  canvas.addEventListener('webglcontextrestored', evt => {
    restored = true;
    self.postMessage("context restored");
  });
  self.postMessage("setup complete");

  function animate() {
    if (restored) {
      gl.clearColor(0, 1, 0, 1);
    } else {
      gl.clearColor(1, 0, 0, 1)
    }
    gl.clear(gl.COLOR_BUFFER_BIT);
    self.postMessage("animation frame");
    requestAnimationFrame(animate);
  }
  requestAnimationFrame(animate);
}
</script>

<script>
// Test that a WebGL rAF loop keeps running after recovering from a context loss.
// Test will timeout if animation fails to resume.

function UnexpectedMessage(state, msg) {
  console.log(`Unexpected message '${msg}' received while in state '${state}'`);
  window.domAutomationController.send('FAILED');
}

window.onload = () => {
  const worker_blob = new Blob([document.getElementById("worker").textContent]);
  const worker = new Worker(URL.createObjectURL(worker_blob));
  let state = "init";
  let frames_after_restore = 0;

  worker.onmessage = evt => {
    // Expected sequence (state: expected message):
    //
    // "init": expect to receive "setup complete" once
    // "ready": expect to receive "animation frame" x1 -> request gpu crash
    // "expecting crash": receive "animation frame" (any count), then "context lost" once
    // "expecting restore": receive "animation frame" (any count), then "context restored" once
    // "recover": receive 5+ "animation frame".

    switch(state) {
      case "init":
        if (evt.data == "setup complete") {
          state = "ready";
        } else {
          UnexpectedMessage(state, evt.data);
        }
        break;
      case "ready":
        if (evt.data == "animation frame") {
          state = "expecting crash";
          // send message that test is ready for GPU process crash
          window.domAutomationController.send('LOADED');
        } else {
          UnexpectedMessage(state, evt.data);
        }
        break;
      case "expecting crash":
        if (evt.data == "animation frame") {
          break;
        }
        if (evt.data == "context lost") {
          state = "expecting restore";
        } else {
          UnexpectedMessage(state, evt.data);
        }
        break;
      case "expecting restore":
        if (evt.data == "animation frame") {
          break;
        }
        if (evt.data == "context restored") {
          state = "recover";
        } else {
          UnexpectedMessage(state, evt.data);
        }
        break;
      case "recover":
        if (evt.data == "animation frame") {
          // Wait for enough frames to pass to ensure the pipeline
          // is not stalled.
          if (++frames_after_restore == 5)
            window.domAutomationController.send('SUCCESS');
        } else {
          UnexpectedMessage(state, evt.data);
        }
        break;
    }
  }
  let offscreen = document.getElementById('c').transferControlToOffscreen();
  worker.postMessage({
      canvas: offscreen
  }, [offscreen]);
}
</script>

</head>
<body>
<canvas id="c" width="300" height="300" class="nomargin" style="position:absolute; top:0px; left:0px;"></canvas>
</body>
</html>