← All reports

[visionOS] Introduce Connected Volumetric Scenes

Component: WebKit visionOS model element / Spatial Portal | a216b77

LayoutTests/model-element/volumetric/resources/volumetric-utils.js

+// Presentation is confirmed by the UI process, so every transition settles asynchronously.
+const waitForPresentationMode = (test, element, expected) =>
+ test.step_wait(() => presentationMode(element) === expected, `presentation mode becomes "${expected}"`);
+
+// requestVolumetricScene() consumes transient activation, which each call needs afresh.
+const requestVolumetricScene = element => {
+ let promise;
+ internals.withUserGesture(() => { promise = element.requestVolumetricScene(); });
+ return promise;
+};
...

LayoutTests/model-element/volumetric/volumetric-scene-api-disabled.html

+<!DOCTYPE html> <!-- webkit-test-runner [ SpatialPortalEnabled=false ModelElementEnabled=true ModelProcessEnabled=true ] -->
+ assert_false('requestVolumetricScene' in div, 'requestVolumetricScene should be absent from Element');
+ assert_false('exitVolumetricScene' in model, 'exitVolumetricScene should be absent from a model');

On visionOS, <model> content is rendered by a separate ModelProcess (RealityKit). WebContent holds only a player proxy and a layer hosting context, which the UI process composites into the page. A spatial: portal element groups child models behind a SpatialPortalController. Presenting in a separate volumetric window means the layer hosting context, normally claimed by the page, is handed to a new UIScene the UI process creates, and that scene must be matched back to the request that asked for it.

This commit adds experimental, off-by-default Connected Volumetric Scenes. requestVolumetricScene() and exitVolumetricScene() are exposed on Element for spatial: portal elements and bare <model> elements, and the model's content is presented in a separate volumetric window while the page stays live. A new ElementVolumetricScene dispatches to SpatialPortalController or HTMLModelElement. The immersive detach flag is replaced by a unified ModelPresentationMode (inline, immersive, volumetric). New messages carry enter, exit and resize through WebPage, WebPageProxy, ModelProcessModelPlayer and ModelProcessModelPlayerProxy, and the UI process hosts the model process's layer in a new WKPortalVolumetricSceneController.

WebContent                    UIProcess                         ModelProcess
   │                              │                                  │
   │ requestVolumetricScene()     │                                  │
   │ (transient activation        │                                  │
   │  consumed)                   │                                  │
   ├─ enterVolumetricScene… ─────►│ presentVolumetricScene           │
   │  (scene-limit check first)   │  ├─ create token + pending ctrl  │
   │                              │  ├─ activate UIScene(token)      │
   │                              │  │   └─ scene:willConnect…       │
   │                              │  │      match token → ctrl       │
   │                              │  └─ hostContent(ctx, pid) ──────►│ layer hosted in
   │                              │                                  │ volume
   │◄─ updateVolumetricSceneSize ─┤ volume size change               │
   │                              │                                  │
   │◄─ volumetricSceneDidClose ───┤ window closed / dismissed        │
   │ (also on navigation/detach   │                                  │
   │  → dismissVolumetricScenes…) │                                  │

This is a new web-reachable API that moves a layer hosting context from the page to a UI-process-owned window, adding IPC across WebContent, ModelProcess and UIProcess plus a token-based scene activation flow.

The new surface runs from the DOM API to WebPage, WebPageProxy IPC, PortalPresentationManagerProxy and WKPortalVolumetricSceneController, with parallel messages to ModelProcessModelPlayerProxy.