<!--
Copyright (c) 2019 The Khronos Group Inc.
Use of this source code is governed by an MIT-style license that can be
found in the LICENSE.txt file.
-->

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebGL Draw Buffers Driver Hang Conformance Test</title>
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
<script src="../../js/js-test-pre.js"></script>
<script src="../../js/webgl-test-utils.js"></script>
</head>
<body>
<div id="description"></div>
<canvas id="canvas" width="64" height="64"> </canvas>
<div id="console"></div>
<script id="vshader" type="x-shader/x-vertex">#version 300 es
in vec4 a_position;
void main() {
    gl_Position = a_position;
}
</script>
<script id="fshader" type="x-shader/x-fragment">#version 300 es
precision mediump float;

out vec4 my_FragColor;
void main() {
    my_FragColor = vec4(1, 0, 0, 1);
}
</script>
<script>
"use strict";
description("This is a regression test for a driver bug causing a hang in the driver and thereby the browser (crbug.com/696187).")

debug("Thanks to Andre Weissflog (@FlohOfWoe / @floooh) for this test.");
debug("If the bug exists, this test doesn't fail or time out per the harness; the browser basically hangs.");

var wtu = WebGLTestUtils;
var canvas = document.getElementById("canvas");
var gl = wtu.create3DContext(canvas, { depth: true, stencil: true, alpha: false }, 2);

if (!gl) {
  testFailed("WebGL context does not exist");
} else {
  testPassed("WebGL context exists");

  runTest();
}

function runTest() {
  // create a global VAO
  let vao = gl.createVertexArray();
  gl.bindVertexArray(vao);

  // create a 3 MSAA 'offscreen render targets', each consisting of:
  //  - 1 color texture which will hold the MSAA resolve result
  //  - 1 MSAA color renderbuffer
  // plus one depth-stencil renderbuffer
  let tex0 = gl.createTexture();
  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, tex0);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 0);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, 200, 200, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  let c_rb0 = gl.createRenderbuffer();
  gl.bindRenderbuffer(gl.RENDERBUFFER, c_rb0);
  gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, 200, 200);
  let ds_rb = gl.createRenderbuffer();
  gl.bindRenderbuffer(gl.RENDERBUFFER, ds_rb);
  gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.DEPTH24_STENCIL8, 200, 200);

  // 2nd offscreen render target
  let tex1 = gl.createTexture();
  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, tex1);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 0);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, 200, 200, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  let c_rb1 = gl.createRenderbuffer();
  gl.bindRenderbuffer(gl.RENDERBUFFER, c_rb1);
  gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, 200, 200);

  // 3rd offscreen render target
  let tex2 = gl.createTexture();
  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, tex2);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 0);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, 200, 200, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  let c_rb2 = gl.createRenderbuffer();
  gl.bindRenderbuffer(gl.RENDERBUFFER, c_rb2);
  gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, 200, 200);

  // an MRT framebuffer with the 3 MSAA renderbuffers and MSAA depth/stencil attachments
  let mrt_fb = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, mrt_fb);
  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, c_rb0);
  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.RENDERBUFFER, c_rb1);
  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT2, gl.RENDERBUFFER, c_rb2);
  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, ds_rb);
  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, ds_rb);
  gl.checkFramebufferStatus(gl.FRAMEBUFFER);

  // 3 'MSAA resolve framebuffers' which are the target for the MSAA-resolve-blit,
  // with the 3 color textures as color attachments
  let res_fb0 = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, res_fb0);
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex0, 0);
  gl.checkFramebufferStatus(gl.FRAMEBUFFER);
  let res_fb1 = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, res_fb1);
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, tex1, 0);
  gl.checkFramebufferStatus(gl.FRAMEBUFFER);
  let res_fb2 = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, res_fb2);
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT2, gl.TEXTURE_2D, tex2, 0);
  let frameNumber = 0;

  function draw() {
    // draw one frame
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    gl.viewport(0, 0, 1024, 768);

  //--- BEGIN: comment out the block begin BEGIN/END to make the demo run
    // clear the 3 MSAA offscreen color renderbuffers and depth/stencil renderbuffer
    gl.bindFramebuffer(gl.FRAMEBUFFER, mrt_fb);
    gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2]);
    gl.viewport(0, 0, 200, 200);
    gl.depthMask(true);
    gl.clearBufferfv(gl.COLOR, 0, [0.25,0.0,0.0,1.0]);
    gl.clearBufferfv(gl.COLOR, 1, [0.0,0.25,0.0,1.0]);
    gl.clearBufferfv(gl.COLOR, 2, [0.0,0.0,0.25,1.0]);
    gl.clearBufferfi(gl.DEPTH_STENCIL, 0, 1.0, 0);

    // the MSAA resolve operation
    gl.bindFramebuffer(gl.READ_FRAMEBUFFER, mrt_fb);
    gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, res_fb0);
    gl.readBuffer(gl.COLOR_ATTACHMENT0);
    gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
    gl.blitFramebuffer(0, 0, 200, 200, 0, 0, 200, 200, gl.COLOR_BUFFER_BIT, gl.NEAREST);
    gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, res_fb1);
    gl.readBuffer(gl.COLOR_ATTACHMENT1);
    gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
    gl.blitFramebuffer(0, 0, 200, 200, 0, 0, 200, 200, gl.COLOR_BUFFER_BIT, gl.NEAREST);
    gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, res_fb2);
    gl.readBuffer(gl.COLOR_ATTACHMENT2);
    gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
    gl.blitFramebuffer(0, 0, 200, 200, 0, 0, 200, 200, gl.COLOR_BUFFER_BIT, gl.NEAREST);
//--- END

    // bind and clear the default framebuffer
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    gl.viewport(0, 0, 1024, 768);
    gl.clearColor(0.5, 0.5, 0.5, 1.0);
    gl.clearDepth(1.0);
    gl.clearStencil(0);
    gl.clear(gl.COLOR_BUFFER_BIT|gl.STENCIL_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);

    if (++frameNumber < 10) {
      requestAnimationFrame(draw);
    } else {
      finishTest();
    }
  }

  // Start the rendering loop
  draw();
}

debug("");
var successfullyParsed = true;
</script>

</body>
</html>
