blob: 77747398529bfd634c7f97427b1b3f056922f841 [file] [log] [blame]
// func: A function that takes a session and optionally a test object and
// performs tests. If func returns a promise, test will only pass if the promise
// resolves.
function xr_session_promise_test(
func, deviceOptions, sessionOptions, name, properties) {
if (document.getElementById('webgl-canvas') ||
document.getElementById('webgl2-canvas')) {
webglCanvasSetup();
}
promise_test((t) => {
let fakeDeviceController;
return XRTest.simulateDeviceConnection(deviceOptions)
.then((controller) => {
fakeDeviceController = controller;
if (gl) {
return gl.makeXRCompatible().then(
() => Promise.resolve());
} else {
return Promise.resolve();
}
})
.then(() => new Promise((resolve, reject) => {
// Run the test with each set of sessionOptions from the array one
// at a time.
function nextSessionTest(i) {
// Check if it's time to break the loop.
if (i == sessionOptions.length) {
if (sessionOptions.length == 0) {
reject('No option for the session. Test Did not run.');
} else {
resolve();
}
return;
}
// Perform the session request in a user gesture.
runWithUserGesture(() => {
let nextOptions = sessionOptions[i];
let testSession = null;
navigator.xr.requestSession(nextOptions)
.then((session) => {
testSession = session;
return func(session, t, fakeDeviceController);
})
.then(() => {
// End the session. Silence any errors generated if the
// session was already ended.
// TODO(bajones): Throwing an error when a session is
// already ended is not defined by the spec. This
// should be defined or removed.
testSession.end().catch(() => {});
fakeDeviceController.setXRPresentationFrameData(null);
})
.then(() => nextSessionTest(++i))
.catch((err) => {
let optionsString = '{';
let firstOption = true;
for (let option in nextOptions) {
if (!firstOption) {
optionsString += ',';
}
optionsString += ` ${option}: ${nextOptions[option]}`;
firstOption = false;
}
optionsString += ' }';
reject(
`Test failed while running with the following options:
${optionsString} ${err}`);
});
});
}
nextSessionTest(0);
}));
}, name, properties);
}
let webglCanvas, gl;
function webglCanvasSetup() {
let webgl2 = false;
webglCanvas = document.getElementById('webgl-canvas');
if (!webglCanvas) {
webglCanvas = document.getElementById('webgl2-canvas');
webgl2 = true;
}
let glAttributes = {
alpha: false,
antialias: false,
};
gl = webglCanvas.getContext(webgl2 ? 'webgl2' : 'webgl', glAttributes);
}
function getOutputContext() {
let outputCanvas = document.createElement('canvas');
document.body.appendChild(outputCanvas);
return outputCanvas.getContext('xrpresent');
}
function perspectiveFromFieldOfView(fov, near, far) {
let upTan = Math.tan(fov.upDegrees * Math.PI / 180.0);
let downTan = Math.tan(fov.downDegrees * Math.PI / 180.0);
let leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0);
let rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0);
let xScale = 2.0 / (leftTan + rightTan);
let yScale = 2.0 / (upTan + downTan);
let nf = 1.0 / (near - far);
let out = new Float32Array(16);
out[0] = xScale;
out[1] = 0.0;
out[2] = 0.0;
out[3] = 0.0;
out[4] = 0.0;
out[5] = yScale;
out[6] = 0.0;
out[7] = 0.0;
out[8] = -((leftTan - rightTan) * xScale * 0.5);
out[9] = ((upTan - downTan) * yScale * 0.5);
out[10] = (near + far) * nf;
out[11] = -1.0;
out[12] = 0.0;
out[13] = 0.0;
out[14] = (2.0 * far * near) * nf;
out[15] = 0.0;
return out;
}
function assert_matrices_approx_equal(
matA, matB, epsilon = FLOAT_EPSILON, message = '') {
if (matA == null && matB == null) {
return;
}
assert_not_equals(matA, null);
assert_not_equals(matB, null);
assert_equals(matA.length, 16);
assert_equals(matB.length, 16);
let mismatched_element = -1;
for (let i = 0; i < 16; ++i) {
if (Math.abs(matA[i] - matB[i]) > epsilon) {
mismatched_element = i;
break;
}
}
if (mismatched_element > -1) {
let error_message =
message ? message + '\n' : 'Matrix comparison failed.\n';
error_message += ' Difference in element ' + mismatched_element +
' exceeded the given epsilon.\n';
error_message += ' Matrix A: [' + matA.join(',') + ']\n';
error_message += ' Matrix B: [' + matB.join(',') + ']\n';
assert_approx_equals(
matA[mismatched_element], matB[mismatched_element], epsilon,
error_message);
}
}
function assert_matrices_significantly_not_equal(
matA, matB, epsilon = FLOAT_EPSILON, message = '') {
if (matA == null && matB == null) {
return;
}
assert_not_equals(matA, null);
assert_not_equals(matB, null);
assert_equals(matA.length, 16);
assert_equals(matB.length, 16);
let mismatch = false;
for (let i = 0; i < 16; ++i) {
if (Math.abs(matA[i] - matB[i]) > epsilon) {
mismatch = true;
break;
}
}
if (!mismatch) {
let matA_str = '[';
let matB_str = '[';
for (let i = 0; i < 16; ++i) {
matA_str += matA[i] + (i < 15 ? ', ' : '');
matB_str += matB[i] + (i < 15 ? ', ' : '');
}
matA_str += ']';
matB_str += ']';
let error_message =
message ? message + '\n' : 'Matrix comparison failed.\n';
error_message +=
' No element exceeded the given epsilon ' + epsilon + '.\n';
error_message += ' Matrix A: ' + matA_str + '\n';
error_message += ' Matrix B: ' + matB_str + '\n';
assert_unreached(error_message);
}
}
function runWithUserGesture(fn) {
function thunk() {
document.removeEventListener('keypress', thunk, false);
fn()
}
document.addEventListener('keypress', thunk, false);
eventSender.keyDown(' ', []);
}