Automatic update from web-platform-tests WebKit export of https://bugs.webkit.org/show_bug.cgi?id=301728 -- wpt-commits: 21961f4352e974004e0311059fe0edfa110570b9 wpt-pr: 55864
220 lines
7.5 KiB
HTML
220 lines
7.5 KiB
HTML
<!DOCTYPE html>
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="resources/webxr_util.js"></script>
|
|
<script src="resources/webxr_test_constants.js"></script>
|
|
|
|
<script>
|
|
let immersiveTestName = "Ensure that the framebuffer given by the WebGL layer" +
|
|
" works with stencil for immersive";
|
|
let nonImmersiveTestName = "Ensure that the framebuffer given by the WebGL layer" +
|
|
" works with stencil for non-immersive";
|
|
|
|
let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
|
|
|
|
function createShader(gl, type, source) {
|
|
var shader = gl.createShader(type);
|
|
gl.shaderSource(shader, source);
|
|
gl.compileShader(shader);
|
|
var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
|
|
if (success) {
|
|
return shader;
|
|
}
|
|
|
|
gl.deleteShader(shader);
|
|
}
|
|
|
|
function createProgram(gl, vertexShader, fragmentShader) {
|
|
var program = gl.createProgram();
|
|
gl.attachShader(program, vertexShader);
|
|
gl.attachShader(program, fragmentShader);
|
|
gl.linkProgram(program);
|
|
var success = gl.getProgramParameter(program, gl.LINK_STATUS);
|
|
if (success) {
|
|
return program;
|
|
}
|
|
|
|
gl.deleteProgram(program);
|
|
}
|
|
|
|
let testFunction =
|
|
(session, fakeDeviceController, t, sessionObjects) => new Promise((resolve, reject) => {
|
|
const gl = sessionObjects.gl;
|
|
const webglLayer = sessionObjects.glLayer;
|
|
const xrFramebuffer = webglLayer.framebuffer;
|
|
const webglCanvas = sessionObjects.gl.canvas;
|
|
|
|
session.requestAnimationFrame((time, xrFrame) => {
|
|
t.step(() => {
|
|
// Make sure we're starting with a clean error slate.
|
|
gl.getError();
|
|
assert_equals(gl.getError(), gl.NO_ERROR, "Should not initially have any errors");
|
|
|
|
if (session.mode === 'inline') {
|
|
// Creating a layer with an inline session should return a framebuffer of
|
|
// null, and as such most of these tests won't apply.
|
|
assert_equals(xrFramebuffer, null, 'inline, fbo = null');
|
|
// We need to set canvas size here for inline session testing, since
|
|
// xrFramebuffer is null.
|
|
webglCanvas.width = webglCanvas.height = 300;
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, xrFramebuffer);
|
|
assert_equals(gl.getError(), gl.NO_ERROR, "Binding default framebuffer for inline session");
|
|
} else {
|
|
assert_not_equals(xrFramebuffer, null, 'immersive, fbo != null');
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, xrFramebuffer);
|
|
assert_equals(gl.getError(), gl.NO_ERROR, "Binding WebGLLayer framebuffer");
|
|
}
|
|
|
|
// Framebuffer status must be complete inside of a XR frame callback.
|
|
assert_equals(gl.checkFramebufferStatus(gl.FRAMEBUFFER), gl.FRAMEBUFFER_COMPLETE, "FBO complete");
|
|
});
|
|
gl.clearColor(1, 1, 1, 1);
|
|
|
|
const vs = `
|
|
attribute vec4 position;
|
|
uniform mat4 matrix;
|
|
void main() {
|
|
gl_Position = matrix * position;
|
|
}
|
|
`;
|
|
|
|
const fs = `
|
|
precision mediump float;
|
|
uniform vec4 color;
|
|
void main() {
|
|
gl_FragColor = color;
|
|
}
|
|
`;
|
|
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vs);
|
|
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fs);
|
|
const program = createProgram(gl, vertexShader, fragmentShader);
|
|
|
|
const posLoc = gl.getAttribLocation(program, 'position');
|
|
const matLoc = gl.getUniformLocation(program, 'matrix');
|
|
const colorLoc = gl.getUniformLocation(program, 'color');
|
|
|
|
const buf = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
|
0, -1,
|
|
1, 1,
|
|
-1, 1,
|
|
]), gl.STATIC_DRAW);
|
|
|
|
gl.enableVertexAttribArray(posLoc);
|
|
gl.vertexAttribPointer(
|
|
posLoc, // attribute location
|
|
2, // 2 value per vertex
|
|
gl.FLOAT, // 32bit floating point values
|
|
false, // don't normalize
|
|
0, // stride (0 = base on type and size)
|
|
0, // offset into buffer
|
|
);
|
|
|
|
let xrViewport;
|
|
if (session.mode == 'inline') {
|
|
xrViewport = { x: 0, y: 0, width: webglCanvas.width, height: webglCanvas.height };
|
|
} else {
|
|
xrViewport = { x: 0, y: 0, width: webglLayer.framebufferWidth, height: webglLayer.framebufferHeight };
|
|
}
|
|
|
|
gl.viewport(xrViewport.x, xrViewport.y, xrViewport.width, xrViewport.height);
|
|
gl.scissor(xrViewport.x, xrViewport.y, xrViewport.width, xrViewport.height);
|
|
|
|
// clear the stencil to 0 (the default)
|
|
gl.stencilMask(0xFF);
|
|
gl.clearStencil(0x0);
|
|
gl.disable( gl.SCISSOR_TEST );
|
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
|
|
|
|
gl.useProgram(program);
|
|
let m4 = [1, 0, 0, 0,
|
|
0, 1, 0, 0,
|
|
0, 0, 1, 0,
|
|
0, 0, 0, 1];
|
|
|
|
// turn on the stencil
|
|
gl.enable(gl.STENCIL_TEST);
|
|
|
|
// Drawing into a stencil, always passes, ref val 1, mask 0xFF
|
|
gl.stencilFunc(
|
|
gl.ALWAYS,
|
|
1,
|
|
0xFF,
|
|
);
|
|
// Set it to replace with the ref val (which is 1)
|
|
gl.stencilOp(
|
|
gl.KEEP, // stencil test fails
|
|
gl.KEEP, // depth test fails
|
|
gl.REPLACE, // both tests pass
|
|
);
|
|
|
|
m4[0] = 0.2; m4[5] = 0.2; // scale x and y
|
|
// draw a white triangle
|
|
gl.uniform4fv(colorLoc, [1, 1, 1, 1]); // white
|
|
gl.uniformMatrix4fv(matLoc, false, m4);
|
|
gl.colorMask(false, false, false, false);
|
|
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
|
|
gl.colorMask(true, true, true, true);
|
|
|
|
// Stencil must be 0
|
|
gl.stencilFunc(
|
|
gl.EQUAL,
|
|
0,
|
|
0xFF,
|
|
);
|
|
// keep stencil unmodified during the draw pass
|
|
gl.stencilOp(
|
|
gl.KEEP, // stencil test fails
|
|
gl.KEEP, // depth test fails
|
|
gl.KEEP, // both tests pass
|
|
);
|
|
|
|
m4[0] = 0.9; m4[5] = -0.9; // scale x and y
|
|
// draw a large green triangle
|
|
gl.uniform4fv(colorLoc, [0, 1, 0, 1]); // green
|
|
gl.uniformMatrix4fv(matLoc, false, m4);
|
|
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
|
|
gl.flush();
|
|
gl.finish();
|
|
let pixels = new Uint8Array(4);
|
|
|
|
// check that the main color is used correctly (green)
|
|
pixels[0] = pixels[1] = pixels[2] = pixels[3] = 30;
|
|
gl.readPixels(xrViewport.x + xrViewport.width / 2, xrViewport.y + xrViewport.height/4, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
|
if (pixels[0] == 0x0 && pixels[1] == 0xFF && pixels[2] == 0x0) { // green?
|
|
// PASSED.
|
|
} else if (pixels[0] == 0xFF && pixels[1] == 0xFF && pixels[2] == 0xFF) { // white?
|
|
reject("Failed, white detected, must be green");
|
|
} else {
|
|
reject("Failed, readPixels (1) didn't work, gl error = " + gl.getError() + ", pixel = " +pixels[0] + " " +pixels[1] + " " +pixels[2]);
|
|
}
|
|
|
|
// check if stencil worked, i.e. white pixels in the center
|
|
pixels[0] = pixels[1] = pixels[2] = pixels[3] = 20;
|
|
gl.readPixels(xrViewport.x + xrViewport.width / 2, xrViewport.y + xrViewport.height/2, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
|
|
if (pixels[0] == 0xFF && pixels[1] == 0xFF && pixels[2] == 0xFF) { // white?
|
|
// PASSED.
|
|
} else if (pixels[0] == 0x0 && pixels[1] == 0xFF && pixels[2] == 0x0) { // green?
|
|
reject("Failed, green detected, must be white");
|
|
} else {
|
|
reject("Failed, readPixels (2) didn't work, gl error = " + gl.getError() + ", pixel = " +pixels[0] + " " +pixels[1] + " " +pixels[2]);
|
|
}
|
|
|
|
// Finished.
|
|
resolve();
|
|
});
|
|
});
|
|
|
|
const gl_props = { antialias: false, alpha: false, stencil: true, depth: true };
|
|
|
|
xr_session_promise_test(
|
|
nonImmersiveTestName, testFunction, fakeDeviceInitParams, 'inline', {}, {}, gl_props, gl_props);
|
|
|
|
xr_session_promise_test(
|
|
immersiveTestName, testFunction, fakeDeviceInitParams, 'immersive-vr', {}, {}, gl_props, gl_props);
|
|
|
|
</script>
|