<!--

/*
** Copyright (c) 2016 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/

-->

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebGL Integer Cubemap Texture Specification Order Bug 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>
<canvas id="example" width="128" height="128"></canvas>
<div id="description"></div>
<div id="console"></div>
<script id="vs" type="x-shader/x-vertex">#version 300 es
  precision highp float;
  in vec4 a_position;
  void main(){
      gl_Position = a_position;
  }
</script>
<script id="fs" type="x-shader/x-fragment">#version 300 es
  precision highp float;
  // This program samples both textures at varying Lod and exposes
  // both of them, the regular on top, and the weird on the bottom.
  // On the NVIDIA driver the top is both green and red while the bottom
  // is only green. This is a driver bug because both textures should be
  // exactly the same.
  // I think that because of our level specification order weirdness, the
  // driver gets confused as to which levels are complete and thinks only
  // level 0 is complete. Then when sampling the texture it clamps the sampling
  // to only level 0, resulting in green for all Lod values.
  layout(location = 0) out vec4 fragColor;
  uniform highp isamplerCube texRegular;
  uniform highp isamplerCube texWeird;
  void main() {
      vec2 fragPos = gl_FragCoord.xy / vec2(128.0, 128.0);
      float lod = (fragPos.x - 0.5) * 10.0 + 0.5;

      ivec4 colorRegular = textureLod(texRegular, vec3(1.0, 0.0, 0.0), lod);
      ivec4 colorWeird = textureLod(texWeird, vec3(1.0, 0.0, 0.0), lod);

      if (fragPos.y > 0.51) {
          fragColor = vec4(vec2(colorRegular.rg), 0.0, 1.0);
      } else if (fragPos.y < 0.49){
          fragColor = vec4(vec2(colorWeird.rg), 0.0, 1.0);
      } else {
          fragColor = vec4(0.0, 0.0, 0.0, 1.0);
      }
  }
</script>
<script>
"use strict";

var wtu = WebGLTestUtils;

description("Test for a driver bug when specifying integer cubemaps in weird order");

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

function createTextureCube(layers, maxLevel) {
    var texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);

    layers.forEach(function(layer) {
        var level = layer.level;
        var face = layer.face;
        var color = layer.color;

        var levelSize = 1 << (maxLevel - level);

        var backingBuffer = new ArrayBuffer(levelSize * levelSize * 2);
        new Int16Array(backingBuffer).fill(color);
        gl.texImage2D(face + gl.TEXTURE_CUBE_MAP_POSITIVE_X, level, gl.RG8I, levelSize, levelSize, 0, gl.RG_INTEGER, gl.BYTE, new Int8Array(backingBuffer));
    });

    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST);
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

    return texture;
}

function test() {
    var kMaxLevel = 4;
    var kBlack = 0x0000;
    var kGreen = 0x7F00;
    var kRed = 0x007F;

    // Create two integer cubemaps with green on level 0 and red on the others.

    // The "regular" cube map is filled in a sensible manner.
    var regularLayers = [];
    for (var level = 0; level <= kMaxLevel; level ++) {
        for (var face = 0; face < 6; face ++) {
            if (level == 0) {
                regularLayers.push({level: level, face: face, color: kGreen});
            } else {
                regularLayers.push({level: level, face: face, color: kRed});
            }
        }
    }

    // The "weird" cube map has all its >= 1 levels filled, then the first level,
    // then the >= 1 levels again but for one face. This replicates what the
    // Chromium command buffer "cubemap completeness" workaround is doing.
    var weirdLayers = [];
    for (var level = 1; level <= kMaxLevel; level ++) {
        for (var face = 0; face < 5; face ++) {
            weirdLayers.push({level: level, face: face, color: kBlack});
        }
        weirdLayers.push({level: level, face: 5, color: kRed});
    }
    for (var level = 0; level <= kMaxLevel; level ++) {
        for (var face = 0; face < 6; face ++) {
            if (level == 0) {
                weirdLayers.push({level: level, face: face, color: kGreen});
            } else {
                if (face != 5) {
                    weirdLayers.push({level: level, face: face, color: kRed});
                }
            }
        }
    }

    var regularTex = createTextureCube(regularLayers, kMaxLevel);
    var weirdTex = createTextureCube(weirdLayers, kMaxLevel);

    // At this point both textures should be the same.

    var sampleProgram = wtu.setupProgram(gl, ["vs", "fs"], ["a_position"]);
    var regularLocation = gl.getUniformLocation(sampleProgram, "texRegular");
    var weirdLocation = gl.getUniformLocation(sampleProgram, "texWeird");

    wtu.setupQuad(gl, gl.getAttribLocation(sampleProgram, "a_position"));

    gl.clearColor(0.0, 0.0, 0.0, 0.0);

    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_CUBE_MAP, regularTex);
    gl.activeTexture(gl.TEXTURE0 + 1);
    gl.bindTexture(gl.TEXTURE_CUBE_MAP, weirdTex);

    gl.uniform1i(regularLocation, 0);
    gl.uniform1i(weirdLocation, 1);

    wtu.drawUnitQuad(gl);

    wtu.checkCanvasRect(gl, 96, 32, 1, 1, [255, 0, 0, 255], "should be green");
    wtu.checkCanvasRect(gl, 96, 96, 1, 1, [255, 0, 0, 255], "should be green");
    wtu.checkCanvasRect(gl, 32, 32, 1, 1, [0, 255, 0, 255], "should be red");
    wtu.checkCanvasRect(gl, 32, 96, 1, 1, [0, 255, 0, 255], "should be red");
}

test();

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

</body>
</html>
