Title: [281331] trunk
Revision
281331
Author
d...@apple.com
Date
2021-08-20 12:41:33 -0700 (Fri, 20 Aug 2021)

Log Message

[WebXR] A session with only one view should cover the full screen
https://bugs.webkit.org/show_bug.cgi?id=229110
<rdar://problem/81940621>

Reviewed by Tim Horton.

Source/WebCore:

If we get into the state with an immersive session and only one view,
we should treat that view as the full width. This situation should never
happen with a real headset, but can be found in testing scenarios.

Test: http/wpt/webxr/xrViewport_singleView_valid.https.html

* Modules/webxr/WebXRWebGLLayer.cpp:
(WebCore::WebXRWebGLLayer::computeViewports): Add test for only one
view and assume it is the left eye.

LayoutTests:

Add a test that provides an immersive session with only one view.
This required copying a few more things over from the WPT directory.

* http/wpt/webxr/resources/test-only-api.js: Added.
(loadScript):
* http/wpt/webxr/resources/webxr_test_constants_single_view.js: Added.
* http/wpt/webxr/resources/webxr_util.js: Added.
* http/wpt/webxr/xrViewport_singleView_valid.https-expected.txt: Added.
* http/wpt/webxr/xrViewport_singleView_valid.https.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (281330 => 281331)


--- trunk/LayoutTests/ChangeLog	2021-08-20 19:38:50 UTC (rev 281330)
+++ trunk/LayoutTests/ChangeLog	2021-08-20 19:41:33 UTC (rev 281331)
@@ -1,3 +1,21 @@
+2021-08-20  Dean Jackson  <d...@apple.com>
+
+        [WebXR] A session with only one view should cover the full screen
+        https://bugs.webkit.org/show_bug.cgi?id=229110
+        <rdar://problem/81940621>
+
+        Reviewed by Tim Horton.
+
+        Add a test that provides an immersive session with only one view.
+        This required copying a few more things over from the WPT directory.
+
+        * http/wpt/webxr/resources/test-only-api.js: Added.
+        (loadScript):
+        * http/wpt/webxr/resources/webxr_test_constants_single_view.js: Added.
+        * http/wpt/webxr/resources/webxr_util.js: Added.
+        * http/wpt/webxr/xrViewport_singleView_valid.https-expected.txt: Added.
+        * http/wpt/webxr/xrViewport_singleView_valid.https.html: Added.
+
 2021-08-20  Carlos Alberto Lopez Perez  <clo...@igalia.com>
 
         [GTK][WPE] Gardening of expected failures

Added: trunk/LayoutTests/http/wpt/webxr/resources/test-only-api.js (0 => 281331)


--- trunk/LayoutTests/http/wpt/webxr/resources/test-only-api.js	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/resources/test-only-api.js	2021-08-20 19:41:33 UTC (rev 281331)
@@ -0,0 +1,31 @@
+'use strict';
+
+/* Whether the browser is Chromium-based with MojoJS enabled */
+const isChromiumBased = 'MojoInterfaceInterceptor' in self;
+/* Whether the browser is WebKit-based with internal test-only API enabled */
+const isWebKitBased = !isChromiumBased && 'internals' in self;
+
+/**
+ * Loads a script in a window or worker.
+ *
+ * @param {string} path - A script path
+ * @returns {Promise}
+ */
+function loadScript(path) {
+  if (typeof document === 'undefined') {
+    // Workers (importScripts is synchronous and may throw.)
+    importScripts(path);
+    return Promise.resolve();
+  } else {
+    // Window
+    const script = document.createElement('script');
+    script.src = ""
+    script.async = false;
+    const p = new Promise((resolve, reject) => {
+      script._onload_ = () => { resolve(); };
+      script._onerror_ = e => { reject(`Error loading ${path}`); };
+    })
+    document.head.appendChild(script);
+    return p;
+  }
+}
Property changes on: trunk/LayoutTests/http/wpt/webxr/resources/test-only-api.js
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/plain \ No newline at end of property

Added: trunk/LayoutTests/http/wpt/webxr/resources/webxr_test_constants_single_view.js (0 => 281331)


--- trunk/LayoutTests/http/wpt/webxr/resources/webxr_test_constants_single_view.js	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/resources/webxr_test_constants_single_view.js	2021-08-20 19:41:33 UTC (rev 281331)
@@ -0,0 +1,199 @@
+// assert_equals can fail when comparing floats due to precision errors, so
+// use assert_approx_equals with this constant instead
+const FLOAT_EPSILON = 0.001;
+
+// Identity matrix
+const IDENTITY_MATRIX = [1, 0, 0, 0,
+                         0, 1, 0, 0,
+                         0, 0, 1, 0,
+                         0, 0, 0, 1];
+
+const IDENTITY_TRANSFORM = {
+    position: [0, 0, 0],
+    orientation: [0, 0, 0, 1],
+};
+
+// A valid pose matrix/transform for  when we don't care about specific values
+// Note that these two should be identical, just different representations
+const VALID_POSE_MATRIX = [0, 1, 0, 0,
+                           0, 0, 1, 0,
+                           1, 0, 0, 0,
+                           1, 1, 1, 1];
+
+const VALID_POSE_TRANSFORM = {
+    position: [1, 1, 1],
+    orientation: [0.5, 0.5, 0.5, 0.5]
+};
+
+const VALID_PROJECTION_MATRIX =
+    [1, 0, 0, 0, 0, 1, 0, 0, 3, 2, -1, -1, 0, 0, -0.2, 0];
+
+// This is a decomposed version of the above.
+const VALID_FIELD_OF_VIEW = {
+    upDegrees: 71.565,
+    downDegrees: -45,
+    leftDegrees:-63.4349,
+    rightDegrees: 75.9637
+};
+
+// A valid input grip matrix for  when we don't care about specific values
+const VALID_GRIP = [1, 0, 0, 0,
+                    0, 1, 0, 0,
+                    0, 0, 1, 0,
+                    4, 3, 2, 1];
+
+const VALID_GRIP_TRANSFORM = {
+    position: [4, 3, 2],
+    orientation: [0, 0, 0, 1]
+};
+
+// A valid input pointer offset for  when we don't care about specific values
+const VALID_POINTER = [1, 0, 0, 0,
+                       0, 1, 0, 0,
+                       0, 0, 1, 0,
+                       0, 0, 1, 1];
+
+const VALID_POINTER_TRANSFORM = {
+    position: [0, 0, 1],
+    orientation: [0, 0, 0, 1]
+};
+
+// A Valid Local to floor matrix/transform for when we don't care about specific
+// values.  Note that these should be identical, just different representations.
+const VALID_FLOOR_ORIGIN_MATRIX = [1, 0,    0,  0,
+                                     0, 1,    0,  0,
+                                     0, 0,    1,  0,
+                                     1, 1.65, -1, 1];
+
+const VALID_FLOOR_ORIGIN = {
+    position: [-1.0, -1.65, 1.0],
+    orientation: [0, 0, 0, 1]
+};
+
+const VALID_BOUNDS = [
+    { x: 3.0, z: -2.0 },
+    { x: 3.5, z: 0.0 },
+    { x: 3.0, z: 2.0 },
+    { x: -3.0, z: 2.0 },
+    { x: -3.5, z: 0.0 },
+    { x: -3.0, z: -2.0 }
+];
+
+const VALID_RESOLUTION = {
+    width: 200,
+    height: 200
+};
+
+const LEFT_OFFSET = {
+    position: [-0.1, 0, 0],
+    orientation: [0, 0, 0, 1]
+};
+
+const RIGHT_OFFSET = {
+    position: [0.1, 0, 0],
+    orientation: [0, 0, 0, 1]
+};
+
+const VALID_VIEWS = [{
+        eye:"left",
+        projectionMatrix: VALID_PROJECTION_MATRIX,
+        viewOffset: LEFT_OFFSET,
+        resolution: VALID_RESOLUTION
+    }, {
+        eye:"right",
+        projectionMatrix: VALID_PROJECTION_MATRIX,
+        viewOffset: RIGHT_OFFSET,
+        resolution: VALID_RESOLUTION
+    },
+];
+
+const NON_IMMERSIVE_VIEWS = [{
+        eye: "none",
+        projectionMatrix: VALID_PROJECTION_MATRIX,
+        viewOffset: IDENTITY_TRANSFORM,
+        resolution: VALID_RESOLUTION,
+    }
+];
+
+const LEFT_ONLY_IMMERSIVE_VIEWS = [{
+        eye: "left",
+        projectionMatrix: VALID_PROJECTION_MATRIX,
+        viewOffset: IDENTITY_TRANSFORM,
+        resolution: VALID_RESOLUTION,
+    }
+];
+
+const ALL_FEATURES = [
+  'viewer',
+  'local',
+  'local-floor',
+  'bounded-floor',
+  'unbounded',
+  'hit-test',
+  'dom-overlay',
+  'light-estimation',
+  'anchors',
+  'depth-sensing',
+];
+
+const TRACKED_IMMERSIVE_DEVICE = {
+    supportsImmersive: true,
+    supportedModes: [ "inline", "immersive-vr"],
+    views: VALID_VIEWS,
+    viewerOrigin: IDENTITY_TRANSFORM,
+    supportedFeatures: ALL_FEATURES,
+    environmentBlendMode: "opaque",
+    interactionMode: "world-space"
+};
+
+const IMMERSIVE_AR_DEVICE = {
+  supportsImmersive: true,
+  supportedModes: [ "inline", "immersive-ar"],
+  views: VALID_VIEWS,
+  viewerOrigin: IDENTITY_TRANSFORM,
+  supportedFeatures: ALL_FEATURES,
+  environmentBlendMode: "additive",
+  interactionMode: "screen-space"
+};
+
+const VALID_NON_IMMERSIVE_DEVICE = {
+    supportsImmersive: false,
+    supportedModes: ["inline"],
+    views: NON_IMMERSIVE_VIEWS,
+    viewerOrigin: IDENTITY_TRANSFORM,
+    supportedFeatures: ALL_FEATURES,
+    environmentBlendMode: "opaque",
+    interactionMode: "screen-space"
+};
+
+const TRACKED_IMMERSIVE_SINGLE_VIEWDEVICE = {
+    supportsImmersive: true,
+    supportedModes: [ "inline", "immersive-vr"],
+    views: LEFT_ONLY_IMMERSIVE_VIEWS,
+    viewerOrigin: IDENTITY_TRANSFORM,
+    supportedFeatures: ALL_FEATURES,
+    environmentBlendMode: "opaque",
+    interactionMode: "world-space"
+};
+
+
+const VALID_CONTROLLER = {
+    handedness: "none",
+    targetRayMode: "tracked-pointer",
+    pointerOrigin: VALID_POINTER_TRANSFORM,
+    profiles: []
+};
+
+const RIGHT_CONTROLLER = {
+    handedness: "right",
+    targetRayMode: "tracked-pointer",
+    pointerOrigin: VALID_POINTER_TRANSFORM,
+    profiles: []
+};
+
+const SCREEN_CONTROLLER = {
+    handedness: "none",
+    targetRayMode: "screen",
+    pointerOrigin: VALID_POINTER_TRANSFORM,
+    profiles: []
+};
Property changes on: trunk/LayoutTests/http/wpt/webxr/resources/webxr_test_constants_single_view.js
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/plain \ No newline at end of property

Added: trunk/LayoutTests/http/wpt/webxr/resources/webxr_util.js (0 => 281331)


--- trunk/LayoutTests/http/wpt/webxr/resources/webxr_util.js	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/resources/webxr_util.js	2021-08-20 19:41:33 UTC (rev 281331)
@@ -0,0 +1,240 @@
+'use strict';
+
+// These tests rely on the User Agent providing an implementation of the
+// WebXR Testing API (https://github.com/immersive-web/webxr-test-api).
+//
+// In Chromium-based browsers, this implementation is provided by a _javascript_
+// shim in order to reduce the amount of test-only code shipped to users. To
+// enable these tests the browser must be run with these options:
+//
+//   --enable-blink-features=MojoJS,MojoJSTest
+
+// Debugging message helper, by default does nothing. Implementations can
+// override this.
+var xr_debug = function(name, msg) {};
+
+function xr_promise_test(name, func, properties, glContextType, glContextProperties) {
+  promise_test(async (t) => {
+    if (glContextType === 'webgl2') {
+      // Fast fail on platforms not supporting WebGL2.
+      assert_implements('WebGL2RenderingContext' in window, 'webgl2 not supported.');
+    }
+    // Perform any required test setup:
+    xr_debug(name, 'setup');
+
+    assert_implements(navigator.xr, 'missing navigator.xr - ensure test is run in a secure context.');
+
+    // Only set up once.
+    if (!navigator.xr.test) {
+      // Load test-only API helpers.
+      const script = document.createElement('script');
+      script.src = '';
+      script.async = false;
+      const p = new Promise((resolve, reject) => {
+        script._onload_ = () => { resolve(); };
+        script._onerror_ = e => { reject(e); };
+      })
+      document.head.appendChild(script);
+      await p;
+
+      if (isChromiumBased) {
+        // Chrome setup
+        await loadChromiumResources();
+      } else if (isWebKitBased) {
+        // WebKit setup
+        await setupWebKitWebXRTestAPI();
+      }
+    }
+
+    // Either the test api needs to be polyfilled and it's not set up above, or
+    // something happened to one of the known polyfills and it failed to be
+    // setup properly. Either way, the fact that xr_promise_test is being used
+    // means that the tests expect navigator.xr.test to be set. By rejecting now
+    // we can hopefully provide a clearer indication of what went wrong.
+    assert_implements(navigator.xr.test, 'missing navigator.xr.test, even after attempted load');
+
+    let gl = null;
+    let canvas = null;
+    if (glContextType) {
+      canvas = document.createElement('canvas');
+      document.body.appendChild(canvas);
+      gl = canvas.getContext(glContextType, glContextProperties);
+    }
+
+    // Ensure that any devices are disconnected when done. If this were done in
+    // a .then() for the success case, a test that expected failure would
+    // already be marked done at the time that runs and the shutdown would
+    // interfere with the next test.
+    t.add_cleanup(async () => {
+      // Ensure system state is cleaned up.
+      xr_debug(name, 'cleanup');
+      await navigator.xr.test.disconnectAllDevices();
+    });
+
+    xr_debug(name, 'main');
+    return func(t, gl);
+  }, name, properties);
+}
+
+// A utility function for waiting one animation frame before running the callback
+//
+// This is only needed after calling FakeXRDevice methods outside of an animation frame
+//
+// This is so that we can paper over the potential race allowed by the "next animation frame"
+// concept https://immersive-web.github.io/webxr-test-api/#xrsession-next-animation-frame
+function requestSkipAnimationFrame(session, callback) {
+ session.requestAnimationFrame(() => {
+  session.requestAnimationFrame(callback);
+ });
+}
+
+// A test function which runs through the common steps of requesting a session.
+// Calls the passed in test function with the session, the controller for the
+// device, and the test object.
+function xr_session_promise_test(
+    name, func, fakeDeviceInit, sessionMode, sessionInit, properties,
+    glcontextPropertiesParam, gllayerPropertiesParam) {
+  const glcontextProperties = (glcontextPropertiesParam) ? glcontextPropertiesParam : {};
+  const gllayerProperties = (gllayerPropertiesParam) ? gllayerPropertiesParam : {};
+
+  function runTest(t, glContext) {
+    let testSession;
+    let testDeviceController;
+    let sessionObjects = {gl: glContext};
+
+    // Ensure that any pending sessions are ended when done. This needs to
+    // use a cleanup function to ensure proper sequencing. If this were
+    // done in a .then() for the success case, a test that expected
+    // failure would already be marked done at the time that runs, and the
+    // shutdown would interfere with the next test which may have started.
+    t.add_cleanup(async () => {
+      // If a session was created, end it.
+      if (testSession) {
+        await testSession.end().catch(() => {});
+      }
+    });
+
+    return navigator.xr.test.simulateDeviceConnection(fakeDeviceInit)
+        .then((controller) => {
+          testDeviceController = controller;
+          return sessionObjects.gl.makeXRCompatible();
+        })
+        .then(() => new Promise((resolve, reject) => {
+                // Perform the session request in a user gesture.
+                xr_debug(name, 'simulateUserActivation');
+                navigator.xr.test.simulateUserActivation(() => {
+                  xr_debug(name, 'document.hasFocus()=' + document.hasFocus());
+                  navigator.xr.requestSession(sessionMode, sessionInit || {})
+                      .then((session) => {
+                        xr_debug(name, 'session start');
+                        testSession = session;
+                        session.mode = sessionMode;
+                        let glLayer = new XRWebGLLayer(session, sessionObjects.gl, gllayerProperties);
+                        glLayer.context = sessionObjects.gl;
+                        // Session must have a baseLayer or frame requests
+                        // will be ignored.
+                        session.updateRenderState({
+                            baseLayer: glLayer
+                        });
+                        sessionObjects.glLayer = glLayer;
+                        xr_debug(name, 'session.visibilityState=' + session.visibilityState);
+                        try {
+                          resolve(func(session, testDeviceController, t, sessionObjects));
+                        } catch(err) {
+                          reject("Test function failed with: " + err);
+                        }
+                      })
+                      .catch((err) => {
+                        xr_debug(name, 'error: ' + err);
+                        reject(
+                            'Session with params ' +
+                            JSON.stringify(sessionMode) +
+                            ' was rejected on device ' +
+                            JSON.stringify(fakeDeviceInit) +
+                            ' with error: ' + err);
+                      });
+                });
+        }));
+  }
+
+  xr_promise_test(
+    name + ' - webgl',
+    runTest,
+    properties,
+    'webgl',
+    {alpha: false, antialias: false, ...glcontextProperties}
+    );
+  xr_promise_test(
+    name + ' - webgl2',
+    runTest,
+    properties,
+    'webgl2',
+    {alpha: false, antialias: false, ...glcontextProperties});
+}
+
+
+// This function wraps the provided function in a
+// simulateUserActivation() call, and resolves the promise with the
+// result of func(), or an error if one is thrown
+function promise_simulate_user_activation(func) {
+  return new Promise((resolve, reject) => {
+    navigator.xr.test.simulateUserActivation(() => {
+      try { let a = func(); resolve(a); } catch(e) { reject(e); }
+    });
+  });
+}
+
+// This functions calls a callback with each API object as specified
+// by https://immersive-web.github.io/webxr/spec/latest/, allowing
+// checks to be made on all ojects.
+// Arguements:
+//      callback: A callback function with two arguements, the first
+//                being the API object, the second being the name of
+//                that API object.
+function forEachWebxrObject(callback) {
+  callback(window.navigator.xr, 'navigator.xr');
+  callback(window.XRSession, 'XRSession');
+  callback(window.XRSessionCreationOptions, 'XRSessionCreationOptions');
+  callback(window.XRFrameRequestCallback, 'XRFrameRequestCallback');
+  callback(window.XRPresentationContext, 'XRPresentationContext');
+  callback(window.XRFrame, 'XRFrame');
+  callback(window.XRLayer, 'XRLayer');
+  callback(window.XRView, 'XRView');
+  callback(window.XRViewport, 'XRViewport');
+  callback(window.XRViewerPose, 'XRViewerPose');
+  callback(window.XRWebGLLayer, 'XRWebGLLayer');
+  callback(window.XRWebGLLayerInit, 'XRWebGLLayerInit');
+  callback(window.XRCoordinateSystem, 'XRCoordinateSystem');
+  callback(window.XRFrameOfReference, 'XRFrameOfReference');
+  callback(window.XRStageBounds, 'XRStageBounds');
+  callback(window.XRSessionEvent, 'XRSessionEvent');
+  callback(window.XRCoordinateSystemEvent, 'XRCoordinateSystemEvent');
+}
+
+// Code for loading test API in Chromium.
+async function loadChromiumResources() {
+  await loadScript('/resources/chromium/webxr-test-math-helper.js');
+  await import('/resources/chromium/webxr-test.js');
+  await loadScript('/resources/testdriver.js');
+  await loadScript('/resources/testdriver-vendor.js');
+
+  // This infrastructure is also used by Chromium-specific internal tests that
+  // may need additional resources (e.g. internal API extensions), this allows
+  // those tests to rely on this infrastructure while ensuring that no tests
+  // make it into public WPTs that rely on APIs outside of the webxr test API.
+  if (typeof(additionalChromiumResources) !== 'undefined') {
+    for (const path of additionalChromiumResources) {
+      await loadScript(path);
+    }
+  }
+
+  xr_debug = navigator.xr.test.Debug;
+}
+
+function setupWebKitWebXRTestAPI() {
+  // WebKit setup. The internals object is used by the WebKit test runner
+  // to provide JS access to internal APIs. In this case it's used to
+  // ensure that XRTest is only exposed to wpt tests.
+  navigator.xr.test = internals.xrTest;
+  return Promise.resolve();
+}
Property changes on: trunk/LayoutTests/http/wpt/webxr/resources/webxr_util.js
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/plain \ No newline at end of property

Added: trunk/LayoutTests/http/wpt/webxr/xrViewport_singleView_valid.https-expected.txt (0 => 281331)


--- trunk/LayoutTests/http/wpt/webxr/xrViewport_singleView_valid.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrViewport_singleView_valid.https-expected.txt	2021-08-20 19:41:33 UTC (rev 281331)
@@ -0,0 +1,4 @@
+
+PASS XRViewport attributes are valid even when there is only one view - webgl
+PASS XRViewport attributes are valid even when there is only one view - webgl2
+
Property changes on: trunk/LayoutTests/http/wpt/webxr/xrViewport_singleView_valid.https-expected.txt
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/plain \ No newline at end of property

Added: trunk/LayoutTests/http/wpt/webxr/xrViewport_singleView_valid.https.html (0 => 281331)


--- trunk/LayoutTests/http/wpt/webxr/xrViewport_singleView_valid.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webxr/xrViewport_singleView_valid.https.html	2021-08-20 19:41:33 UTC (rev 281331)
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+
+<script>
+let testName = "XRViewport attributes are valid even when there is only one view";
+
+let fakeDeviceInitParams = TRACKED_IMMERSIVE_SINGLE_VIEWDEVICE;
+
+let testFunction = function(session, fakeDeviceController, t, sessionObjects) {
+  return session.requestReferenceSpace('local')
+    .then((referenceSpace) => new Promise((resolve) =>{
+      let webglLayer = sessionObjects.glLayer;
+      function onFrame(time, xrFrame) {
+        let pose = xrFrame.getViewerPose(referenceSpace);
+        assert_not_equals(pose, null);
+        assert_not_equals(pose.views, null);
+        assert_equals(pose.views.length, 1);
+
+        let leftView = pose.views[0];
+
+        let leftViewport = webglLayer.getViewport(leftView);
+
+        t.step(() => {
+          // Ensure the views report the expected viewports into the WebGL layer.
+          assert_true(leftViewport instanceof XRViewport);
+
+          assert_not_equals(leftViewport, null);
+
+          // Exact viewport values don't matter, but they must pass several tests:
+
+          // Viewports have non-zero widths and heights.
+          assert_greater_than(leftViewport.width, 0);
+          assert_greater_than(leftViewport.height, 0);
+
+          // Viewports are located within the framebuffer.
+          assert_greater_than_equal(leftViewport.x, 0);
+          assert_greater_than_equal(leftViewport.y, 0);
+          assert_greater_than_equal(leftViewport.x, 0);
+          assert_greater_than_equal(leftViewport.y, 0);
+
+          assert_less_than_equal(
+            leftViewport.x + leftViewport.width, webglLayer.framebufferWidth);
+          assert_less_than_equal(
+            leftViewport.y + leftViewport.height, webglLayer.framebufferHeight);
+        });
+
+        resolve();
+      }
+      session.requestAnimationFrame(onFrame);
+  }));
+};
+
+xr_session_promise_test(
+  testName, testFunction, fakeDeviceInitParams, 'immersive-vr');
+
+</script>
Property changes on: trunk/LayoutTests/http/wpt/webxr/xrViewport_singleView_valid.https.html
___________________________________________________________________

Added: svn:eol-style

+native \ No newline at end of property

Added: svn:keywords

+Date Revision \ No newline at end of property

Added: svn:mime-type

+text/html \ No newline at end of property

Modified: trunk/Source/WebCore/ChangeLog (281330 => 281331)


--- trunk/Source/WebCore/ChangeLog	2021-08-20 19:38:50 UTC (rev 281330)
+++ trunk/Source/WebCore/ChangeLog	2021-08-20 19:41:33 UTC (rev 281331)
@@ -1,3 +1,21 @@
+2021-08-20  Dean Jackson  <d...@apple.com>
+
+        [WebXR] A session with only one view should cover the full screen
+        https://bugs.webkit.org/show_bug.cgi?id=229110
+        <rdar://problem/81940621>
+
+        Reviewed by Tim Horton.
+
+        If we get into the state with an immersive session and only one view,
+        we should treat that view as the full width. This situation should never
+        happen with a real headset, but can be found in testing scenarios.
+
+        Test: http/wpt/webxr/xrViewport_singleView_valid.https.html
+
+        * Modules/webxr/WebXRWebGLLayer.cpp:
+        (WebCore::WebXRWebGLLayer::computeViewports): Add test for only one
+        view and assume it is the left eye.
+
 2021-08-20  Aditya Keerthi  <akeer...@apple.com>
 
         [macOS] Crash when painting <meter> with large scale

Modified: trunk/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp (281330 => 281331)


--- trunk/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp	2021-08-20 19:38:50 UTC (rev 281330)
+++ trunk/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp	2021-08-20 19:41:33 UTC (rev 281331)
@@ -324,18 +324,13 @@
     auto width = framebufferWidth();
     auto height = framebufferHeight();
 
-    if (m_session->mode() == XRSessionMode::ImmersiveVr) {
-        // Update left viewport
-        auto scale = m_leftViewportData.currentScale;
-        m_leftViewportData.viewport->updateViewport(IntRect(0, 0, roundDown(width * 0.5 * scale), roundDown(height * scale)));
-
-        // Update right viewport
-        scale = m_rightViewportData.currentScale;
-        m_rightViewportData.viewport->updateViewport(IntRect(width * 0.5, 0, roundDown(width * 0.5 * scale), roundDown(height * scale)));
-    } else {
-        // We reuse m_leftViewport for XREye::None.
+    if (m_session->mode() == XRSessionMode::ImmersiveVr && m_session->views().size() > 1) {
+        auto leftScale = m_leftViewportData.currentScale;
+        m_leftViewportData.viewport->updateViewport(IntRect(0, 0, roundDown(width * 0.5 * leftScale), roundDown(height * leftScale)));
+        auto rightScale = m_rightViewportData.currentScale;
+        m_rightViewportData.viewport->updateViewport(IntRect(width * 0.5, 0, roundDown(width * 0.5 * rightScale), roundDown(height * rightScale)));
+    } else
         m_leftViewportData.viewport->updateViewport(IntRect(0, 0, width, height));
-    }
 
     m_viewportsDirty = false;
 }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to