| <!DOCTYPE html> |
| <script src="../resources/testharness.js"></script> |
| <script src="../resources/testharnessreport.js"></script> |
| <script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> |
| <script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> |
| <script src="../external/wpt/resources/chromium/webxr-test.js"></script> |
| <script src="../xr/resources/xr-test-utils.js"></script> |
| <script src="../xr/resources/test-constants.js"></script> |
| <canvas id="webgl-canvas"></canvas> |
| |
| <script> |
| const TEN_SECONDS = 10000; // 10k ms in ten seconds |
| const ONE_MINUTE = 60000; // 60k ms in one minute |
| |
| let testName = "XRFrame getViewerPose updates on the next frame"; |
| |
| let fakeDeviceInitParams = { supportsImmersive:true }; |
| |
| let requestSessionOptions = [ |
| { outputContext: getOutputContext() }, |
| { immersive: true }, |
| ]; |
| |
| let testFunction = function(session, t, fakeDeviceController) { |
| // Session must have a baseLayer or else frame requests will be ignored. |
| session.baseLayer = new XRWebGLLayer(session, gl); |
| |
| // Need to have a valid pose or input event's don't process. |
| fakeDeviceController.setXRPresentationFrameData( |
| VALID_POSE_MATRIX, [{ |
| eye:"left", |
| projectionMatrix: VALID_PROJECTION_MATRIX, |
| viewMatrix: VALID_VIEW_MATRIX |
| }, { |
| eye:"right", |
| projectionMatrix: VALID_PROJECTION_MATRIX, |
| viewMatrix: VALID_VIEW_MATRIX |
| }]); |
| |
| return session.requestReferenceSpace({ type: "stationary", subtype: "eye-level" }) |
| .then((referenceSpace) => new Promise((resolve, reject) => { |
| let counter = 0; |
| let windowFrameTime = 0; |
| let frameTime = 0; |
| |
| function onFrameFirst(time, xrFrame) { |
| frameTime = time; |
| let now = performance.now(); |
| |
| t.step( () => { |
| // This callback must be the first one called. |
| assert_equals(counter, 0); |
| |
| // window.requestAnimationFrame and session.requestAnimationFrame |
| // should be providing timestamps that are on the same scale and |
| // within a resonable margin of error of eachother. This means that |
| // this frame's timestamp should be larger than one provided to a |
| // previous window.requestAnimationFrame and should also be within |
| // a sane delta of it. One minute is probably overly generous here, |
| // but it will at least catch cases where the times are reported with |
| // entirely different bases. |
| assert_greater_than(frameTime, windowFrameTime); |
| assert_approx_equals(frameTime, windowFrameTime, ONE_MINUTE); |
| |
| // There's going to be some disparity between performance.now() and |
| // the timestamp passed into the callback, but it shouldn't be huge. |
| // If they're more than ten seconds apart something has gone horribly |
| // wrong. |
| assert_approx_equals(frameTime, now, TEN_SECONDS); |
| }); |
| |
| counter++; |
| } |
| |
| function onFrameSubsequent(time, xrFrame) { |
| t.step( () => { |
| // The timestamp passed to this callback should be exactly equal to |
| // the one passed to the first callback in this set. |
| assert_equals(time, frameTime); |
| }); |
| |
| counter++; |
| } |
| |
| function onFrameLast(time, xrFrame) { |
| t.step( () => { |
| // Make sure all the previous callbacks fired as expected. |
| assert_equals(counter, 11); |
| }); |
| |
| // Finished. |
| resolve(); |
| } |
| |
| window.requestAnimationFrame((time) => { |
| windowFrameTime = time; |
| |
| // Queue up several callbacks |
| session.requestAnimationFrame(onFrameFirst); |
| for (let i = 0; i < 10; ++i) { |
| session.requestAnimationFrame(onFrameSubsequent); |
| } |
| session.requestAnimationFrame(onFrameLast); |
| }); |
| |
| })); |
| }; |
| |
| xr_session_promise_test( |
| testFunction, fakeDeviceInitParams, requestSessionOptions, testName); |
| |
| </script> |