summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/switching-objects.html
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/switching-objects.html231
1 files changed, 231 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/switching-objects.html b/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/switching-objects.html
new file mode 100644
index 0000000000..fce82dd21f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/switching-objects.html
@@ -0,0 +1,231 @@
+<!--
+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>Switching transform feedback objects</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 float in_value;
+out float out_value1;
+out float out_value2;
+
+void main() {
+ out_value1 = in_value * 2.;
+ out_value2 = in_value * 4.;
+}
+</script>
+<script id="fshader" type="x-shader/x-fragment">#version 300 es
+precision mediump float;
+out vec4 dummy;
+void main() {
+ dummy = vec4(0.);
+}
+</script>
+<script>
+"use strict";
+description("Tests switching transform feedback objects.");
+
+debug("<h3>Setup</h3>")
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, null, 2);
+if (!gl) {
+ testFailed("WebGL context does not exist");
+}
+
+// Setup
+const prog_interleaved = wtu.setupTransformFeedbackProgram(gl, ["vshader", "fshader"],
+ ["out_value1", "out_value2"], gl.INTERLEAVED_ATTRIBS,
+ ["in_value"]);
+const prog_no_varyings = wtu.setupTransformFeedbackProgram(gl, ["vshader", "fshader"],
+ [], gl.INTERLEAVED_ATTRIBS,
+ ["in_value"]);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "shader compilation");
+const vertexBuffer = createBuffer(gl, new Float32Array([1, 2, 3, 4]));
+gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+gl.enableVertexAttribArray(0);
+gl.vertexAttribPointer(0, 1, gl.FLOAT, false, 0, 0);
+gl.useProgram(prog_interleaved);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "vertex buffer and program setup");
+
+const tf1 = gl.createTransformFeedback();
+const tf2 = gl.createTransformFeedback();
+const tfBuffer1 = createBuffer(gl, new Float32Array([0, 0]));
+const tfBuffer2 = createBuffer(gl, new Float32Array([0, 0]));
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf1);
+gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer1);
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf2);
+gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer2);
+const expected_tf_output = [2, 4];
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "TF object setup");
+
+debug("<h3>Baseline transform feedback success case</h3>");
+
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf1);
+gl.beginTransformFeedback(gl.POINTS);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "begin TF");
+gl.drawArrays(gl.POINTS, 0, 1);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "draw");
+gl.endTransformFeedback();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "end TF");
+
+gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer1);
+wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, expected_tf_output);
+
+debug("<h3>Generic binding is not changed when switching TF object</h3>");
+
+// According to the GL ES spec historically, TRANSFORM_FEEDBACK_BUFFER_BINDING is listed as part
+// of the transform feedback object state. However, many drivers treat it as global context state
+// and not part of the tranform feedback object, which means that it does not change when
+// bindTransformFeedback is called. Khronos has resolved to change the spec to specify the latter
+// behavior: https://gitlab.khronos.org/opengl/API/issues/66 (Khronos private link). This tests
+// for the new behavior.
+
+// Set each buffer to contain its buffer number. We use this to check which
+// buffer is *really* bound at the driver level by reading the buffer contents.
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
+gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer1);
+gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, new Float32Array([1]), gl.STREAM_READ);
+gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer2);
+gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, new Float32Array([2]), gl.STREAM_READ);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "bufferData");
+
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf1);
+checkParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, tfBuffer2);
+checkIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, tfBuffer1);
+wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, [2]);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readback");
+
+gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, null);
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf2);
+checkParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, null);
+checkIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, tfBuffer2);
+
+debug("<h3>Error switching TF object while TF is enabled</h3>");
+
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf1);
+gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer1);
+gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, new Float32Array([0, 0]), gl.STREAM_READ);
+gl.beginTransformFeedback(gl.POINTS);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "begin");
+checkParameter(gl.TRANSFORM_FEEDBACK_BINDING, tf1);
+
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf2);
+wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "bind while unpaused");
+
+// Check that nothing actually changed and rendering still works
+checkParameter(gl.TRANSFORM_FEEDBACK_BINDING, tf1);
+gl.drawArrays(gl.POINTS, 0, 1);
+gl.endTransformFeedback();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "transform feedback should complete successfully");
+wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, expected_tf_output);
+
+
+debug("<h3>Successfully switching TF object while TF is paused</h3>");
+
+gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer1);
+gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, new Float32Array([0, 0]), gl.STREAM_READ);
+gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer2);
+gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, new Float32Array([0, 0]), gl.STREAM_READ);
+
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf2);
+gl.beginTransformFeedback(gl.POINTS);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "begin on tf2");
+checkParameter(gl.TRANSFORM_FEEDBACK_BINDING, tf2);
+
+gl.pauseTransformFeedback();
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf1);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "bind while paused");
+gl.beginTransformFeedback(gl.POINTS);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "begin on tf1");
+checkParameter(gl.TRANSFORM_FEEDBACK_BINDING, tf1);
+gl.drawArrays(gl.POINTS, 0, 1);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "draw should succeed");
+gl.endTransformFeedback();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "end on tf1");
+gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer1);
+wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, expected_tf_output);
+
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf2);
+gl.endTransformFeedback();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "end on tf2");
+
+debug("<h3>Misc. invalid operations</h3>")
+
+gl.endTransformFeedback();
+wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "endTransformFeedback before begin");
+gl.pauseTransformFeedback();
+wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "pauseTransformFeedback when not active");
+gl.resumeTransformFeedback();
+wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "pauseTransformFeedback when not active");
+
+gl.beginTransformFeedback(gl.POINTS);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "transform feedback should begin successfully");
+gl.drawArrays(gl.TRIANGLE_STRIP, 0, 1);
+wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "wrong primitive mode");
+gl.useProgram(prog_no_varyings);
+wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "switch program while active");
+gl.resumeTransformFeedback();
+wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "resumeTransformFeedback when not paused");
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf2);
+wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "bindTransformFeedback when active");
+gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer2);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "bindBuffer(TRANSFORM_FEEDBACK_BUFFER) when active");
+gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer2);
+wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "bindBufferBase(TRANSFORM_FEEDBACK_BUFFER) when active");
+
+gl.pauseTransformFeedback();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "pause");
+gl.pauseTransformFeedback();
+wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "already paused");
+gl.endTransformFeedback();
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "end while paused");
+
+finishTest();
+
+// Helper functions
+function createBuffer(gl, dataOrSize) {
+ const buf = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
+ gl.bufferData(gl.ARRAY_BUFFER, dataOrSize, gl.STATIC_DRAW);
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
+ return buf;
+}
+
+function checkParameter(param, expected) {
+ const value = gl.getParameter(param);
+ if (value != expected) {
+ testFailed(wtu.glEnumToString(gl, param) + " was " + value + ", but expected " + expected);
+ } else {
+ testPassed(wtu.glEnumToString(gl, param) + " was " + value + ", matching expected " + expected);
+ }
+}
+
+function checkIndexedParameter(param, index, expected) {
+ const value = gl.getIndexedParameter(param, index);
+ if (value != expected) {
+ testFailed(wtu.glEnumToString(gl, param) + "[" + index + "] was " + value + ", but expected " + expected);
+ } else {
+ testPassed(wtu.glEnumToString(gl, param) + "[" + index + "] was " + value + ", matching expected " + expected);
+ }
+}
+
+
+</script>
+
+</body>
+</html>