Source code

Revision control

Copy as Markdown

Other Tools

<!--
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>WebGL2 getBufferSubData validity 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>
<div id="console"></div>
<script id="vshader" type="x-shader/x-vertex">#version 300 es
in uint in_data;
flat out uint out_data;
void main() {
out_data = in_data;
}
</script>
<script id="fshader" type="x-shader/x-fragment">#version 300 es
void main() {}
</script>
<script>
"use strict";
description("Test that getBufferSubData returns valid data in edge cases");
var wtu = WebGLTestUtils;
var gl = wtu.create3DContext(undefined, undefined, 2);
const srcData = new Uint8Array([ 1, 2, 3, 4, 5, 6, 7, 8 ]);
const noData = new Uint8Array(8);
const srcBuffer = gl.createBuffer();
gl.bindBuffer(gl.COPY_READ_BUFFER, srcBuffer);
gl.bufferData(gl.COPY_READ_BUFFER, srcData, gl.STATIC_DRAW);
const badBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, badBuffer);
gl.bufferData(gl.ARRAY_BUFFER, 8, gl.STATIC_DRAW);
let readbackBuffer;
function deleteReadbackBuffer() {
gl.deleteBuffer(readbackBuffer);
}
function recreateReadbackBuffer() {
readbackBuffer = gl.createBuffer();
gl.bindBuffer(gl.COPY_WRITE_BUFFER, readbackBuffer);
gl.bufferData(gl.COPY_WRITE_BUFFER, 8, gl.STREAM_READ);
}
recreateReadbackBuffer();
const dest = new Uint8Array(8);
// Makes a new "resolvable" Promise
function resolvable() {
let resolve;
const promise = new Promise(res => { resolve = res; });
promise.resolve = resolve;
return promise;
}
function wait() {
return new Promise(res => {
setTimeout(res, 0);
});
}
async function fence() {
const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
gl.flush();
let status;
do {
await wait();
status = gl.clientWaitSync(sync, 0, 0);
} while (status != gl.ALREADY_SIGNALED && status != gl.CONDITION_SATISFIED);
gl.deleteSync(sync);
}
function checkGetBufferSubData(err, data) {
dest.fill(0);
wtu.shouldGenerateGLError(gl, err, "gl.getBufferSubData(gl.COPY_WRITE_BUFFER, 0, dest)");
if (!err) {
shouldBeTrue(`areArraysEqual(dest, ${data})`);
}
}
const tfProgram = wtu.setupTransformFeedbackProgram(gl, ["vshader", "fshader"],
["out_data"], gl.SEPARATE_ATTRIBS,
["in_data"]);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "linking transform feedback shader should not set an error");
shouldBeNonNull("tfProgram");
const tf = gl.createTransformFeedback();
function copyBufferUsingTransformFeedback(src, dst) {
gl.enableVertexAttribArray(0);
gl.bindBuffer(gl.ARRAY_BUFFER, src);
gl.vertexAttribIPointer(0, 1, gl.UNSIGNED_INT, 0, 0);
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, tf);
gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, dst);
gl.drawBuffers([gl.NONE]);
gl.enable(gl.RASTERIZER_DISCARD);
gl.beginTransformFeedback(gl.POINTS);
// treats the input and output data as two uint32s
gl.drawArrays(gl.POINTS, 0, 2);
gl.endTransformFeedback();
gl.disable(gl.RASTERIZER_DISCARD);
gl.bindBuffer(gl.ARRAY_BUFFER, badBuffer);
gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null);
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
}
(async () => {
debug("");
debug("write-read");
gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
checkGetBufferSubData(gl.NO_ERROR, "srcData");
debug("");
debug("fence-wait-write-read");
await fence();
gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
checkGetBufferSubData(gl.NO_ERROR, "srcData");
debug("");
debug("write-read-fence-wait");
gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
checkGetBufferSubData(gl.NO_ERROR, "srcData");
await fence();
debug("");
debug("write-fence-fence-wait-read");
gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
fence(); // no await
await fence();
checkGetBufferSubData(gl.NO_ERROR, "srcData");
debug("");
debug("write-fence-wait-read");
gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
await fence();
checkGetBufferSubData(gl.NO_ERROR, "srcData");
debug("");
debug("write-fence-wait-write-read");
gl.copyBufferSubData(gl.ARRAY_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
await fence();
gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
checkGetBufferSubData(gl.NO_ERROR, "srcData");
debug("");
debug("write-fence-write-wait-read");
gl.copyBufferSubData(gl.ARRAY_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
{
const p = fence();
gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
await p;
}
checkGetBufferSubData(gl.NO_ERROR, "srcData");
debug("");
debug("write-fence-transformfeedback-wait-read");
gl.copyBufferSubData(gl.ARRAY_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
{
const p = fence();
gl.bindBuffer(gl.COPY_WRITE_BUFFER, null);
copyBufferUsingTransformFeedback(srcBuffer, readbackBuffer);
gl.bindBuffer(gl.COPY_WRITE_BUFFER, readbackBuffer);
await p;
}
checkGetBufferSubData(gl.NO_ERROR, "srcData");
debug("");
debug("write-unbind-fence-wait-bind-read");
gl.bindBuffer(gl.COPY_WRITE_BUFFER, null);
gl.bindBuffer(gl.ARRAY_BUFFER, readbackBuffer);
gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.ARRAY_BUFFER, 0, 0, 8);
gl.bindBuffer(gl.ARRAY_BUFFER, badBuffer);
await fence();
gl.bindBuffer(gl.COPY_WRITE_BUFFER, readbackBuffer);
checkGetBufferSubData(gl.NO_ERROR, "srcData");
debug("");
debug("write-fence-wait-delete-read");
gl.copyBufferSubData(gl.ARRAY_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
await fence();
deleteReadbackBuffer();
checkGetBufferSubData(gl.INVALID_OPERATION, "noData");
recreateReadbackBuffer();
debug("");
debug("write-fence-delete-wait-read");
gl.copyBufferSubData(gl.ARRAY_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
{
const p = fence();
deleteReadbackBuffer();
await p;
}
checkGetBufferSubData(gl.INVALID_OPERATION, "noData");
recreateReadbackBuffer();
debug("");
debug("write-fence-delete-wait-read");
gl.copyBufferSubData(gl.ARRAY_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
deleteReadbackBuffer();
await fence();
checkGetBufferSubData(gl.INVALID_OPERATION, "noData");
recreateReadbackBuffer();
// crbug.com/941930
{
debug("");
debug("write-delete-recreate-fence-wait-read");
gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
deleteReadbackBuffer();
recreateReadbackBuffer();
await fence();
checkGetBufferSubData(gl.NO_ERROR, "noData");
debug("");
debug("write-delete-fence-wait-read");
gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
{
const p = fence();
deleteReadbackBuffer();
await p;
}
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
}
finishTest();
})();
var successfullyParsed = true;
</script>
</body>
</html>