summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/simultaneous_binding.html
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/simultaneous_binding.html')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/simultaneous_binding.html330
1 files changed, 330 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/simultaneous_binding.html b/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/simultaneous_binding.html
new file mode 100644
index 0000000000..228b4ab5cf
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/conformance2/transform_feedback/simultaneous_binding.html
@@ -0,0 +1,330 @@
+<!--
+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>Simultaneous binding</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;
+in float in_value2;
+out float out_value;
+
+void main() {
+ out_value = in_value * 2.;
+}
+</script>
+<script id="fshader" type="x-shader/x-fragment">#version 300 es
+precision mediump float;
+out vec4 dummy;
+uniform UniformBlock {
+ float fragment_value;
+};
+void main() {
+ dummy = vec4(fragment_value);
+}
+</script>
+<script>
+"use strict";
+description("This test verifies that access to a buffer simultaneously bound to a transform feedback object and a non-transform-feedback binding point is forbidden.");
+
+debug("");
+
+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");
+}
+
+function drawWithFeedbackBound(gl, drawFunction, prog, vao, tf, enableFeedback) {
+ gl.useProgram(prog);
+ gl.bindVertexArray(vao);
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ if (enableFeedback) gl.beginTransformFeedback(gl.POINTS);
+ let error = gl.getError();
+ if (error != gl.NO_ERROR) testFailed("Unexpected error before drawing: " + error)
+ drawFunction();
+ if (enableFeedback) gl.endTransformFeedback();
+ gl.bindVertexArray(null);
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
+}
+
+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 createVAO(gl, vertexBuffer, vertexBuffer2, indexBuffer) {
+ const vao = gl.createVertexArray();
+ gl.bindVertexArray(vao);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 1, gl.FLOAT, false, 0, 0);
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer2);
+ gl.enableVertexAttribArray(1);
+ gl.vertexAttribPointer(1, 1, gl.FLOAT, false, 0, 0);
+ gl.vertexAttribDivisor(1, 2);
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
+ gl.bindVertexArray(null);
+ return vao;
+}
+
+const prog = wtu.setupTransformFeedbackProgram(gl, ["vshader", "fshader"],
+ ["out_value"], gl.SEPARATE_ATTRIBS,
+ ["in_value", "in_value2"]);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "linking transform feedback shader should not set an error");
+
+const vertexBuffer = createBuffer(gl, new Float32Array([1, 2, 3, 4]));
+const vertexBuffer2 = createBuffer(gl, new Float32Array([1, 2, 3, 4]));
+const vertexBuffer3 = createBuffer(gl, new Float32Array([1, 2, 3, 4]));
+
+const indexBuffer = gl.createBuffer();
+gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Int16Array([0, 1, 2, 3]), gl.STATIC_DRAW);
+
+const tfBuffer = createBuffer(gl, new Float32Array([0, 0, 0, 0]));
+
+const vao = createVAO(gl, vertexBuffer, vertexBuffer2, indexBuffer);
+// This tests that having a transform feedback buffer bound in an unbound VAO
+// does not affect anything.
+const unboundVao = createVAO(gl, tfBuffer, tfBuffer, indexBuffer);
+
+const tf = gl.createTransformFeedback();
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+gl.useProgram(prog);
+gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer);
+// this binds the default (id = 0) TRANSFORM_FEEBACK buffer
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
+
+const uniformBuffer = createBuffer(gl, new Float32Array([1, 0, 0, 0]));
+const ubi = gl.getUniformBlockIndex(prog, "UniformBlock");
+gl.uniformBlockBinding(prog, ubi, 0);
+gl.bindBufferBase(gl.UNIFORM_BUFFER, 0, uniformBuffer);
+
+const drawFunctions = [
+ [
+ ()=>gl.drawArrays(gl.POINTS, 0, 4),
+ ()=>gl.drawElements(gl.POINTS, 4, gl.UNSIGNED_SHORT, 0),
+ ],
+ [
+ ()=>gl.drawArraysInstanced(gl.POINTS, 0, 4, 1),
+ ()=>gl.drawElementsInstanced(gl.POINTS, 4, gl.UNSIGNED_SHORT, 0, 1),
+ ],
+ [
+ ()=>gl.drawArrays(gl.POINTS, 0, 4),
+ ()=>gl.drawRangeElements(gl.POINTS, 0, 3, 4, gl.UNSIGNED_SHORT, 0),
+ ],
+ ];
+
+for (let [drawArrays, drawElements] of drawFunctions) {
+ debug("<h3>With draw functions " + drawArrays + " and " + drawElements + "</h3>");
+ debug("<hr/>Test baseline");
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer);
+ gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 16, gl.STATIC_DRAW);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "bufferData to TRANSFORM_FEEDBACK_BUFFER");
+ drawWithFeedbackBound(gl, drawElements, prog, vao, tf, false);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElements should be successful");
+ drawWithFeedbackBound(gl, drawArrays, prog, vao, tf, true);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "transform feedback should be successful");
+
+ const expected = [2, 4, 6, 8];
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer);
+ wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, expected);
+
+ debug("<hr/>Test generic bind point set to null");
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, null);
+ drawWithFeedbackBound(gl, drawElements, prog, vao, tf, false);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElements should be successful");
+ drawWithFeedbackBound(gl, drawArrays, prog, vao, tf, true);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "transform feedback should be successful");
+
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer);
+ wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, expected);
+
+ debug("<hr/>Test generic bind point set to vertex buffer");
+ // The TRANSFORM_FEEDBACK_BUFFER generic binding point is not part of the
+ // transform feedback object and not written to by transform feedback. Only
+ // the indexed binding points are written to. So it should be legal to draw
+ // from a buffer bound to the generic binding point.
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, vertexBuffer);
+ drawWithFeedbackBound(gl, drawElements, prog, vao, tf, false);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElements should be successful");
+ drawWithFeedbackBound(gl, drawArrays, prog, vao, tf, true);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "transform feedback should be successful");
+
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer);
+ wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, expected);
+
+ debug("<hr/>Test ARRAY_BUFFER");
+ // this should fail because the transform feedback's buffer #0 and the
+ // badVao's buffer #0 are the same buffer
+ const badVao = createVAO(gl, tfBuffer, vertexBuffer2, indexBuffer);
+ drawWithFeedbackBound(gl, drawArrays, prog, badVao, tf, false);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArrays: buffer used as vertex attrib and tf simultaneously");
+ drawWithFeedbackBound(gl, drawElements, prog, badVao, tf, false);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElements: buffer used as vertex attrib and tf simultaneously");
+ drawWithFeedbackBound(gl, drawArrays, prog, badVao, tf, true);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "buffer used as vertex attrib and tf simultaneously");
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer);
+ wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, expected, "should be the same as before as nothing has executed");
+
+ debug("<hr/>Test UNIFORM_BUFFER");
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, 0, tfBuffer);
+ gl.bindBuffer(gl.UNIFORM_BUFFER, null); // tfBuffer is still bound at index 0
+ drawWithFeedbackBound(gl, drawArrays, prog, vao, tf, false);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawArrays: buffer used as uniform buffer and tf simultaneously");
+ drawWithFeedbackBound(gl, drawElements, prog, vao, tf, false);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "drawElements: buffer used as uniform buffer and tf simultaneously");
+ drawWithFeedbackBound(gl, drawArrays, prog, vao, tf, true);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "buffer used as uniform buffer and tf simultaneously");
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, 0, uniformBuffer);
+ drawWithFeedbackBound(gl, drawArrays, prog, vao, tf, false);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays: tf buffer not used as uniform buffer anymore");
+ drawWithFeedbackBound(gl, drawElements, prog, vao, tf, false);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElements: tf buffer not used as uniform buffer anymore");
+ drawWithFeedbackBound(gl, drawArrays, prog, vao, tf, true);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "tf buffer not used as uniform buffer anymore");
+
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ const tfBuffer2 = createBuffer(gl, Float32Array.BYTES_PER_ELEMENT * 4);
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer2);
+ drawWithFeedbackBound(gl, drawArrays, prog, badVao, tf);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "buffer is no longer bound for transform feedback");
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer);
+
+ debug("<hr/>Test TF buffer bound to target unused by draw");
+ // Even if the TF buffer is bound to a target that's not used by the draw, it's
+ // still an error.
+ gl.bindBuffer(gl.COPY_READ_BUFFER, tfBuffer);
+ drawWithFeedbackBound(gl, drawArrays, prog, vao, tf, true);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "tf enabled");
+ drawWithFeedbackBound(gl, drawArrays, prog, vao, tf, false);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArrays: tf disabled");
+ drawWithFeedbackBound(gl, drawElements, prog, vao, tf, false);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElements: tf disabled");
+ gl.bindBuffer(gl.COPY_READ_BUFFER, null);
+
+ debug("<hr/>Test TF buffer bound to disabled vertex attrib");
+ // Having a TF buffer bound to a disabled vertex attrib should not be an error
+ // when TF is not enabled, because the buffer is not used.
+ gl.bindVertexArray(vao);
+ gl.bindBuffer(gl.ARRAY_BUFFER, tfBuffer);
+ gl.vertexAttribPointer(2, 1, gl.FLOAT, false, 0, 0);
+ gl.disableVertexAttribArray(2);
+ gl.bindVertexArray(null);
+ drawWithFeedbackBound(gl, drawArrays, prog, vao, tf, false);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "tf disabled, draw should succeed");
+ drawWithFeedbackBound(gl, drawElements, prog, vao, tf, false);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "tf disabled, draw should succeed");
+ // Remove the TF buffer binding from the VAO after the test.
+ gl.bindVertexArray(vao);
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer3);
+ gl.vertexAttribPointer(2, 1, gl.FLOAT, false, 0, 0);
+ gl.disableVertexAttribArray(2);
+ gl.bindVertexArray(null);
+}
+
+debug("<h1>Non-drawing tests</h1>");
+
+debug("<hr/>Test bufferData");
+
+gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer);
+gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 16, gl.STATIC_DRAW);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "bufferData to TRANSFORM_FEEDBACK_BUFFER");
+gl.bindBuffer(gl.COPY_WRITE_BUFFER, tfBuffer);
+gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 16, gl.STATIC_DRAW);
+wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "bufferData with double bound buffer");
+gl.bindBuffer(gl.COPY_WRITE_BUFFER, null);
+
+// The value of the TRANSFORM_FEEDBACK_BUFFER generic bind point should not
+// affect the legality of any operation.
+let genericBindPointValues = [()=>null, ()=>tfBuffer, ()=>vertexBuffer];
+
+for (let genericBindPointValue of genericBindPointValues) {
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
+ debug("<h3>With TRANSFORM_FEEDBACK_BUFFER generic bind point value " + genericBindPointValue + "</h3>");
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, genericBindPointValue());
+
+ debug("<hr/>Test PIXEL_UNPACK_BUFFER");
+ const tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, vertexBuffer);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "PIXEL_UNPACK_BUFFER is not bound for transform feedback");
+
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, tfBuffer);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "PIXEL_UNPACK_BUFFER is bound for transform feedback");
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
+
+ debug("<hr/>Test PIXEL_PACK_BUFFER");
+ gl.bindBuffer(gl.PIXEL_PACK_BUFFER, vertexBuffer);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "PIXEL_PACK_BUFFER is not bound for transform feedback");
+ gl.bindBuffer(gl.PIXEL_PACK_BUFFER, tfBuffer);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "PIXEL_PACK_BUFFER is bound for transform feedback");
+ gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null)
+
+ debug("<hr/>Test bufferData family with tf object bound");
+
+ gl.bindBuffer(gl.COPY_WRITE_BUFFER, tfBuffer);
+ gl.bufferData(gl.COPY_WRITE_BUFFER, 16, gl.STATIC_DRAW);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "bufferData with double bound buffer");
+ gl.bufferSubData(gl.COPY_WRITE_BUFFER, 0, new Uint8Array([0]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "bufferSubData with double bound buffer");
+ gl.getBufferSubData(gl.COPY_WRITE_BUFFER, 0, new Uint8Array([0]), 0, 1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "getBufferSubData with double bound buffer");
+
+ gl.bindBuffer(gl.COPY_READ_BUFFER, vertexBuffer);
+ gl.copyBufferSubData(gl.COPY_WRITE_BUFFER, gl.COPY_READ_BUFFER, 0, 0, 1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "copyBufferSubData with double bound buffer");
+ gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "copyBufferSubData with double bound buffer");
+
+ debug("<hr/>Test bufferData family with tf object unbound");
+
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
+ gl.bindBuffer(gl.COPY_WRITE_BUFFER, tfBuffer);
+ gl.bufferData(gl.COPY_WRITE_BUFFER, 16, gl.STATIC_DRAW);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "bufferData should succeed");
+ gl.bufferSubData(gl.COPY_WRITE_BUFFER, 0, new Uint8Array([0]));
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "bufferSubData should succeed");
+ gl.getBufferSubData(gl.COPY_WRITE_BUFFER, 0, new Uint8Array([0]), 0, 1);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "getBufferSubData should succeed");
+
+ gl.bindBuffer(gl.COPY_READ_BUFFER, vertexBuffer);
+ gl.copyBufferSubData(gl.COPY_WRITE_BUFFER, gl.COPY_READ_BUFFER, 0, 0, 1);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "copyBufferSubData should succeed");
+ gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 1);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "copyBufferSubData should succeed");
+}
+
+finishTest();
+
+</script>
+
+</body>
+</html>