<!--
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 Occlusion Query Conformance 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>
</head>
<body>
<div id="description"></div>
<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
<div id="console"></div>
<script>
"use strict";
description("This test verifies the functionality of occlusion query objects.");

debug("");

var tests = [];
var currentTest;
var currentTestIndex = 0;
var numberOfTestAttempts = 4; // Just to stress implementations a bit more.
var query;
var numberOfCompletionAttempts = 0;

function setupTests(gl) {
    tests = [
        {
            target: gl.ANY_SAMPLES_PASSED_CONSERVATIVE,
            name:   "ANY_SAMPLES_PASSED_CONSERVATIVE",
            result: 1,
        },
        {
            target: gl.ANY_SAMPLES_PASSED,
            name:   "ANY_SAMPLES_PASSED",
            result: 1,
        },
    ];
}

function runOcclusionQueryTest() {
    currentTest = tests[currentTestIndex];

    debug("");
    debug("Testing completion and behavior of " + currentTest.name + " occlusion query");
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    var program = wtu.setupSimpleColorProgram(gl, 0);
    gl.uniform4f(gl.getUniformLocation(program, "u_color"), 0, 1, 0, 1);
    wtu.setupUnitQuad(gl, 0);
    query = gl.createQuery();
    var target = currentTest.target;
    gl.beginQuery(target, query);
    wtu.drawUnitQuad(gl);
    gl.endQuery(target);

    // Verify as best as possible that the implementation doesn't
    // allow a query's result to become available the same frame, by
    // spin-looping for some time and ensuring that none of the
    // queries' results become available.
    var numEarlyTests = 20000;
    while (--numEarlyTests > 0) {
        gl.finish();
        if (gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE)) {
            testFailed("Query's result became available too early");
            finishTest();
            return;
        }
    }

    testPassed("Query's result didn't become available too early");
    numberOfCompletionAttempts = 0;
    requestAnimationFrame(completeOcclusionQueryTest);
}

function completeOcclusionQueryTest() {
    ++numberOfCompletionAttempts;

    if (numberOfCompletionAttempts > 500) {
        testFailed("Query didn't become available in a reasonable time");
        finishTest();
        return;
    }

    if (!gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE)) {
        requestAnimationFrame(completeOcclusionQueryTest);
        return;
    }

    // No matter whether the test was run with ANY_SAMPLES_PASSED or
    // ANY_SAMPLES_PASSED_CONSERVATIVE, the query object should always
    // report a non-zero result.
    var result = gl.getQueryParameter(query, gl.QUERY_RESULT);
    if (result == currentTest.result) {
        testPassed("Occlusion query " + currentTest.name + " returned a correct result (" + result + ")");
    } else {
        testFailed("Occlusion query " + currentTest.name + " returned an incorrect result " + result + " (expected " + currentTest.result + ")");
    }

    gl.deleteQuery(query);
    query = null;

    ++currentTestIndex;
    if (currentTestIndex >= tests.length) {
        --numberOfTestAttempts;
        if (numberOfTestAttempts == 0) {
            finishTest();
        } else {
            currentTestIndex = 0;
            requestAnimationFrame(runOcclusionQueryTest);
        }
    } else {
        requestAnimationFrame(runOcclusionQueryTest);
    }
}

var wtu = WebGLTestUtils;
var canvas = document.getElementById("canvas");
var gl = wtu.create3DContext(canvas, null, 2);

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

    setupTests(gl);
    runOcclusionQueryTest();
}
</script>
</body>
</html>
