<!--
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 BlitFramebuffer Stencil-only Tests</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>

<script id="vs" type="x-shader/x-vertex">#version 300 es
in vec4 position;
void main() {
  gl_Position = position;
}
</script>
<script id="fs" type="x-shader/x-fragment">#version 300 es
out mediump vec4 colorOut;
uniform mediump vec3 color;
void main() {
   colorOut = vec4(color, 1.0);
}
</script>

</head>
<body>
<canvas id="example" width="8" height="8"></canvas>
<div id="description"></div>
<div id="console"></div>

<script>
"use strict";

var wtu = WebGLTestUtils;
description("This test covers some edge cases of blitFramebuffer with stencil.");

var gl = wtu.create3DContext("example", undefined, 2);

var program, colorLoc;

function init_buffer(format) {
  var buf = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, buf)
  var tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 16, 16);
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
  var rbo = gl.createRenderbuffer();
  gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
  gl.renderbufferStorage(gl.RENDERBUFFER, format, 16, 16);
  gl.framebufferRenderbuffer(gl.FRAMEBUFFER,
      gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, rbo);

  gl.clearBufferfi(gl.DEPTH_STENCIL, 0, 1.0, 0);

  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after buffer init");
  shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');

  return { fbo: buf, color: tex, depthStencil: rbo };
}

var quadVB;

function drawQuad(depth) {
  if (!quadVB) {
    quadVB = gl.createBuffer()
  }

  var quadVerts = new Float32Array(3 * 6);
  quadVerts[0] = -1.0; quadVerts[1] =   1.0; quadVerts[2] = depth;
  quadVerts[3] = -1.0; quadVerts[4] =  -1.0; quadVerts[5] = depth;
  quadVerts[6] =  1.0; quadVerts[7] =  -1.0; quadVerts[8] = depth;
  quadVerts[9] = -1.0; quadVerts[10] =  1.0; quadVerts[11] = depth;
  quadVerts[12] = 1.0; quadVerts[13] = -1.0; quadVerts[14] = depth;
  quadVerts[15] = 1.0; quadVerts[16] =  1.0; quadVerts[17] = depth;

  gl.bindBuffer(gl.ARRAY_BUFFER, quadVB);
  gl.bufferData(gl.ARRAY_BUFFER, quadVerts, gl.STATIC_DRAW);
  gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 0, 0);
  gl.enableVertexAttribArray(0);
  gl.drawArrays(gl.TRIANGLES, 0, 6);

  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after drawQuad");
}

// Test based on dEQP-GLES3.functional.blit.depth_stencil.depth_24_stencil8_stencil_only
function test_stencil_only_blit(format) {
  debug("testing format: " + wtu.glEnumToString(gl, format))

  var src = init_buffer(format);
  var dest = init_buffer(format);

  gl.bindFramebuffer(gl.FRAMEBUFFER, src.fbo);
  gl.viewport(0, 0, 16, 16);

  // Fill source with red, depth = 0.5, stencil = 7
  gl.enable(gl.DEPTH_TEST);
  gl.enable(gl.STENCIL_TEST);
  gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
  gl.stencilFunc(gl.ALWAYS, 7, 0xFF);
  gl.uniform3f(colorLoc, 1.0, 0.0, 0.0);
  drawQuad(0.5);

  // Fill dest with yellow, depth = 0.0, stencil = 1
  gl.bindFramebuffer(gl.FRAMEBUFFER, dest.fbo);
  gl.stencilFunc(gl.ALWAYS, 1, 0xff);
  gl.uniform3f(colorLoc, 1.0, 1.0, 0.0);
  drawQuad(0.0);

  // Perform copy.
  gl.bindFramebuffer(gl.READ_FRAMEBUFFER, src.fbo);
  gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, dest.fbo);
  gl.blitFramebuffer(0, 0, 16, 16, 0, 0, 16, 16, gl.STENCIL_BUFFER_BIT, gl.NEAREST);

  // Render blue where depth < 0, decrement on depth failure.
  gl.bindFramebuffer(gl.FRAMEBUFFER, dest.fbo);
  gl.stencilOp(gl.KEEP, gl.DECR, gl.KEEP);
  gl.stencilFunc(gl.ALWAYS, 0, 0xff);

  gl.uniform3f(colorLoc, 0.0, 0.0, 1.0);
  drawQuad(0.0);

  // Render green where stencil == 6.
  gl.disable(gl.DEPTH_TEST);
  gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
  gl.stencilFunc(gl.EQUAL, 6, 0xff);

  gl.uniform3f(colorLoc, 0.0, 1.0, 0.0);
  drawQuad(0.0);

  wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after test");
  wtu.checkCanvasRect(gl, 0, 0, 16, 16, [0, 255, 0, 255],
                      "stencil test should be green");

  gl.deleteFramebuffer(src.fbo);
  gl.deleteFramebuffer(dest.fbo);
  gl.deleteTexture(src.color);
  gl.deleteTexture(dest.color);
  gl.deleteRenderbuffer(src.depthStencil);
  gl.deleteRenderbuffer(dest.depthStencil);
}

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

    program = wtu.setupProgram(gl, ["vs", "fs"], ["position"]);
    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after program initialization");
    shouldBe('gl.getProgramParameter(program, gl.LINK_STATUS)', 'true');

    colorLoc = gl.getUniformLocation(program, "color")
    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "query uniform location");
    shouldBeNonNull('colorLoc')

    test_stencil_only_blit(gl.DEPTH24_STENCIL8);
    test_stencil_only_blit(gl.DEPTH32F_STENCIL8);
}

var successfullyParsed = true;
</script>
<script src="../../js/js-test-post.js"></script>

</body>
</html>
