diff options
Diffstat (limited to '')
-rw-r--r-- | dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/switching-objects.html | 231 |
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> |