<!--
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">
<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>
<script id="vshader" type="x-shader/x-vertex">
uniform mat4 transformMatrix;
uniform vec3 positionOffset;
attribute vec2 aPosition;
void main() {
  gl_Position = transformMatrix * vec4(aPosition, 0.0, 1.0) + vec4(positionOffset, 0.0);
}
</script>
<script id="fshader" type="x-shader/x-fragment">
void main() {
  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
</script>
<div id="description"></div>
<canvas id="canvas" width="256" height="256"></canvas>
<div id="console"></div>
<script>
"use strict";
enableJSTestPreVerboseLogging();
description("Test many draw calls and uniform updates per frame");

debug('Regression test for Chromium <a href="http://crbug.com/320724">Issue 320724</a> and <a href="http://crbug.com/322726">Issue 322726</a>');
debug('');

var contextWasLost = false;

var wtu = WebGLTestUtils;
var canvas = document.getElementById('canvas');
var gl = wtu.create3DContext(canvas);
canvas.addEventListener('webglcontextlost', function(event) { contextWasLost = true; }, false);
var program = wtu.setupProgram(gl, ["vshader", "fshader"], [ "aPosition" ]);
if (!program) {
  testFailed("failed to create test program");
}

gl.useProgram(program);
var vertexObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
gl.enableVertexAttribArray(0);

// Initialize vertices
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
   -1.0,  1.0,
    1.0, -1.0,
    1.0,  1.0,
   -1.0,  1.0,
   -1.0, -1.0,
    1.0, -1.0 ]), gl.STATIC_DRAW);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);

gl.clearColor(0.3, 0.3, 0.3, 1.0);

// Initialize uniforms
var transformLoc = gl.getUniformLocation(program, 'transformMatrix');
var offsetLoc = gl.getUniformLocation(program, 'positionOffset');

// This many draw calls appear to be necessary to trigger the original bug reliably.
var tilesPerSide = 100;
var numDrawsThisFrame = 0;

var doNextDraw = function() {
  // Sometimes, the original bug can't be caught cooperatively, and it
  // causes the entire tab to hang irrevocably.
  if (contextWasLost) {
    testFailed("WebGL context was lost while running the test");
    finishTest();
    return;
  }

  var totalDraws = tilesPerSide * tilesPerSide;
  if (numDrawsThisFrame >= totalDraws) {
    testPassed("All draw calls completed successfully");
    finishTest();
    return;
  }

  numDrawsThisFrame += tilesPerSide;

  gl.clear(gl.COLOR_BUFFER_BIT);

  var transformMatrix = new Float32Array(16);
  transformMatrix[15] = 1.0;
  var scaleFactor = 1.0 / tilesPerSide;
  transformMatrix[0] = scaleFactor;
  transformMatrix[5] = scaleFactor;
  transformMatrix[10] = scaleFactor;

  var offset = new Float32Array(3);

  var drawsDoneThisFrame = 0;
  for (var yy = 0; yy < tilesPerSide; ++yy) {
    for (var xx = 0; xx < tilesPerSide; ++xx) {
      if (drawsDoneThisFrame >= numDrawsThisFrame)
        break;

      gl.uniformMatrix4fv(transformLoc, false, transformMatrix);

      offset[0] = 2.0 * ((0.5 + xx) / tilesPerSide) - 1.0;
      offset[1] = 2.0 * ((0.5 + yy) / tilesPerSide) - 1.0;
      gl.uniform3f(offsetLoc, offset[0], offset[1], offset[2]);

      gl.drawArrays(gl.TRIANGLES, 0, 6);
      ++drawsDoneThisFrame;
    }

    if (drawsDoneThisFrame >= numDrawsThisFrame)
      break;
  }

  var iterations = numDrawsThisFrame / tilesPerSide;
  if (iterations % 10 === 0) {
    // Needed to avoid test timeout within the harness on some slower platforms
    testPassed("Completed " + iterations + " iterations");
  }

  wtu.requestAnimFrame(doNextDraw);
}

wtu.requestAnimFrame(doNextDraw);
var successfullyParsed = true;
</script>
</body>
</html>
