summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/transform_feedback.html
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/transform_feedback.html645
1 files changed, 645 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/transform_feedback.html b/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/transform_feedback.html
new file mode 100644
index 0000000000..20256c6ace
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/transform_feedback.html
@@ -0,0 +1,645 @@
+<!--
+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 Transform Feedback 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 id="vshader" type="x-shader/x-vertex">#version 300 es
+
+in vec4 in_data;
+out vec4 out_add;
+out vec4 out_mul;
+void main(void) {
+ out_add = in_data + vec4(2.0, 3.0, 4.0, 5.0);
+ out_mul = in_data * vec4(2.0, 3.0, 4.0, 5.0);
+}
+</script>
+<script id="fshader" type="x-shader/x-fragment">#version 300 es
+precision mediump float;
+out vec4 out_color;
+void main(void) {
+ out_color = vec4(1.0, 1.0, 1.0, 1.0);
+}
+</script>
+<script>
+"use strict";
+description("This test verifies the functionality of the Transform Feedback objects.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, null, 2);
+var tf = null;
+var tf1 = null;
+var buf = null;
+let out_add_buffer = null;
+var program = null;
+var activeInfo = null;
+var query = null;
+var numberOfQueryCompletionAttempts = 0;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ runBindingTest();
+ runTFBufferBindingTest();
+ runObjectTest();
+ runGetBufferSubDataTest();
+ runUnboundDeleteTest();
+ runBoundDeleteTest();
+ runOneOutputFeedbackTest();
+ // Must be the last test, since it's asynchronous and calls finishTest().
+ runTwoOutputFeedbackTest();
+}
+
+function runBindingTest() {
+ debug("");
+ debug("Testing binding enum");
+
+ shouldBe("gl.TRANSFORM_FEEDBACK_BINDING", "0x8E25");
+
+ gl.getParameter(gl.TRANSFORM_FEEDBACK_BINDING);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "TRANSFORM_FEEDBACK_BINDING query should succeed");
+
+ // Default value is null
+ shouldBe("gl.getParameter(gl.TRANSFORM_FEEDBACK_BINDING)", "null");
+
+ debug("Testing binding a Transform Feedback object");
+ tf = gl.createTransformFeedback();
+ tf1 = gl.createTransformFeedback();
+ shouldBeNull("gl.getParameter(gl.TRANSFORM_FEEDBACK_BINDING)");
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ shouldBe("gl.getParameter(gl.TRANSFORM_FEEDBACK_BINDING)", "tf");
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf1);
+ shouldBe("gl.getParameter(gl.TRANSFORM_FEEDBACK_BINDING)", "tf1");
+ gl.deleteTransformFeedback(tf);
+ gl.deleteTransformFeedback(tf1);
+ shouldBeNull("gl.getParameter(gl.TRANSFORM_FEEDBACK_BINDING)");
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "binding a deleted Transform Feedback object");
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
+ shouldBeNull("gl.getParameter(gl.TRANSFORM_FEEDBACK_BINDING)");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function runTFBufferBindingTest() {
+ debug("");
+ debug("Testing binding and unbinding transform feedback objects and buffers");
+
+ buf = gl.createBuffer();
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, buf);
+ gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 16, gl.STATIC_DRAW);
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, null);
+
+ tf = gl.createTransformFeedback();
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, buf);
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
+
+ // gl.TRANSFORM_FEEDBACK_BUFFER is part of Transform Feedback objects'
+ // state. See OpenGL ES 3.0.5 Section 6.24.
+ //
+ // Since the TRANSFORM_FEEDBACK was just unbound, there should be nothing
+ // bound.
+ shouldBeNull('gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)');
+
+ // Binding the buffer to the ARRAY_BUFFER binding point should succeed.
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "binding buffer to ARRAY_BUFFER");
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
+ gl.deleteBuffer(buf);
+ buf = null;
+ gl.deleteTransformFeedback(tf);
+ tf = null;
+}
+
+function runObjectTest() {
+ debug("");
+ debug("Testing object creation");
+
+ tf = gl.createTransformFeedback();
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "createTransformFeedback should not set an error");
+ shouldBeNonNull("tf");
+
+ // Expect false if never bound
+ shouldBeFalse("gl.isTransformFeedback(tf)");
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ shouldBeTrue("gl.isTransformFeedback(tf)");
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
+ shouldBeTrue("gl.isTransformFeedback(tf)");
+ gl.deleteTransformFeedback(tf);
+ shouldBeFalse("gl.isTransformFeedback(tf)");
+
+ shouldBeFalse("gl.isTransformFeedback(null)");
+
+ tf = null;
+}
+
+function runOneOutputFeedbackTest() {
+ debug("");
+ debug("Testing one-output transform feedback");
+
+ // Build the input and output buffers
+ var in_data = [
+ 1.0, 2.0, 3.0, 4.0,
+ 2.0, 4.0, 8.0, 16.0,
+ 0.75, 0.5, 0.25, 0.0
+ ];
+
+ var in_buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, in_buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(in_data), gl.STATIC_DRAW);
+
+ out_add_buffer = gl.createBuffer();
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_add_buffer);
+ gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, Float32Array.BYTES_PER_ELEMENT * in_data.length, gl.STATIC_DRAW);
+
+ // Create the transform feedback shader
+ program = wtu.setupTransformFeedbackProgram(gl, ["vshader", "fshader"],
+ ["out_add"], gl.SEPARATE_ATTRIBS,
+ ["in_data"]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "linking transform feedback shader should not set an error");
+ shouldBeNonNull("program");
+
+ // Draw the the transform feedback buffers
+ tf = gl.createTransformFeedback();
+
+ gl.enableVertexAttribArray(0);
+ gl.bindBuffer(gl.ARRAY_BUFFER, in_buffer);
+ gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 16, 0);
+
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, out_add_buffer);
+
+ gl.enable(gl.RASTERIZER_DISCARD);
+ gl.beginTransformFeedback(gl.POINTS);
+
+ debug("Testing switching program while transform feedback is active");
+ gl.pauseTransformFeedback();
+ var program2 = wtu.setupSimpleColorProgram(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Switching program while transform feedback is active and paused should succeed");
+ gl.useProgram(program);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Switching program while transform feedback is active and paused should succeed");
+ gl.resumeTransformFeedback();
+ gl.useProgram(program2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Switching program while transform feedback is active should fail");
+ shouldBe("gl.getParameter(gl.CURRENT_PROGRAM)", "program");
+
+ debug("Testing deleting an active transform feedback object");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors before testing deletion");
+ gl.deleteTransformFeedback(tf);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Deleting the transform feedback while active should fail, and have no effect");
+ shouldBe("gl.isTransformFeedback(tf)", "true");
+ debug("Resuming testing of single-output transform feedback");
+
+ gl.drawArrays(gl.POINTS, 0, 3);
+
+ gl.endTransformFeedback();
+ gl.disable(gl.RASTERIZER_DISCARD);
+
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null);
+
+ // Verify the output buffer contents
+ var add_expected = [
+ 3.0, 5.0, 7.0, 9.0,
+ 4.0, 7.0, 12.0, 21.0,
+ 2.75, 3.5, 4.25, 5.0
+ ];
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_add_buffer);
+ wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, add_expected);
+
+ gl.deleteBuffer(in_buffer);
+ gl.deleteBuffer(out_add_buffer);
+ gl.deleteProgram(program);
+ gl.deleteTransformFeedback(tf);
+
+ tf = null;
+ program = null;
+}
+
+function runTwoOutputFeedbackTest() {
+ debug("");
+ debug("Testing two-output transform feedback");
+
+ // Build the input and output buffers
+ var in_data = [
+ 1.0, 2.0, 3.0, 4.0,
+ 2.0, 4.0, 8.0, 16.0,
+ 0.75, 0.5, 0.25, 0.0
+ ];
+
+ var in_buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, in_buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(in_data), gl.STATIC_DRAW);
+
+ out_add_buffer = gl.createBuffer();
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_add_buffer);
+ gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, Float32Array.BYTES_PER_ELEMENT * in_data.length, gl.STATIC_DRAW);
+
+ var out_mul_buffer = gl.createBuffer();
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_mul_buffer);
+ gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, Float32Array.BYTES_PER_ELEMENT * in_data.length, gl.STATIC_DRAW);
+
+ // Create the transform feedback shader
+ program = wtu.setupTransformFeedbackProgram(gl, ["vshader", "fshader"],
+ ["out_add", "out_mul"], gl.SEPARATE_ATTRIBS,
+ ["in_data"]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "linking transform feedback shader should not set an error");
+ shouldBeNonNull("program");
+
+ // Create a query object to check the number of primitives written
+ query = gl.createQuery();
+
+ // Draw the the transform feedback buffers
+ tf = gl.createTransformFeedback();
+
+ gl.enableVertexAttribArray(0);
+ gl.bindBuffer(gl.ARRAY_BUFFER, in_buffer);
+ gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 16, 0);
+
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, out_add_buffer);
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 1, out_mul_buffer);
+
+ gl.enable(gl.RASTERIZER_DISCARD);
+ gl.beginTransformFeedback(gl.POINTS);
+ gl.beginQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query);
+
+ gl.drawArrays(gl.POINTS, 0, 3);
+
+ gl.endQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
+ gl.endTransformFeedback();
+ gl.disable(gl.RASTERIZER_DISCARD);
+
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null);
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 1, null);
+
+ // Verify the output buffer contents
+ var add_expected = [
+ 3.0, 5.0, 7.0, 9.0,
+ 4.0, 7.0, 12.0, 21.0,
+ 2.75, 3.5, 4.25, 5.0
+ ];
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_add_buffer);
+ wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, add_expected);
+
+ var mul_expected = [
+ 2.0, 6.0, 12.0, 20.0,
+ 4.0, 12.0, 32.0, 80.0,
+ 1.5, 1.5, 1.0, 0.0
+ ];
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_mul_buffer);
+ wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, mul_expected);
+
+ gl.deleteBuffer(in_buffer);
+ gl.deleteBuffer(out_add_buffer);
+ gl.deleteBuffer(out_mul_buffer);
+ gl.deleteProgram(program);
+ gl.deleteTransformFeedback(tf);
+
+ tf = null;
+ program = null;
+
+ // Check the result of the query. It should not be available yet.
+ // This constant was chosen arbitrarily to take around 1 second on
+ // one WebGL implementation on one desktop operating system. (Busy-
+ // loops based on calling Date.now() have been found unreliable.)
+ var numEarlyTests = 50000;
+ while (--numEarlyTests > 0) {
+ gl.finish();
+ if (gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE)) {
+ testFailed("Query's result became available too early");
+ finishTest();
+ return;
+ }
+ }
+ testPassed("TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query's result didn't become available too early");
+
+ // Complete the rest of the test asynchronously.
+ requestAnimationFrame(completeTransformFeedbackQueryTest);
+}
+
+function runUnboundDeleteTest() {
+ debug("");
+ debug("Testing deleting buffers attached to an unbound transform feedback object");
+
+ // Theoretically it would be possible to verify the result of performing
+ // transform feedback into a deleted buffer object. The buffer would have to
+ // be latched into a VAO as well as into the transform feedback object. In
+ // order to get the results out of the output buffer, it would be necessary
+ // to run transform feedback again, reading from the buffer bound to the
+ // VAO, and writing into a (non-deleted) buffer object latched into the
+ // transform feedback object. It's not possible to arrange things to be able
+ // to copyBufferSubData from the deleted buffer object into a temporary one
+ // for readback.
+
+ // This would be a lot of code to test an unlikely corner case, so instead,
+ // this test verifies simpler behaviors.
+
+ out_add_buffer = gl.createBuffer();
+ const output_buffer_length = Float32Array.BYTES_PER_ELEMENT * 16;
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_add_buffer);
+ gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, output_buffer_length, gl.STATIC_DRAW);
+
+ // Set up the transform feedback object
+ tf = gl.createTransformFeedback();
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, out_add_buffer);
+
+ // Unbind transform feedback and delete out_add_buffer.
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
+ gl.deleteBuffer(out_add_buffer);
+ debug("isBuffer should report false after deletion");
+ shouldBe("gl.isBuffer(out_add_buffer)", "false");
+
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ debug("Transform feedback object should keep output buffer alive");
+ shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)", "out_add_buffer");
+ // Deleting the buffer again while the transform feedback is bound shouldn't unbind it.
+ gl.deleteBuffer(out_add_buffer);
+ debug("Deleting output buffer again should be a no-op");
+ shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)", "out_add_buffer");
+
+ // Try unbinding and rebinding the transform feedback object just
+ // to make sure that has no effect on the attached output buffer.
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ debug("Transform feedback object should still keep output buffer alive");
+ shouldBe("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)", "out_add_buffer");
+
+ gl.deleteTransformFeedback(tf);
+
+ tf = null;
+ out_add_buffer = null;
+}
+
+function runBoundDeleteTest() {
+ debug("");
+ debug("Testing deleting buffers attached to a bound transform feedback object");
+
+ out_add_buffer = gl.createBuffer();
+ const output_buffer_length = Float32Array.BYTES_PER_ELEMENT * 16;
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_add_buffer);
+ gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, output_buffer_length, gl.STATIC_DRAW);
+
+ // Set up the transform feedback object
+ tf = gl.createTransformFeedback();
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, out_add_buffer);
+
+ // Delete the output buffer
+ gl.deleteBuffer(out_add_buffer);
+
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ debug("Buffer should have been unbound from active transform feedback");
+ shouldBeNull("gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)");
+
+ gl.deleteTransformFeedback(tf);
+
+ tf = null;
+ out_add_buffer = null;
+}
+
+var retArray;
+
+function verifyGetBufferSubData(expected) {
+ wtu.shouldGenerateGLError(gl, expected, "gl.getBufferSubData(gl.TRANSFORM_FEEDBACK_BUFFER, 0, retArray, 0, retArray.length)");
+}
+
+function runGetBufferSubDataTest() {
+ debug("");
+ debug("Test that getBufferSubData...");
+
+ // Build the input and output buffers
+ var in_data = [
+ 1.0, 2.0, 3.0, 4.0,
+ 2.0, 4.0, 8.0, 16.0,
+ 0.75, 0.5, 0.25, 0.0
+ ];
+
+ retArray = new Float32Array(in_data.length);
+
+ var in_buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, in_buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(in_data), gl.STATIC_DRAW);
+
+ out_add_buffer = gl.createBuffer();
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_add_buffer);
+ gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, Float32Array.BYTES_PER_ELEMENT * in_data.length, gl.STATIC_DRAW);
+
+ // Create the transform feedback shader
+ program = wtu.setupTransformFeedbackProgram(gl, ["vshader", "fshader"],
+ ["out_add"], gl.SEPARATE_ATTRIBS,
+ ["in_data"]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "linking transform feedback shader should not set an error");
+ shouldBeNonNull("program");
+
+ // Draw the the transform feedback buffers
+ tf = gl.createTransformFeedback();
+
+ gl.enableVertexAttribArray(0);
+ gl.bindBuffer(gl.ARRAY_BUFFER, in_buffer);
+ gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 16, 0);
+
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
+
+ debug("... passes when a transform feedback object is not bound");
+ verifyGetBufferSubData(gl.NO_ERROR);
+
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, out_add_buffer);
+
+ debug("... passes when a transform feedback object is bound but not active");
+ verifyGetBufferSubData(gl.NO_ERROR);
+
+ gl.enable(gl.RASTERIZER_DISCARD);
+ gl.beginTransformFeedback(gl.POINTS);
+
+ debug("... fails when a transform feedback object is active");
+ verifyGetBufferSubData(gl.INVALID_OPERATION);
+
+ gl.drawArrays(gl.POINTS, 0, 3);
+
+ gl.endTransformFeedback();
+ gl.disable(gl.RASTERIZER_DISCARD);
+
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null);
+
+ // Verify the output buffer contents
+ var add_expected = [
+ 3.0, 5.0, 7.0, 9.0,
+ 4.0, 7.0, 12.0, 21.0,
+ 2.75, 3.5, 4.25, 5.0
+ ];
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_add_buffer);
+ wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, add_expected);
+
+ tf = null;
+ program = null;
+}
+
+function completeTransformFeedbackQueryTest() {
+ debug("");
+ debug("Testing TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query");
+
+ ++numberOfQueryCompletionAttempts;
+ if (numberOfQueryCompletionAttempts > 500) {
+ testFailed("Query didn't become available in a reasonable time");
+ finishTest();
+ return;
+ }
+
+ if (!gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE)) {
+ requestAnimationFrame(completeTransformFeedbackQueryTest);
+ return;
+ }
+
+ var result = gl.getQueryParameter(query, gl.QUERY_RESULT);
+ if (result == 3) {
+ testPassed("TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query returned a correct result (3)");
+ } else {
+ testFailed("TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query returned an incorrect result " + result + " (expected 3)");
+ }
+
+ runVaryingsTest();
+}
+
+function verifyTransformFeedbackVarying(prog, index, valid, name) {
+ activeInfo = gl.getTransformFeedbackVarying(prog, index);
+ if (valid) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR,
+ "Should be no errors from valid getTransformFeedbackVarying.");
+ shouldBeNonNull("activeInfo");
+ shouldBe("activeInfo.name", "'" + name + "'");
+ shouldBe("activeInfo.type", "gl.FLOAT_VEC4");
+ shouldBe("activeInfo.size", "1");
+ } else {
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE,
+ "Should be INVALID_VALUE when calling getTransformFeedbackVarying with an invalid index.");
+ shouldBeNull("activeInfo");
+ }
+}
+
+function runVaryingsTest() {
+ debug("");
+ debug("Testing transform feedback varyings");
+
+ // Create the transform feedback shader. This is explicitly run after runTwoOutputFeedbackTest,
+ // as re-linking the shader here will test browser caching.
+ program = wtu.setupTransformFeedbackProgram(gl, ["vshader", "fshader"],
+ ["out_add", "out_mul"], gl.SEPARATE_ATTRIBS,
+ ["in_data"]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "linking transform feedback shader should not set an error");
+ shouldBeNonNull("program");
+
+ // Check the varyings
+ shouldBe("gl.getProgramParameter(program, gl.TRANSFORM_FEEDBACK_VARYINGS)", "2");
+ verifyTransformFeedbackVarying(program, 0, true, "out_add");
+ verifyTransformFeedbackVarying(program, 1, true, "out_mul");
+ verifyTransformFeedbackVarying(program, 2, false);
+
+ // transformFeedbackVaryings() doesn't take effect until a successful link.
+ gl.transformFeedbackVaryings(program, ["out_mul"], gl.SEPARATE_ATTRIBS);
+ shouldBe("gl.getProgramParameter(program, gl.TRANSFORM_FEEDBACK_VARYINGS)", "2");
+ verifyTransformFeedbackVarying(program, 0, true, "out_add");
+ verifyTransformFeedbackVarying(program, 1, true, "out_mul");
+ verifyTransformFeedbackVarying(program, 2, false);
+
+ // Now relink.
+ gl.linkProgram(program);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "linking transform feedback shader should not set an error");
+ shouldBeTrue("gl.getProgramParameter(program, gl.LINK_STATUS)");
+ shouldBe("gl.getProgramParameter(program, gl.TRANSFORM_FEEDBACK_VARYINGS)", "1");
+ verifyTransformFeedbackVarying(program, 0, true, "out_mul");
+ verifyTransformFeedbackVarying(program, 1, false);
+ verifyTransformFeedbackVarying(program, 2, false);
+
+ // Test recompiling/relinking the program
+ // Regression test for http://crbug.com/716018
+ var skipCompileStatus = true;
+ program = wtu.setupTransformFeedbackProgram(gl, ["vshader", "fshader"],
+ ["out_add", "out_mul"], gl.SEPARATE_ATTRIBS,
+ ["in_data"], undefined, undefined, skipCompileStatus);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "linking transform feedback shader should not set an error");
+ shouldBeTrue("gl.getProgramParameter(program, gl.LINK_STATUS)");
+ shouldBe("gl.getProgramParameter(program, gl.TRANSFORM_FEEDBACK_VARYINGS)", "2");
+ verifyTransformFeedbackVarying(program, 0, true, "out_add");
+ verifyTransformFeedbackVarying(program, 1, true, "out_mul");
+ verifyTransformFeedbackVarying(program, 2, false);
+
+ runContextLostOneOutputFeedbackTest();
+}
+
+function runContextLostOneOutputFeedbackTest() {
+ var ext = gl.getExtension("WEBGL_lose_context");
+ if (!ext) {
+ debug("No WEBGL_lose_context support");
+ finishTest();
+ return;
+ }
+ debug("");
+ debug("Testing switching program after context lost while transform feedback is active");
+
+ var in_buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, in_buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(12), gl.STATIC_DRAW);
+
+ out_add_buffer = gl.createBuffer();
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, out_add_buffer);
+ gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, Float32Array.BYTES_PER_ELEMENT * 12, gl.STATIC_DRAW);
+
+ // Create an extra program to try switching to
+ var program2 = wtu.setupSimpleColorProgram(gl);
+
+ // Create the transform feedback shader
+ program = wtu.setupTransformFeedbackProgram(gl, ["vshader", "fshader"],
+ ["out_add"], gl.SEPARATE_ATTRIBS,
+ ["in_data"]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "linking transform feedback shader should not set an error");
+ shouldBeNonNull("program");
+
+ // Draw the the transform feedback buffers
+ tf = gl.createTransformFeedback();
+
+ gl.enableVertexAttribArray(0);
+ gl.bindBuffer(gl.ARRAY_BUFFER, in_buffer);
+ gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 16, 0);
+
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, out_add_buffer);
+
+ gl.beginTransformFeedback(gl.POINTS);
+
+ debug("Calling loseContext()");
+ ext.loseContext();
+ shouldBeTrue("gl.isContextLost()");
+ shouldBe("gl.getError()", "gl.CONTEXT_LOST_WEBGL");
+ shouldBe("gl.getError()", "gl.NO_ERROR");
+ debug("Trying to switch program");
+ gl.useProgram(program2);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No transform feedback error generated on lost context");
+ finishTest();
+}
+
+debug("");
+</script>
+
+</body>
+</html>