WebXR Layers API Level 1

W3C Working Draft,

More details about this document
This version:
https://www.w3.org/TR/2022/WD-webxrlayers-1-20220105/
Latest published version:
https://www.w3.org/TR/webxrlayers-1/
Editor's Draft:
https://immersive-web.github.io/layers/
Previous Versions:
History:
https://www.w3.org/standards/history/webxrlayers-1
Feedback:
GitHub
Inline In Spec
Editor:
(Facebook)
Participate:
File an issue (open issues)
Mailing list archive
W3C’s #immersive-web IRC

Abstract

This specification describes support for various layer types used in a WebXR session.

Status of this document

This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.

The Immersive Web Working Group maintains a list of all bug reports that the group has not yet addressed. This draft highlights some of the pending issues that are still to be discussed in the working group. No decision has been taken on the outcome of these issues including whether they are valid. Pull requests with proposed specification text for outstanding issues are strongly encouraged.

This document was published by the Immersive Web Working Group as a Working Draft using the Recommendation track. This document is intended to become a W3C Recommendation.

Publication as a Working Draft does not imply endorsement by W3C and its Members. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the 1 August 2017 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 2 November 2021 W3C Process Document.

1. Introduction

This specification adds support of `composition` layers to the WebXR spec. The benefits of layers are as follows:

1.1. Terminology

1.2. Application flow

If an author wants to use GL layers, they have to go through these steps:

  1. For any layer type other than XRProjectionLayer request support through requiredFeatures or optionalFeatures in requestSession().

  2. Create an XRWebGLBinding or XRMediaBinding.

  3. Create layers with these objects.

  4. Add the layers to XRRenderStateInit and call updateRenderState().

  5. During requestAnimationFrame() for webgl layers, draw content each WebGL layer.

2. Initialization

If an application wants to create layers other than of type XRProjectionLayer during a session, the session MUST be requested with an appropriate feature descriptor. The string "layers" is introduced by this module as a new valid feature descriptor for the WebXR Layers feature.

Layers of type XRProjectionLayer MUST always be supported, regardless if the feature descriptor was requested.

The following code requests layers as an optional feature.
navigator.xr.requestSession('immersive-vr', {
    optionalFeatures: ['layers']
  }

Layers are only supported for XRSessions created with XRSessionMode of "immersive-vr" or "immersive-ar". "inline" sessions MUST not support layers.

The "layers" feature descriptor has a feature requirement that it cannot be enabled when there is an active immersive session.

NOTE: This means that executing the request(permissionDesc) API with "layers" will not enable layers support for the current active session.

3. Layer types

3.1. Mono and stereo layers

A stereo layer MUST supply an XRSubImage to render to for each view.

A mono layer MUST supply a single XRSubImage which is shown to each view.

The XR Compositor MUST ensure that layers are presented correctly in stereo to the observer.

3.2. XRLayerLayout

The XRLayerLayout enum defines the layout of the layer.
enum XRLayerLayout {
  "default",
  "mono",
  "stereo",
  "stereo-left-right",
  "stereo-top-bottom"
};

NOTE: If an XRCompositionLayer is created with a "default" or "stereo" XRLayerLayout, it is highly recommended that it is allocated with an "texture-array" texture type.

Note: The "stereo-left-right" and "stereo-top-bottom" layouts are designed to minimize draw calls for content that is already in stereo (for example stereo videos or images). Experiences that don’t require such assets types should use the "default" or "stereo" layout.

3.3. XRCompositionLayer

XRCompositionLayer defines a set of common attributes and behaviors across certain layer types.
[Exposed=Window] interface XRCompositionLayer : XRLayer {
  readonly attribute XRLayerLayout layout;

  attribute boolean blendTextureSourceAlpha;
  attribute boolean? chromaticAberrationCorrection;
  readonly attribute unsigned long mipLevels;

  readonly attribute boolean needsRedraw;

  undefined destroy();
};

The layout attribute returns the layout of the layer.

The blendTextureSourceAlpha attribute enables the layer’s texture alpha channel.

The chromaticAberrationCorrection attribute is a hint for the XR Compositor to enable optical chromatic aberration correction for the layer. If the user agent or device does not support this attribute, they should return null on getting, and setting should be a no-op. If the chromaticAberrationCorrection was changed, it will take effect at the next XRFrame.

The needsRedraw attribute signals that the XRCompositionLayer should be rerendered in the next XR animation frame. It MAY be set when the underlying resources of a layer are lost or when the XR Compositor can no longer reproject the layer. Failing to redraw the content in the next XR animation frame might cause flickering or other side effects.

The mipLevels attribute returns the depth of the mip chain. This MUST be equal or smaller than the value requested in mipLevels.

NOTE: some platforms don’t support mip levels. Authors should query mipLevels to determine if they can target a certain mip level and not rely on the value they passed in mipLevels.

When the underlying resources of a layer are lost for an XRCompositionLayer layer, the user agent MUST run the following steps:
  1. Set layer’s needsRedraw to true.

  2. If layer is not an XRProjectionLayer, queue a task to fire an event named redraw on layer.

destroy() will delete the underlying attachments. If there are no attachments, this function does nothing.

To intialize a composition layer with a XRSession session and an optional instance of a WebGLRenderingContext or a WebGL2RenderingContext context, the user agent MUST run the following steps:

  1. Set this session to session.

  2. If context is defined, set this context to context.

  3. Set this blendTextureSourceAlpha to true.

  4. Initialize this chromaticAberrationCorrection as follows:

    If the user agent supports chromatic aberration correction
    Set this chromaticAberrationCorrection to true or false depending on the user agent’s preference.
    Otherwise
    Set this chromaticAberrationCorrection to null.

When calling destroy(), the user agent MUST run the following steps:

  1. Set this colorTextures array to an empty array.

  2. Set this depthStencilTextures array to an empty array.

  3. Destroy the underlying GL attachments.

Each XRCompositionLayer has a context object which is an instance of either null or a WebGLRenderingContext or a WebGL2RenderingContext and a media object which is an instance of null or a HTMLVideoElement.

Each XRCompositionLayer has an associated session, which is the XRSession it was created with.

When setting the space on a layer with XRSpace space and XRCompositionLayer layer, the user agent MUST run the following steps to validate if the space is valid:

  1. If space is null, throw TypeError and abort these steps.

  2. If space’s session is not equal to the layer’s session, throw TypeError and abort these steps.

XRCompositionLayer has an internal boolean isStatic that indicates that the author can only draw to this layer when needsRedraw is true.

NOTE: if isStatic is true the author can only draw into the layer once after creation or once after a redraw event. This allows the UA to only allocate a single GPU buffer.

When a writeable attribute is set on an XRCompositionLayer or any of its derived classes, reading that attribute MUST return that value. At the end of the requestAnimationFrame() callback, the value MUST be sent to the underlying XR Compositor. The XR Compositor MUST apply the value next time it presents the XRFrame that was passed to the requestAnimationFrame() callback.

NOTE: this means that the values must be applied when the XR Compositor redraws the scene using the new XRFrame, even if there was no change in the colorTexture associated with the XRCompositionLayer or the videoframe associated with a media layer. If the XR Compositor redraws the scene with the previous XRFrame's state, it must not use the new values.

3.4. XRProjectionLayer

An XRProjectionLayer is a layer that fills the entire view of the observer. Projection layers should be refreshed close to the device’s native frame rate.

representation of a projection layer

[Exposed=Window] interface XRProjectionLayer : XRCompositionLayer {
  readonly attribute unsigned long textureWidth;
  readonly attribute unsigned long textureHeight;
  readonly attribute unsigned long textureArrayLength;

  readonly attribute boolean ignoreDepthValues;
  attribute float? fixedFoveation;
};

The textureWidth attribute returns the width in pixels of the colorTextures textures of this layer.

The textureHeight attribute returns the height in pixels of the colorTextures textures of this layer.

The textureArrayLength attribute returns the number of layers of the colorTextures textures of this layer if the XRProjectionLayer was initialized with a textureType of "texture-array". Otherwise it will return 1.

The fixedFoveation attribute controls the amount of foveation used by the XR Compositor. If the user agent or device does not support this attribute, they should return null on getting, and setting should be a no-op. Setting fixedFoveation to a value less than 0 will set it to 0 and setting it to a value higher than 1 will set it to 1. 0 sets the minimum amount of foveation while 1 set the maximum. It is up to the user agent how the XR Compositor interprets these values. If the fixedFoveation level was changed, it will take effect at the next XRFrame.

The ignoreDepthValues attribute, if true, indicates that the XR Compositor MUST NOT make use of values in the depth buffer attachment when rendering. When the attribute is false it indicates that the content of the depth buffer attachment will be used by the XR Compositor and is expected to be representative of the scene rendered into the layer.

3.5. XRQuadLayer

An XRQuadLayer renders a layer that takes up a flat rectangular space in the virtual environment. Only the front of the layer MUST be visible; the back face MUST not be drawn by the XR Compositor.

A XRQuadLayer has no thicknes. It is a two-dimensional object positioned and oriented in 3D space. The position of a quad refers to the center of the quad.

representation of a quad layer

[Exposed=Window] interface XRQuadLayer : XRCompositionLayer {
  attribute XRSpace space;
  attribute XRRigidTransform transform;

  attribute float width;
  attribute float height;

  // Events
  attribute EventHandler onredraw;
};

The transform attributes sets and returns the offset and orientation relative to the space attribute. The transform and space attributes establish the spatial relationship of the layer within the user’s physical environment. When setting the space, first run the steps for setting the space on a layer.

The width and height attributes set and return the width and height of the layer in meters.

When initializing an XRQuadLayer layer with an XRQuadLayerInit init, the user agent MUST run the following steps:
  1. Initialize layer’s width to init’s width.

  2. Initialize layer’s height to init’s height.

  3. Let layer’s space be the init’s space.

  4. Initialize layer’s transform as follows:

    If init’s transform is set
    Let layer’s transform be a new XRRigidTransform in the relevant realm of layer initialized with position and orientation of init’s transform.
    Otherwise
    Let layer’s transform be a new XRRigidTransform in the relevant realm of layer initialized with a DOMPointInit position of { x: 0.0, y: 0.0, z: 0.0, w: 1.0 }.
  5. Initialize layer’s isStatic to init’s isStatic

The onredraw attribute is an Event handler IDL attribute for the redraw event type.

3.6. XRCylinderLayer

An XRCylinderLayer renders a layer that takes up a curved rectangular space in the virtual environment. Only the front of the layer MUST be visible; the back face MUST not be drawn by the XR Compositor.

representation of a cylinder layer

A XRCylinderLayer has no thicknes. It is a two-dimensional object positioned and oriented in 3D space. The position of the cylinder refers to the center of the quad.

[Exposed=Window] interface XRCylinderLayer : XRCompositionLayer {
  attribute XRSpace space;
  attribute XRRigidTransform transform;

  attribute float radius;
  attribute float centralAngle;
  attribute float aspectRatio;

  // Events
  attribute EventHandler onredraw;
};

The transform attribute sets and returns the offset and orientation relative to the space attribute. The transform and space attributes establish the spatial relationship of the layer within the user’s physical environment. When setting the space, first run the steps for setting the space on a layer.

The radius attribute controls the radius in meters of the cylinder.

The centralAngle attribute controls the angle in radians of the visible section of the cylinder. It grows symmetrically around the 0 angle.

The aspectRatio attribute controls the ratio of the visible cylinder section. It is the ratio of the width of the visible section of the cylinder divided by its height. The width is calculated by multiplying the radius with the centralAngle.

description of the parameters of a cylinder layer

When initializing an XRCylinderLayer layer with an XRCylinderLayerInit init, the user agent MUST run the following steps:
  1. Initialize layer’s radius to init’s radius.

  2. Initialize layer’s centralAngle to init’s centralAngle.

  3. Initialize layer’s aspectRatio to init’s aspectRatio.

  4. Let layer’s space be the init’s space.

  5. Initialize layer’s transform as follows:

    If init’s transform is set
    Let layer’s transform be a new XRRigidTransform in the relevant realm of layer initialized with position and orientation of init’s transform.
    Otherwise
    Let layer’s transform be a new XRRigidTransform in the relevant realm of layer initialized with a DOMPointInit position of { x: 0.0, y: 0.0, z: 0.0, w: 1.0 }.
  6. Initialize layer’s isStatic to init’s isStatic

The onredraw attribute is an Event handler IDL attribute for the redraw event type.

3.7. XREquirectLayer

An XREquirectLayer renders a layer where the XR Compositor MUST map an equirectangular coded data onto the inside of a sphere.

representation of an equirect layer

this section needs clarification

[Exposed=Window] interface XREquirectLayer : XRCompositionLayer {
  attribute XRSpace space;
  attribute XRRigidTransform transform;

  attribute float radius;
  attribute float centralHorizontalAngle;
  attribute float upperVerticalAngle;
  attribute float lowerVerticalAngle;

  // Events
  attribute EventHandler onredraw;
};

The transform attribute sets and returns the offset and orientation relative to space. The transform attribute and the space establish the spatial relationship of the layer within the user’s physical environment.

The radius attribute is the non-negative radius in meters of the sphere. Values of zero or infinity are treated as an infinite sphere.

Setting radius to a value less than 0 will set it to 0.

The centralHorizontalAngle, upperVerticalAngle and lowerVerticalAngle attributes set and return how the texture is mapped to the sphere.

Setting centralHorizontalAngle to a value less than 0 will set it to 0 and setting it to a value higher than 2π will set it to 2π.

Setting upperVerticalAngle or lowerVerticalAngle to a value less than -π/2 will set it to -π/2 and setting it to a value higher than π/2 will set it to π/2.

description of the parameters of an equirect layer

When assigning an XRSpace to the space attribute, first run the following steps.

When setting the space on an equirect layer with XRSpace space and XREquirectLayer layer, the user agent MUST run the following steps to validate if the space is valid:

  1. If init’s space is not an instance of type XRReferenceSpace, throw TypeError and abort these steps.

  2. If init’s space has a type of "viewer", throw TypeError and abort these steps.

  3. Run setting the space on a layer with space and layer.

When initializing an XREquirectLayer layer with an XREquirectLayerInit init, the user agent MUST run the following steps:
  1. Initialize layer’s radius to init’s radius.

  2. Initialize layer’s centralHorizontalAngle to init’s centralHorizontalAngle.

  3. Initialize layer’s upperVerticalAngle to init’s upperVerticalAngle.

  4. Initialize layer’s lowerVerticalAngle to init’s lowerVerticalAngle.

  5. Let layer’s space be the init’s space.

  6. Initialize layer’s transform as follows:

    If init’s transform is set
    Let layer’s transform be a new XRRigidTransform in the relevant realm of layer initialized with position and orientation of init’s transform.
    Otherwise
    Let layer’s transform be a new XRRigidTransform in the relevant realm of layer.
  7. Initialize layer’s isStatic to init’s isStatic

The onredraw attribute is an Event handler IDL attribute for the redraw event type.

3.8. XRCubeLayer

A XRCubeLayer renders a layer where the XR Compositor renders directly from a cubemap.

representation of a cube layer

this section needs clarification

[Exposed=Window] interface XRCubeLayer : XRCompositionLayer {
  attribute XRSpace space;
  attribute DOMPointReadOnly orientation;

  // Events
  attribute EventHandler onredraw;
};

The orientation attribute sets and returns the orientation relative to the space attribute. The orientation and space attributes establish the spatial relationship of the layer within the user’s physical environment. When placing the XRCubeLayer only the orientation of the space is considered. The cube layer will always be rendered with the view point at the center.

When assigning an XRSpace to the space attribute, first run the following steps.

When setting the space on an cube layer with XRSpace space and XRCubeLayer layer, the user agent MUST run the following steps to validate if the space is valid:

  1. If init’s space is not an instance of type XRReferenceSpace, throw TypeError and abort these steps.

  2. If init’s space has a type of "viewer", throw TypeError and abort these steps.

  3. Run setting the space on a layer with space and layer.

The onredraw attribute is an Event handler IDL attribute for the redraw event type.

4. Spaces

XRProjectionLayer and XRWebGLLayer don’t have associated an XRSpace because they render to the full frame.

XRCubeLayer and XREquirectLayer MUST only support XRReferenceSpaces that are not of type "viewer".

XRQuadLayer and XRCylinderLayer MUST support all XRSpace types.

Generally, developers should not use of "viewer" space to stabilize layers, as this will almost always defeat positional or rotational reprojection and result in a loss in stability of the rendered content relative to the world. The exception being small UI elements like a gaze cursor or targeting reticle.

Following are some best practices of spaces to use with a layer type:

5. Rendering

5.1. XRSubImage

The XRSubImage object represents what viewport of the GPU texture to use.
[Exposed=Window] interface XRSubImage {
  [SameObject] readonly attribute XRViewport viewport;
};

NOTE: this class is designed to accomodate future extensions

The viewport attribute returns the XRViewport to use when rendering the sub image.

5.2. XRWebGLSubImage

The XRWebGLSubImage object is used during rendering of the layer.
[Exposed=Window] interface XRWebGLSubImage : XRSubImage {
  [SameObject] readonly attribute WebGLTexture colorTexture;
  [SameObject] readonly attribute WebGLTexture? depthStencilTexture;
  readonly attribute unsigned long? imageIndex;
  readonly attribute unsigned long textureWidth;
  readonly attribute unsigned long textureHeight;
};

The colorTexture attribute returns the color opaque texture for the XRCompositionLayer.

The depthStencilTexture attribute returns the depth/stencil opaque texture for the XRCompositionLayer. If the layer was created without depth/stencil, this attribute returns null.

The imageIndex attribute returns the offset into the texture array. Valid only for layers that were requested with texture-array.

The textureWidth and textureHeight attributes return the width and height in pixels of the GL attachments, respectively.

5.3. XRTextureType

The XRTextureType enum defines what type of texture is allocated.
enum XRTextureType {
  "texture",
  "texture-array"
};

6. GPU layer and view creation

6.1. Overview

When a layer is created it is backed by a GPU resource, typically a texture, provided by one of the Web platform’s graphics APIs. In order to specify which API is providing the layer’s GPU resources an XRWebGLBinding for the API in question must be created. Each graphics API may have unique requirements that must be satisfied before a context can be used in the creation of a layer. For example, a WebGLRenderingContext must have its xrCompatible flag set prior to being passed to the constructor of the XRWebGLBinding instance.

Any interaction between the XRSession the graphics API, such as allocating or retrieving textures, will go through this XRWebGLBinding instance, and the exact mechanics of the interaction will typically be API specific. This allows the rest of the WebXR API to be graphics API agnostic and more easily adapt to future advances in rendering techniques.

Once an XRWebGLBinding instance has been acquired, it can be used to create a variety of XRCompositionLayer. Any layers created by that instance will then be able to query the associated GPU resources each frame, generally expected to be the native API’s texture interface.

The various layer types are created with the create____Layer series of methods on the XRWebGLBinding instance. Information about the graphics resources required, such as whether or not to allocate a depth buffer or alpha channel, are passed in at layer creation time and will be immutable for the lifetime of the layer. The method will return the associated XRCompositionLayer type.

Some layer types may not be supported by the XRSession. If a layer type isn’t supported the method will throw an exception. XRProjectionLayer MUST be supported by all XRSessions.

6.2. Opaque textures

When using WebXR GPU layers, the XRWebGLBinding object will return instances of an opaque texture for the color and depth/stencil attachments.

An opaque texture functions identically to a standard WebGLTexture with the following changes:

The buffers attached to an opaque texture MUST be cleared to the values in the table below during the processing of the first call to getViewSubImage() or getSubImage() in each XR animation frame.

Buffer Clear Value
Color (0, 0, 0, 0)
Depth 1.0
Stencil 0

If the opaque texture was created with 2 or more mipLevels, the author SHOULD populate all the mip levels. The user agent MUST NOT assume that it should create the mip levels.

NOTE: the opaque textures are allocated when the layer is contructed using the allocate color textures and allocate depth textures algoritms. The side effect of this pre-allocation is that calling getSubImage() and getViewSubImage() with the same parameters will always return the same texture objects.

NOTE: Changes to the dimensions or format of the opaque textures are not allowed. GL commands may only alter the texel values and texture parameters. Using any of the following commands with the WebGLTexture will result in an INVALID_OPERATION error being generated, even if it does not affect the dimensions or format: TexImage*, CompressedTexImage*, CopyTexImage* and TexStorage*. The "Immutable-Format Texture Images" section in the OpenGL ES 3.0 spec defines these limitations in more detail.

Allocation of the resources for layers (such as memory) MUST be done through the same mechanism as WebGL.

6.3. XRProjectionLayerInit

The XRProjectionLayerInit dictionary represents a set of configurable values that describe how an XRProjectionLayer is initialized.
dictionary XRProjectionLayerInit {
  XRTextureType textureType = "texture";
  GLenum colorFormat = 0x1908; // RGBA
  GLenum depthFormat = 0x1902; // DEPTH_COMPONENT
  double scaleFactor = 1.0;
};

The textureType attribute defines the type of texture that the layer will have.

The colorFormat attribute defines the data type of the color texture data.

This is the list of color formats for projection layers that the XR Compositor MUST support:

For WebGL2 contexts these additional formats are supported:

The depthFormat attribute defines the data type of the depth texture data. If depthFormat is 0 the layer will not provide a depth/stencil texture.

This is the list of depth formats for projection layers that the XR Compositor MUST support:

For WebGLRenderingContext contexts with the 'WEBGL_depth_texture' extension enabled or WebGL2 contexts:

If the extension was not enabled, the request for a depth texture is ignored.

NOTE: this could be confusing to authors because they might expect a depth texture. If possible, provide a warning with the reason why the texture was not created.

For WebGL2RenderingContext contexts these additional formats are supported:

The scaleFactor attribute defines the value that the session’s recommended WebGL framebuffer resolution MUST be multiplied by determining the resolution of the layer’s attachments.

NOTE: the XRProjectionLayerInit dictionary does not have support to configure mipLevels like XRLayerInit. If a user agent wants to support mipmapping on projection layers, it is free to allocate the texture with mips. In that case the user agent (and not the author) is responsible for generating all the mip levels.

6.4. XRLayerInit

The XRLayerInit dictionary represents a set of common configurable values for XRQuadLayer, XRCylinderLayer, XREquirectLayer and XRCubeLayer .
dictionary XRLayerInit {
  required XRSpace space;
  GLenum colorFormat = 0x1908; // RGBA
  GLenum? depthFormat;
  unsigned long mipLevels = 1;
  required unsigned long viewPixelWidth;
  required unsigned long viewPixelHeight;
  XRLayerLayout layout = "mono";
  boolean isStatic = false;
};

The space attribute defines the spatial relationship with the user’s physical environment.

The colorFormat attribute defines the data type of the color texture data.

This is the list of color formats for non-projection layers that the XR Compositor MUST support:

For WebGL2 contexts these additional formats are supported:

For contexts with the 'WEBGL_compressed_texture_etc' extension enabled these additional formats are supported:

For contexts with the 'WEBGL_compressed_texture_astc' extension enabled all the formats of that extension are supported.

The depthFormat attribute defines the data type of the depth texture data. If depthFormat is not supplied, the layer will not provide a depth/stencil texture.

This is the list of depth formats for non-projection layers that the XR Compositor MUST support:

For WebGLRenderingContext contexts with the 'WEBGL_depth_texture' extension enabled or WebGL2 contexts:

For WebGL2RenderingContext contexts these additional formats are supported:

The mipLevels attribute defines the desired number of mip levels in the color and texture data. If the user agent can’t create the requested number, it can create less. Authors MUST query mipLevels to determine the actual number of mip levels.

The viewPixelWidth and viewPixelHeight attributes define the rectangular dimensions of the XRCompositionLayer.

The layout attribute defines the layout of the layer.

6.5. XRQuadLayerInit

The XRQuadLayerInit dictionary represents a set of configurable values that describe how an XRQuadLayer is initialized.

dictionary XRQuadLayerInit : XRLayerInit {
  XRTextureType textureType = "texture";
  XRRigidTransform? transform;
  float width = 1.0;
  float height = 1.0;
};

6.6. XRCylinderLayerInit

The XRCylinderLayerInit dictionary represents a set of configurable values that describe how an XRCylinderLayer is initialized.

dictionary XRCylinderLayerInit : XRLayerInit {
  XRTextureType textureType = "texture";
  XRRigidTransform? transform;
  float radius = 2.0;
  float centralAngle = 0.78539;
  float aspectRatio = 2.0;
};

The default value of centralAngle is π / 4.

6.7. XREquirectLayerInit

The XREquirectLayerInit dictionary represents a set of configurable values that describe how an XREquirectLayer is initialized.

dictionary XREquirectLayerInit : XRLayerInit {
  XRTextureType textureType = "texture";
  XRRigidTransform? transform;
  float radius = 0;
  float centralHorizontalAngle = 6.28318;
  float upperVerticalAngle = 1.570795;
  float lowerVerticalAngle = -1.570795;
};

The default value of centralHorizontalAngle is 2π. The default value of upperVerticalAngle is π/2. The default value of lowerVerticalAngle is -π/2.

6.8. XRCubeLayerInit

The XRCubeLayerInit dictionary represents a set of configurable values that describe how an XRCubeLayer is initialized.

dictionary XRCubeLayerInit : XRLayerInit {
  DOMPointReadOnly? orientation;
};

6.9. XRWebGLBinding

The XRWebGLBinding object is used to create layers that have a GPU backend.
[Exposed=Window] interface XRWebGLBinding {
  constructor(XRSession session, XRWebGLRenderingContext context);

  readonly attribute double nativeProjectionScaleFactor;
  readonly attribute boolean usesDepthValues;

  XRProjectionLayer createProjectionLayer(optional XRProjectionLayerInit init = {});
  XRQuadLayer createQuadLayer(optional XRQuadLayerInit init = {});
  XRCylinderLayer createCylinderLayer(optional XRCylinderLayerInit init = {});
  XREquirectLayer createEquirectLayer(optional XREquirectLayerInit init = {});
  XRCubeLayer createCubeLayer(optional XRCubeLayerInit init = {});

  XRWebGLSubImage getSubImage(XRCompositionLayer layer, XRFrame frame, optional XREye eye = "none");
  XRWebGLSubImage getViewSubImage(XRProjectionLayer layer, XRView view);
};

the init dictionaries shouldn’t be optional. This is bikeshed issue 1566.

Each XRWebGLBinding has a context object of type XRWebGLRenderingContext which is an instance of either a WebGLRenderingContext or a WebGL2RenderingContext.

Each XRWebGLBinding has an associated session, which is the XRSession it was created with.

NOTE: It is possible to create more than one XRWebGLBinding. Any layer created with an instance of XRWebGLBinding can be used with another instance of XRWebGLBinding as long as both were created with the same session and the same context. The lifetime of layers or instances of XRWebGLSubImage is not tied to the lifetime of the XRWebGLBinding that created them.

Each XRCompositionLayer created through XRWebGLBinding has an internal colorTextures array which is an array of WebGLTextures for color textures and an internal depthStencilTextures which is an array of opaque textures for depth/stencil textures.

Each XRProjectionLayer created through XRWebGLBinding has an internal colorTextures for secondary views array which is an array of opaque textures for color textures and an internal depthStencilTextures for secondary views array which is an array of opaque textures for depth/stencil textures that are used to render the secondary views.

The XRWebGLBinding(session, context) constructor MUST perform the following steps when invoked:

  1. Let binding be a new XRWebGLBinding in the relevant realm of session.

  2. If session’s ended value is true, throw an InvalidStateError and abort these steps.

  3. If context is lost, throw an InvalidStateError and abort these steps.

  4. If session is not an immersive session, throw an InvalidStateError and abort these steps.

  5. If context’s XR compatible boolean is false, throw an InvalidStateError and abort these steps.

  6. Initialize binding’s context to context.

  7. Initialize binding’s session to session.

  8. Return binding.

The nativeProjectionScaleFactor function returns the value that the session’s recommended WebGL framebuffer resolution MUST be multiplied by to yield the session’s native WebGL framebuffer resolution.

special case UA behavior if the size causes the layout to change (ie if the requested width exceeds a limit with "stereo-left-right")

The usesDepthValues attribute, if false, indicates that the XR Compositor MUST NOT make use of values if there is a depth buffer attachment. When the attribute is true it indicates that the content of the depth buffer attachment will be used by the XR Compositor and is expected to be representative of the scene rendered into the layer.

To determine the layout attribute using an XRTextureType textureType, an XRWebGLRenderingContext context and an XRLayerLayout layout, the user agent MUST run the following steps:

  1. If context is not an WebGL2RenderingContext and textureType is "texture-array", throw TypeError and abort these steps.

  2. If textureType is "texture-array" and not all of the session’s views in the list of views have the same recommended WebGL texture resolution, throw a NotSupportedError and abort these steps.

  3. If layout is "mono", return layout and abort these steps.

  4. If layout is "default", run the following steps:

    1. If the size of list of views is 1, return "mono" and abort these steps.

    2. If textureType is "texture-array", return layout and abort these steps.

  5. If layout is "default" or "stereo" and textureType is "texture", run the following steps:

    1. If the user agent prefers "stereo-left-right" layout, return "stereo-left-right" and abort these steps.

    2. If the user agent prefers "stereo-top-bottom" layout, return "stereo-top-bottom" and abort these steps.

  6. return layout.

To determine the maximum scalefactor using an XRSession session, an XRWebGLRenderingContext context and an XRLayerLayout layout, the user agent MUST run the following steps:

  1. Let largest width be the largest width of the recommended WebGL texture resolution from the session’s list of views excluding the secondary views.

  2. Let largest height be the largest height of the recommended WebGL texture resolution from the session’s list of views excluding the secondary views.

  3. If layout is "stereo-left-right" layout, multiply largest width by 2.

  4. If layout is "stereo-top-bottom" layout, multiply largest height by 2.

  5. Let largest view dimension be the largest of largest width or largest height.

  6. Let largest texture dimension be the largest dimension of a WebGLTexture created by context.

  7. return largest texture dimension divided by largest view dimension.

To allocate color textures for projection layers using an XRProjectionLayer layer, an XRTextureType textureType, a GLenum textureFormat and a float scaleFactor, the user agent MUST run the following steps:

  1. Let array be a new array in the relevant realm of context.

  2. Let context be layer’s context.

  3. Let session be layer’s session.

  4. Let numViews be the number of the session’s list of views excluding the secondary views.

  5. Let view be the first entry in the session’s list of views that is not a secondary views.

  6. Let width be the width of view’s recommended WebGL texture resolution multiplied by scaleFactor.

  7. Let height be the height of view’s recommended WebGL texture resolution multiplied by scaleFactor.

  8. If textureFormat is not in the list of color formats for projection layers, throw a NotSupportedError and abort these steps.

  9. If layer’s layout is "mono" or "default":

    If textureType is "texture-array":
    If the session’s views in the list of views don’t all have the same recommended WebGL texture resolution excluding the secondary views, throw a NotSupportedError and abort these steps.
    Initialize array with 1 new instance of an opaque texture in the relevant realm of context created as a TEXTURE_2D_ARRAY texture with numViews layers using context, textureFormat, width and height.
    Return array and abort these steps.
    Otherwise
    For each view in the session’s list of views:
    1. If view is a secondary view, continue.

    2. Let width be the width of view’s recommended WebGL texture resolution multiplied by scaleFactor.

    3. Let height be the height of view’s recommended WebGL texture resolution multiplied by scaleFactor.

    4. let texture be a new instance of an opaque texture in the relevant realm of context created as a TEXTURE_2D texture with context, textureFormat, width and height.

    5. Append texture to array.

    Return array and abort these steps.
  10. If the session’s views in the list of views don’t all have the same recommended WebGL texture resolution excluding the secondary views, throw a NotSupportedError and abort these steps.

  11. If layer’s layout is stereo-left-right, initialize array with 1 new instance of opaque texture in the relevant realm of context created as a textureType texture using context , textureFormat, numViews multiplied by width and height.

  12. If layer’s layout is stereo-top-bottom, initialize array with 1 new instance of opaque texture in the relevant realm of context created as a textureType texture using context , textureFormat, width and numViews multiplied by height.

  13. return array.

To allocate depth textures for projection layers using an XRProjectionLayer layer, an XRTextureType textureType, a GLenum textureFormat and a float scaleFactor, the user agent MUST run the following steps:

  1. Let array be a new array in the relevant realm of context.

  2. Let context be layer’s context.

  3. Let session be layer’s session.

  4. If textureFormat is 0, return array and abort these steps.

  5. If context is a WebGLRenderingContext and the WEBGL_depth_texture extension is not enabled in context, return array and abort these steps.

  6. If textureFormat is not in the list of depth formats for projection layers, throw a NotSupportedError and abort these steps.

  7. let numViews be the number of the session’s list of views excluding the secondary views.

  8. Let view be the first entry in the session’s list of views that is not a secondary view.

  9. Let width be the width of view’s recommended WebGL texture resolution multiplied by scaleFactor.

  10. Let height be the height of view’s recommended WebGL texture resolution multiplied by scaleFactor.

  11. If layer’s layout is "mono" or "default":

    If textureType is "texture-array":
    Initialize array with 1 new instance of an opaque texture in the relevant realm of context created as a TEXTURE_2D_ARRAY texture with numViews layers using context, textureFormat, stencil, width and height.
    Return array and abort these steps.
    Otherwise
    For each view in the session’s list of views:
    1. If view is a secondary view, continue.

    2. Let width be the width of view’s recommended WebGL texture resolution multiplied by scaleFactor.

    3. Let height be the height of view’s recommended WebGL texture resolution multiplied by scaleFactor.

    4. let texture be a new instance of an opaque texture in the relevant realm of context created as a TEXTURE_2D texture with context, textureFormat, stencil, width and height.

    5. Append texture to array.

    Return array and abort these steps.
  12. If the session’s views in the list of views don’t all have the same recommended WebGL texture resolution excluding the secondary views, throw a NotSupportedError and abort these steps.

  13. If layer’s layout is stereo-left-right, initialize array with 1 new instance of an opaque texture in the relevant realm of context created as a textureType texture using context, textureFormat, stencil, numViews multiplied by width and height.

  14. If layer’s layout is stereo-top-bottom, initialize array with 1 new instance of an opaque texture in the relevant realm of context created as a textureType texture using context, textureFormat, stencil, width and numViews multiplied by height.

  15. return array.

To allocate the color textures for the secondary views using an XRProjectionLayer layer, an XRTextureType textureType, a GLenum textureFormat and a float scaleFactor, the user agent MUST run the following steps:

  1. Let context be layer’s context.

  2. Let session be layer’s session.

  3. Let array be a new array in the relevant realm of context.

  4. If textureFormat is not in the list of color formats for projection layers, throw a NotSupportedError and abort these steps.

  5. For each view in the session’s list of views:

    1. If view is not a secondary view, continue.

    2. Let width be the width of view’s recommended WebGL texture resolution multiplied by scaleFactor.

    3. Let height be the height of view’s recommended WebGL texture resolution multiplied by scaleFactor.

    4. Initialize texture as follows:

      If textureType is "texture-array":
      Let texture be a new instance of an opaque texture in the relevant realm of context created as a TEXTURE_2D_ARRAY texture with context, textureFormat, width and height.
      Otherwise
      Let texture be a new instance of an opaque texture in the relevant realm of context created as a TEXTURE_2D texture with context, textureFormat, width and height.
    5. Append texture to array.

  6. Return array and abort these steps.

To allocate the depth textures for the secondary views using an XRProjectionLayer layer, an XRTextureType textureType, a GLenum textureFormat and a float scaleFactor, the user agent MUST run the following steps:

  1. Let context be layer’s context.

  2. Let session be layer’s session.

  3. If textureFormat is 0, return array and abort these steps.

  4. If context is a WebGLRenderingContext and the WEBGL_depth_texture extension is not enabled in context, return array and abort these steps.

  5. If textureFormat is not in the list of depth formats for projection layers, throw a NotSupportedError and abort these steps.

  6. Let array be a new array in the relevant realm of context.

  7. For each view in the session’s list of views:

    1. If view is not a secondary view, continue.

    2. Let width be the width of view’s recommended WebGL texture resolution multiplied by scaleFactor.

    3. Let height be the height of view’s recommended WebGL texture resolution multiplied by scaleFactor.

    4. Initialize texture as follows:

      If textureType is "texture-array":
      Let texture be a new instance of an opaque texture in the relevant realm of context created as a TEXTURE_2D_ARRAY texture with context, textureFormat, stencil, width and height.
      Otherwise
      Let texture be a new instance of an opaque texture in the relevant realm of context created as a TEXTURE_2D texture with context, textureFormat, stencil, width and height.
    5. Append texture to array.

  8. Return array and abort these steps.

the scaleFactor needs to be recalculated for the secondary views.

To allocate color textures using an XRCompositionLayer layer, an XRTextureType textureType and an XRLayerInit init, the user agent MUST run the following steps:

  1. let array be a new array in the relevant realm of context.

  2. let context be layer’s context.

  3. If init’s colorFormat is not in the list of color formats for non-projection layers, throw a NotSupportedError and abort these steps.

  4. If init’s mipLevels is smaller than 1, throw a InvalidStateError and abort these steps.

  5. If init’s mipLevels is larger than 1 and viewPixelWidth and viewPixelHeight are not powers of 2, throw a InvalidStateError and abort these steps

  6. If layer’s layout is "mono":

    If textureType is "texture-array":
    Initialize array with 1 new instance of an opaque texture in the relevant realm of this context created as a TEXTURE_2D_ARRAY texture with 1 internal texture using context and init’s colorFormat, mipLevels, viewPixelWidth and viewPixelHeight values.
    Otherwise
    Initialize array with 1 new instance of an opaque texture in the relevant realm of context created as a TEXTURE_2D texture with context and init’s colorFormat, mipLevels, viewPixelWidth and viewPixelHeight values.
  7. If layer’s layout is "stereo":

    If textureType is "texture-array":
    Initialize array with 1 new instance of an opaque texture in the relevant realm of context created as a TEXTURE_2D_ARRAY texture with 2 layers using context and init’s colorFormat, mipLevels, viewPixelWidth and viewPixelHeight values.
    Return array and abort these steps.
    Otherwise
    Initialize array with 2 new instances of an opaque texture in the relevant realm of context created as a TEXTURE_2D texture with context and init’s colorFormat, mipLevels, viewPixelWidth and viewPixelHeight values.
    Return array and abort these steps.
  8. If layer’s layout is stereo-left-right, initialize array with 1 new instance of an opaque texture in the relevant realm of context created as a textureType texture using context and init’s colorFormat, mipLevels, double of viewPixelWidth and viewPixelHeight values.

  9. If layer’s layout is stereo-top-bottom, initialize array with 1 new instance of an opaque texture in the relevant realm of context created as a textureType texture using context and init’s colorFormat, mipLevels, viewPixelWidth and double of viewPixelHeight values.

  10. return array.

To allocate depth textures using an XRCompositionLayer layer, an XRTextureType textureType and an XRLayerInit init, the user agent MUST run the following steps:

  1. let array be a new array in the relevant realm of context.

  2. let context be layer’s context.

  3. If init’s depthFormat is not set, return array and abort these steps.

  4. If init’s depthFormat is not in the list of depth formats for non-projection layers, throw a NotSupportedError and abort these steps.

  5. If init’s mipLevels is smaller than 1, throw a InvalidStateError and abort these steps.

  6. If init’s mipLevels is larger than 1 and viewPixelWidth and viewPixelHeight are not powers of 2, throw a InvalidStateError and abort these steps.

  7. If layer’s layout is "mono":

    If textureType is "texture-array":
    Initialize array with 1 new instance of an opaque texture in the relevant realm of context created as a TEXTURE_2D_ARRAY texture with 1 internal texture using context and init’s depthFormat, mipLevels, viewPixelWidth and viewPixelHeight values.
    Otherwise
    Initialize array with 1 new instance of an opaque texture in the relevant realm of context created as a TEXTURE_2D texture with context and init’s depthFormat, mipLevels, viewPixelWidth and viewPixelHeight values.
  8. If layer’s layout is "stereo":

    If textureType is "texture-array":
    Initialize array with 1 new instance of an opaque texture in the relevant realm of context created as a TEXTURE_2D_ARRAY texture with 2 layers using context and init’s depthFormat, mipLevels, viewPixelWidth and viewPixelHeight values.
    Return array and abort these steps.
    Otherwise
    Initialize array with 2 new instances of an opaque texture in the relevant realm of context created as a TEXTURE_2D texture with context and init’s depthFormat, mipLevels, viewPixelWidth and viewPixelHeight values.
    Return array and abort these steps.
  9. If layer’s layout is stereo-left-right, initialize array with 1 new instance of an opaque texture in the relevant realm of context created as a textureType texture using context and init’s depthFormat, mipLevels, double of viewPixelWidth and viewPixelHeight values.

  10. If layer’s layout is stereo-top-bottom, initialize array with 1 new instance of an opaque texture in the relevant realm of context created as a textureType texture using context and init’s depthFormat, mipLevels, viewPixelWidth and double of viewPixelHeight values.

  11. return array.

The createProjectionLayer(optional XRProjectionLayerInit init) method creates a new XRProjectionLayer layer.

When this method is invoked, the user agent MUST run the following steps:

  1. Let session be this session.

  2. Let context be this context.

  3. Let layer be a new XRProjectionLayer in the relevant realm of this.

  4. If session’s ended value is true, throw InvalidStateError and abort these steps.

  5. If context is lost, throw InvalidStateError and abort these steps.

  6. Run intialize a composition layer on layer with session and context.

  7. Initialize layer’s isStatic to false.

  8. Initialize layer’s ignoreDepthValues as follows:

    If init’s depthFormat is false and the XR Compositor will make use of depth values
    Initialize layer’s ignoreDepthValues to false
    Otherwise
    Initialize layer’s ignoreDepthValues to true
  9. Initialize layer’s fixedFoveation to 0.

  10. let layout be the result of determining the layout attribute with init’s textureType, context and "default".

  11. Let maximum scalefactor be the result of determining the maximum scalefactor with session, context and layout.

  12. If scaleFactor is larger than maximum scalefactor, set scaleFactor to maximum scalefactor.

  13. Initialize layer’s layout to layout.

  14. Initialize layer’s needsRedraw to true.

  15. let layer’s colorTextures be the result of allocating color textures for projection layers with layer, init’s textureType, init’s colorFormat and init’s scaleFactor.

  16. let layer’s depthStencilTextures be the result of allocating depth textures for projection layers with layer, init’s textureType, init’s depthFormat and init’s scaleFactor.

  17. Initialize the colortextures for secondary views as follows:

    If the session was created with "secondary-views" enabled
    Let colortextures for secondary views be the result of allocate the color textures for the secondary views with layer, init’s textureType, init’s colorFormat and init’s scaleFactor.
    Otherwise
    Let colortextures for secondary views be null.
  18. Initialize the depthstenciltextures for secondary views as follows:

    If the session was created with "secondary-views" enabled
    Let depthstenciltextures for secondary views be the result of allocate the depth textures for the secondary views with layer, init’s textureType, init’s depthFormat and init’s scaleFactor.
    Otherwise
    Let depthstenciltextures for secondary views be null.
  19. If the XR Compositor knows that it will be unable to create the resources for the layer for any reason, throw an OperationError and abort these steps.

  20. Return layer.

The createQuadLayer(XRQuadLayerInit init) method creates a new XRQuadLayer layer.

When this method is invoked, the user agent MUST run the following steps:

  1. Let session be this session.

  2. If session was not created with "layers" enabled, throw a NotSupportedError and abort these steps.

  3. Let context be this context.

  4. If session’s ended value is true, throw InvalidStateError and abort these steps.

  5. If context is lost, throw InvalidStateError and abort these steps.

  6. If layout is "default", throw TypeError and abort these steps.

  7. Let layer be a new XRQuadLayer in the relevant realm of this.

  8. Run intialize a composition layer on layer with session and context.

  9. Run initialize a quad layer with layer and init.

  10. let layout be the result of determining the layout attribute with init’s textureType, context and init’s layout.

  11. Initialize layer’s layout to layout.

  12. Initialize layer’s needsRedraw to true.

  13. let layer’s colorTextures be the result of allocating color textures with layer, init’s textureType and init.

  14. let layer’s depthStencilTextures be the result of allocating depth textures with layer, init’s textureType and init.

  15. If the XR Compositor knows that it will be unable to create the resources for the layer for any reason, throw an OperationError and abort these steps.

  16. return layer.

The createCylinderLayer(XRCylinderLayerInit init) method creates a new XRCylinderLayer layer.

When this method is invoked, the user agent MUST run the following steps:

  1. Let session be this session.

  2. If session was not created with "layers" enabled, throw a NotSupportedError and abort these steps.

  3. Let context be this context.

  4. If session’s ended value is true, throw InvalidStateError and abort these steps.

  5. If context is lost, throw InvalidStateError and abort these steps.

  6. If layout is "default", throw TypeError and abort these steps.

  7. Let layer be a new XRCylinderLayer in the relevant realm of this.

  8. Run intialize a composition layer on layer with session and context.

  9. Run initialize a cylinder layer with layer and init.

  10. let layout be the result of determining the layout attribute with init’s textureType, context and init’s layout.

  11. Initialize layer’s layout to layout.

  12. Initialize layer’s needsRedraw to true.

  13. let layer’s colorTextures be the result of allocating color textures with layer, init’s textureType and init.

  14. let layer’s depthStencilTextures be the result of allocating depth textures with layer, init’s textureType and init.

  15. If the XR Compositor knows that it will be unable to create the resources for the layer for any reason, throw an OperationError and abort these steps.

  16. return layer.

The createEquirectLayer(XREquirectLayerLayerInit init) method creates a new XREquirectLayer layer.

When this method is invoked, the user agent MUST run the following steps:

  1. Let session be this session.

  2. If session was not created with "layers" enabled, throw a NotSupportedError and abort these steps.

  3. Let context be this context.

  4. If session’s ended value is true, throw InvalidStateError and abort these steps.

  5. If context is lost, throw InvalidStateError and abort these steps.

  6. If layout is "default", throw TypeError and abort these steps.

  7. If init’s space is not an instance of type XRReferenceSpace, throw TypeError and abort these steps.

  8. If init’s space has a type of "viewer", throw TypeError and abort these steps.

  9. Let layer be a new XREquirectLayer in the relevant realm of this.

  10. Run intialize a composition layer on layer with session and context.

  11. Run initialize a equirect layer with layer and init.

  12. let layout be the result of determining the layout attribute with init’s textureType, context and init’s layout.

  13. Initialize layer’s layout to layout.

  14. Initialize layer’s needsRedraw to true.

  15. let layer’s colorTextures be the result of allocating color textures with layer, init’s textureType and init.

  16. let layer’s depthStencilTextures be the result of allocating depth textures with layer, init’s textureType and init.

  17. If the XR Compositor knows that it will be unable to create the resources for the layer for any reason, throw an OperationError and abort these steps.

  18. return layer.

The createCubeLayer(XRCubeLayerInit init) method creates a new XRCubeLayer layer.

When this method is invoked, the user agent MUST run the following steps:

  1. Let session be this session.

  2. If session was not created with "layers" enabled, throw a NotSupportedError and abort these steps.

  3. Let context be this context.

  4. If session’s ended value is true, throw InvalidStateError and abort these steps.

  5. If context is not a WebGL2RenderingContext context, throw InvalidStateError and abort these steps.

  6. If context is lost, throw InvalidStateError and abort these steps.

  7. If init’s space is not an instance of type XRReferenceSpace, throw TypeError and abort these steps.

  8. If init’s space has a type of "viewer", throw TypeError and abort these steps.

  9. Let layer be a new XRCubeLayer in the relevant realm of this.

  10. Run intialize a composition layer on layer with session and context.

  11. Let layer’s space be the init’s space.

  12. Initialize layer’s isStatic to init’s isStatic

  13. Initialize layer’s orientation as follows:

    If init’s orientation is set
    Let layer’s orientation be the result of running fromPoint with init’s orientation.
    Otherwise
    Let layer’s orientation be a new DOMPointReadOnly in the relevant realm of this.
  14. let layout be init’s layout.

  15. Initialize layer’s needsRedraw to true.

  16. If layout is "default" or "stereo-left-right" or "stereo-top-bottom", throw TypeError and abort these steps.

  17. Let layer’s colorTextures be a new array in the relevant realm of this XRCubeLayer.

  18. Initialize layer’s colorTextures as follows, based on the value of layout:

    "mono":
    Initialize colorTextures with 1 new instance of an opaque texture in the relevant realm of this XRCubeLayer created as a TEXTURE_CUBE_MAP texture with context and init’s colorFormat, viewPixelWidth and viewPixelHeight values.
    Otherwise
    Initialize colorTextures with 2 new instances of an opaque texture in the relevant realm of this XRCubeLayer created as a TEXTURE_CUBE_MAP texture with context and init’s colorFormat, viewPixelWidth and viewPixelHeight values.
  19. Let layer’s depthStencilTextures be a new array in the relevant realm of this XRCubeLayer.

  20. If init’s depthFormat is set, initialize layer’s depthStencilTextures as follows:

    If context is not a WebGL2RenderingContext and the WEBGL_depth_texture extension is not enabled in context
    Throw TypeError and abort these steps.
    Else if layout is "mono"
    Initialize depthStencilTextures with 1 new instance of an opaque texture in the relevant realm of this XRCubeLayer created as a TEXTURE_CUBE_MAP texture with context and init’s depthFormat, viewPixelWidth and viewPixelHeight values.
    Otherwise
    Initialize depthStencilTextures with 2 new instances of an opaque texture in the relevant realm of this XRCubeLayer created as a TEXTURE_CUBE_MAP texture with context and init’s depthFormat, viewPixelWidth and viewPixelHeight values.
  21. If the XR Compositor knows that it will be unable to create the resources for the layer for any reason, throw an OperationError and abort these steps.

  22. return layer.

Define how cubemap sizes are determined.

How should space be handled. Can you walk to the edge of a cubemap?

determine the initial state of orientation.

To validate the state of the XRWebGLSubImage creation function of an XRWebGLBinding binding with parameters of XRCompositionLayer layer and XRFrame frame, the user agent MUST run the following steps:

  1. If frame’s session is not equal to layer’s session, return false and abort these steps.

  2. If frame’s active boolean is false, return false and abort these steps.

  3. If frame’s animationFrame boolean is false, return false and abort these steps.

  4. If binding’s session is not equal to layer’s session, return false and abort these steps.

  5. If binding’s context is not equal to layer’s context, return false and abort these steps.

  6. If the layer’s colorTextures array is empty or missing, return false and abort these steps.

  7. If the layer’s isStatic is true and layer’s needsRedraw is false, return false and abort these steps.

  8. return true.

To initialize the viewport of an XRViewport viewport with a opaque texture texture, a XRLayerLayout layout, an integer offset and a integer num, the user agent MUST run the following steps:

  1. Set viewport’s x to 0.

  2. Set viewport’s y to 0.

  3. Set viewport’s width to the pixel width of texture.

  4. Set viewport’s height to the pixelh eight of texture.

  5. Update viewport as follows:

    If layout is "stereo-left-right"
    Set viewport’s x to the pixel width of texture multiplied by offset and divided by num.
    Set viewport’s width to the pixel width of subimage’s texture divided by num.
    Else if layout is "stereo-top-bottom"
    Set viewport’s y to the pixel height of texture multiplied by offset and divided by num.
    Set viewport’s height to the pixel height of subimage’s texture divided by num.
The getSubImage(XRCompositionLayer layer, XRFrame frame, optional XREye eye = "none") method creates a new XRWebGLSubImage.

When this method is invoked on an XRWebGLBinding binding, it MUST run the following steps:

  1. Initialize subimage as follows:

    If getSubImage() was called previously with the same binding, layer and eye, the user agent MAY
    Let subimage be the same XRWebGLSubImage object as returned by an earlier call with the same arguments.
    Otherwise
    Let subimage be a new XRWebGLSubImage in the relevant realm of this.
    Let subimage’s viewport be a new XRViewport in the relevant realm of this.
  2. Let session be this session.

  3. If layer is not in the session’s layers array, throw a TypeError and abort these steps.

  4. If layer’s type is XRProjectionLayer, throw a TypeError and abort these steps.

  5. If layer’s layout attribute is "default", throw a TypeError and abort these steps.

  6. Let index be 0.

  7. If layer’s layout attribute is "stereo":

    1. If eye is "none", throw a TypeError and abort these steps.

    2. If eye is "right", set index to 1.

  8. If validate the state of the XRWebGLSubImage creation function with layer and frame is false, throw an InvalidStateError and abort these steps.

  9. Initialize subimage’s imageIndex as follows:

    If the layer was created with a textureType of "texture-array"
    Initialize subimage’s imageIndex with index.
    Otherwise
    Initialize subimage’s imageIndex with 0.
  10. Initialize subimage’s colorTexture as follows:

    If the layer was created with a textureType of "texture"
    Initialize subimage’s colorTexture with the element at offset index of the layer’s colorTextures array.
    Otherwise
    Initialize subimage’s colorTexture with the first element of the layer’s colorTextures array.
  11. Initialize subimage’s depthStencilTexture as follows:

    If the layer’s depthStencilTextures is an empty array
    Initialize subimage’s depthStencilTexture with null.
    Else the layer was created with a textureType of "texture"
    Initialize subimage’s depthStencilTexture with the element at offset index of the layer’s depthStencilTextures array.
    Otherwise
    Initialize subimage’s depthStencilTexture with the first element of layer’s depthStencilTextures array.
  12. Set subimage’s textureWidth to the pixel width of subimage’s colorTexture.

  13. Set subimage’s textureHeight to the pixel height of subimage’s colorTexture.

  14. Let viewsPerTexture be 1.

  15. If layer’s layout attribute is "stereo-left-right" or "stereo-top-bottom", set viewsPerTexture to 2.

  16. Run initialize the viewport on subimage’s viewport with subimage’s colorTexture, layer’s layout, index and viewsPerTexture.

  17. Queue a task to set needsRedraw to false.

  18. return subimage.

The getViewSubImage(XRProjectionLayer layer, XRView view) method creates a new XRWebGLSubImage.

When this method is invoked on an XRWebGLBinding binding, it MUST run the following steps:

  1. Initialize subimage as follows:

    If getViewSubImage() was called previously with the same binding, layer and view, the user agent MAY
    Let subimage be the same XRWebGLSubImage object as returned by an earlier call with the same arguments.
    Otherwise
    Let subimage be a new XRWebGLSubImage in the relevant realm of this.
    Let subimage’s viewport be a new XRViewport in the relevant realm of this.
  2. Let frame be view’s frame.

  3. Let session be this session.

  4. If validate the state of the XRWebGLSubImage creation function with layer and frame is false, throw an InvalidStateError and abort these steps.

  5. If layer is not in the session’s layers array, throw a TypeError and abort these steps.

  6. If view’s active flag is false, throw an InvalidStateError and abort these steps.

  7. Initialize index as follows:

    If view is a secondary view from session’s list of views
    Let index be the offset of view’s view in session’s list of views excluding the primary views.
    Otherwise
    Let index be the offset of view’s view in session’s list of views excluding the secondary views.
  8. Initialize subimage’s imageIndex as follows:

    If the layer was created with a textureType of "texture-array":
    Initialize subimage’s imageIndex with index.
    Otherwise
    Initialize subimage’s imageIndex to 0.
  9. Initialize subimage’s colorTexture as follows:

    If view is a secondary view from session’s list of views
    Initialize subimage’s colorTexture with the element at offset index of the layer’s colorTextures for secondary views.
    Else if the layer’s layout is "default" and the layer was created with a textureType of "texture"
    Initialize subimage’s colorTexture with the element at offset index of the layer’s colorTextures array.
    Otherwise
    Initialize subimage’s colorTexture with the first element of the layer’s colorTextures array.
  10. Initialize subimage’s depthStencilTexture as follows:

    If the layer’s depthStencilTextures is an empty array
    Initialize subimage’s depthStencilTexture with null.
    Else if view is a secondary view from session’s list of views
    Initialize subimage’s colorTexture with the element at offset index of the layer’s depthStencilTextures for secondary views.
    Else if the layer’s layout is "default" and the layer was created with a textureType of "texture"
    Initialize subimage’s depthStencilTexture with the element at offset index of the layer’s depthStencilTextures array.
    Otherwise
    Initialize subimage’s depthStencilTexture with the first element of layer’s depthStencilTextures array.
  11. Set subimage’s textureWidth to the pixel width of subimage’s colorTexture.

  12. Set subimage’s textureHeight to the pixel height of subimage’s colorTexture.

  13. Run initialize the viewport on subimage’s viewport with subimage’s colorTexture, layer’s layout, index and the number of the session’s list of views.

  14. Set needsRedraw to false.

  15. return subimage

NOTE: The session should try to defer calls to getSubImage() and getViewSubImage() to the time that the experience starts drawing using WebGL. Typically that would be after the game logic runs. On certain user agents having distinct stages for CPU and GPU dependent code allows them to dynamically optimize system resources.

When an XRLayer is a member of the layers array, it MUST be presented to the immersive XR device immediately after an XR animation frame completes, but only if at least one of the following has occurred since the previous XR animation frame:

Before the opaque framebuffer or colorTexture texture are presented to the immersive XR device the user agent MUST ensure that all rendering operations have been flushed.

7. Video layer creation

7.1. XRMediaLayerInit

The XRMediaLayerInit dictionary represents a set of configurable values that describe how an XRCompositionLayer containing a video is initialized.
dictionary XRMediaLayerInit {
  required XRSpace space;
  XRLayerLayout layout = "mono";
  boolean invertStereo = false;
};

The space attribute defines the spatial relationship with the user’s physical environment.

The layout attribute defines the layout of the video in the XRCompositionLayer.

The invertStereo attribute defines if the natural location of each view in the video should be inverted.

7.2. XRMediaQuadLayerInit

The XRMediaQuadLayerInit dictionary represents a set of configurable values that describe how an XRQuadLayer containing a video is initialized.
dictionary XRMediaQuadLayerInit : XRMediaLayerInit {
  XRRigidTransform? transform;
  float? width;
  float? height;
};

7.3. XRMediaCylinderLayerInit

The XRMediaCylinderLayerInit dictionary represents a set of configurable values that describe how an XRCylinderLayer containing a video is initialized.
dictionary XRMediaCylinderLayerInit : XRMediaLayerInit {
  XRRigidTransform? transform;
  float radius = 2.0;
  float centralAngle = 0.78539;
  float? aspectRatio;
};

7.4. XRMediaEquirectLayerInit

The XRMediaEquirectLayerInit dictionary represents a set of configurable values that describe how an XREquirectLayer containing a video is initialized.
dictionary XRMediaEquirectLayerInit : XRMediaLayerInit {
  XRRigidTransform? transform;
  float radius = 0.0;
  float centralHorizontalAngle = 6.28318;
  float upperVerticalAngle = 1.570795;
  float lowerVerticalAngle = -1.570795;
};

7.5. XRMediaBinding

The XRMediaBinding object is used to create layers that display the content of an HTMLVideoElement.
[Exposed=Window] interface XRMediaBinding {
  constructor(XRSession session);

  XRQuadLayer createQuadLayer(HTMLVideoElement video, optional XRMediaQuadLayerInit init = {});
  XRCylinderLayer createCylinderLayer(HTMLVideoElement video, optional XRMediaCylinderLayerInit init = {});
  XREquirectLayer createEquirectLayer(HTMLVideoElement video, optional XRMediaEquirectLayerInit init = {});
};

the init dictionaries shouldn’t be optional. This is bikeshed issue 1566.

Each XRMediaBinding has an associated session, which is the XRSession it was created with.

NOTE: It is possible to create more than one XRMediaBinding. The lifetime of a layer is not tied to the lifetime of the XRMediaBinding that created it.

Each layer created through XRMediaBinding has an internal HTMLVideoElement media. If the layer is part of the session’s renderState, it will display the current frame of the video. The layer is update at the native framerate of the XR device or the video, whichever is less.

NOTE: only the video frames will be displayed in the layer. Video controls should be implemented by the author and must be drawn in another layer.

more clarification is needed on how the video is blitted to the layers.

When an XRCompositionLayer layer with a HTMLVideoElement media needs to be rendered, the user agent MUST run the following steps:
  1. Let usability be the result of checking the usability of media.

  2. If usability is bad, then fill the layer with opaque black and abort these steps.

  3. Fill the layer with the content of the media element.

add a better algorithm to describe the drawing.

The XRMediaBinding(XRSession session) constructor MUST perform the following steps when invoked:

  1. If session’s ended value is true, throw an InvalidStateError and abort these steps.

  2. If session is not an immersive session, throw an InvalidStateError and abort these steps.

  3. Let binding be a new XRMediaBindingin the relevant realm of session.

  4. Initialize binding’s session to session.

  5. Return binding.

To calculate the aspect ratio of an HTMLVideoElement video and an XRLayerLayout layout, run the following steps:
  1. Let width be the video’s videoWidth.

  2. Let height be the video’s videoHeight.

  3. If layout is "stereo-left-right", divide width by 2.

  4. If layout is "stereo-top-bottom", divide height by 2.

  5. Return width divided by height.

The createQuadLayer(HTMLVideoElement video, XRMediaQuadLayerInit init) method creates a new XRQuadLayer layer.

When this method is invoked, the user agent MUST run the following steps:

  1. Let session be this session.

  2. If session was not created with "layers" enabled, throw a NotSupportedError and abort these steps.

  3. If session’s ended value is true, throw InvalidStateError and abort these steps.

  4. If init’s layout is "default", throw a TypeError and abort these steps.

  5. Let layer be a new XRQuadLayer in the relevant realm of this.

  6. Run intialize a composition layer on layer with session.

  7. Initialize layer’s media to video.

  8. Initialize layer’s needsRedraw to false.

  9. Let aspectRatio be the result of calculate the aspect ratio with video and init’s layout.

  10. If init’s width and height are undefined, set width to 1.

  11. If init’s height is undefined, set height to width divided by aspectRatio.

  12. If init’s width is undefined, set width to height multiplied by aspectRatio.

  13. Run initialize a quad layer with layer and init.

  14. If the XR Compositor knows that it will be unable to create the resources for the layer for any reason, throw an OperationError and abort these steps.

  15. return layer.

The createCylinderLayer(HTMLVideoElement video, XRMediaCylinderLayerInit init) method creates a new XRCylinderLayer layer.

When this method is invoked, the user agent MUST run the following steps:

  1. Let session be this session.

  2. If session was not created with "layers" enabled, throw a NotSupportedError and abort these steps.

  3. If session’s ended value is true, throw InvalidStateError and abort these steps.

  4. If init’s layout is "default", throw a TypeError and abort these steps.

  5. Let layer be a new XRCylinderLayer in the relevant realm of this.

  6. Run intialize a composition layer on layer with session.

  7. Initialize layer’s media to video.

  8. Initialize layer’s needsRedraw to false.

  9. Let aspectRatio be the result of calculate the aspect ratio with video and init’s layout.

  10. If init’s aspectRatio is undefined, set aspectRatio to aspectRatio.

  11. Run initialize a cylinder layer with layer and init.

  12. If the XR Compositor knows that it will be unable to create the resources for the layer for any reason, throw an OperationError and abort these steps.

  13. return layer.

The createEquirectLayer(HTMLVideoElement video, XRMediaEquirectLayerInit init) method creates a new XREquirectLayer layer.

When this method is invoked, the user agent MUST run the following steps:

  1. Let session be this session.

  2. If session was not created with "layers" enabled, throw a NotSupportedError and abort these steps.

  3. If session’s ended value is true, throw InvalidStateError and abort these steps.

  4. If init’s layout is "default", throw a TypeError and abort these steps.

  5. If init’s space is not an instance of type XRReferenceSpace, throw InvalidStateError and abort these steps.

  6. If init’s space has a type of "viewer", throw InvalidStateError and abort these steps.

  7. Let layer be a new XREquirectLayer in the relevant realm of this.

  8. Run intialize a composition layer on layer with session.

  9. Initialize layer’s media to video.

  10. Initialize layer’s needsRedraw to false.

  11. Run initialize a equirect layer with layer and init.

  12. If the XR Compositor knows that it will be unable to create the resources for the layer for any reason, throw an OperationError and abort these steps.

  13. return layer.

define how the XREquirectLayer's parameters affect the video display.

8. Events

8.1. XRLayerEvent

XRLayerEvent is fired to indicate changes to the state of an XRLayer.

[SecureContext, Exposed=Window] interface XRLayerEvent : Event {
  constructor(DOMString type, XRLayerEventInit eventInitDict);
  [SameObject] readonly attribute XRLayer layer;
};

dictionary XRLayerEventInit : EventInit {
  required XRLayer layer;
};

The layer attribute indicates the XRLayer that generated the event.

8.2. Event Types

The user agent MUST provide the following new events. Registration for and firing of the events must follow the usual behavior of DOM4 Events.

The user agent MAY fire a redraw event on the XRLayer object when the underlying resources of a layer are lost or when the XR Compositor can no longer reproject the layer.

The author SHOULD redraw the content of the layer at the next XR animation frame. The event must be of type XRLayerEvent.

9. Depth sorting between layers

By default, the layers array defines the order of the composition of the layers and each layer is drawn on top of the previous layer. If an application wants to have layers that are sorted by depth, it MUST request a session with the "depth-sorted-layers" feature descriptor.

If an XRSession is created with the "depth-sorted-layers" feature descriptor, XRProjectionLayer, XRQuadLayer and XRCylinderLayer layers MUST be displayed based on their depth as opposed to the location in the layers array. Other layers types MUST continue to be sorted as before.

XRQuadLayer and XRCylinderLayer layers MUST be sorted by their dimensions (for instance width or centralAngle), transform and space.

XRProjectionLayer layers MUST be sorted according to the values in their depthStencilTexture. This also implies that if "depth-sorted-layers" is enabled, the XR Compositor MUST make use of depth values and ignoreDepthValues MUST be set to `true`.

10. WebXR Device API Integration

10.1. XRRenderState changes

This module extends the XRRenderStateInit and XRRenderState interfaces with a new optional array layers containing instances of XRLayer.
[SecureContext, Exposed=Window] partial interface XRRenderState {
  readonly attribute FrozenArray<XRLayer> layers;
};

The layers attribute returns an array containing the instances of XRLayer that are displayed by the XR Compositor.

By default, the layers array defines the order of the composition of the layers. The XR Compositor MUST draw each layer in order of its position in the array using source-over blending. Unless the "depth-sorted-layers" feature descriptor is enabled, the XR Compositor MUST NOT apply any depth sorting of the layers.

NOTE: this means that each layer can potentially overwrite the previous layers whether or not the previous layers are virtually closer to the viewer.

This module replaces the steps given by initialize the render state. Instead when an XRRenderState object state is created for an XRSession session, the user agent MUST initialize the render state by running the following steps:
  1. Initialize state by running the original steps to initialize the render state.

  2. Initialize state’s layers with a new empty array in the relevant realm of session.

10.2. updateRenderState changes

This module replaces the steps given by "update the pending layers state" from the WebXR specification. Instead when the user agent will update the pending layers state with XRSession session and XRRenderStateInit newState, it must run the following steps:

  1. If both newState’s baseLayer and newState’s layers are set, throw a NotSupportedError and abort these steps.

  2. Let activeState be session’s active render state.

  3. If newState’s baseLayer is set:

    1. If session’s pending render state is null, set it to a copy of activeState.

    2. Set session’s pending render state's layers to null.

  4. If newState’s layers is set:

    1. If session was not created with "layers" enabled and newState’s layers contains more than 1 instance, throw a NotSupportedError and abort these steps.

    2. If session’s pending render state is null, set it to a copy of activeState.

    3. If newState’s layers contains duplicate instances, throw a TypeError and abort these steps.

    4. For each layer in newState’s layers:

      1. If layer is an XRCompositionLayer and layer’s session is different from session, throw a TypeError and abort these steps.

      2. If layer is an XRWebGLLayer and layer’s session is different from session, throw a TypeError and abort these steps.

    5. Set session’s pending render state's baseLayer to null.

    6. Set session’s pending render state's layers to newState’s layers.

10.3. XRCompositor changes

The XR Compositor MUST be extended so all XRLayer instances from the layers array are composited at the same time. All other requirements for WebXR MUST continue to apply.

If the XR Compositor is rendering to a view with an XREye of "none" and drawing an XRCompositionLayer which is NOT an XRProjectionLayer and does NOT have a layout of "mono", the XR Compositor MUST render that layer as if the view had an XREye of "left".

NOTE: This means that the side for the right eye of the layer is ignored. This enables authors to use the same assets for stereoscopic and monoscopic devices.

10.4. XRView changes

Each view MUST define a recommended WebGL texture resolution which represents a best estimate of the WebGL texture resolution large enough to contain the view.

10.5. Animation frames changes

This module replaces the steps given by "check the layers state" from the WebXR specification. Instead to check the layers state with renderState state, the user agent MUST run the following steps:
  1. If state’s baseLayer is not null, return true.

  2. If state’s layers is not empty, return true.

  3. return false.

11. Security and Privacy Considerations

11.1. Timing of the composition

Composition timing MUST be independent of the content that is rendered. Moreover, content in a layer MUST not be observable in other layers.

If possible, composition of layers should happen outside the browser to reduce risk of timing attacks or other security vulnerabilities.

11.2. Allocation of layers

The user agent MAY put limits on any resource allocation such as the maximum pixel size or the number of layers to reduce the identifiability of the GPU hardware.

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Conformant Algorithms

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.

Conformance requirements phrased as algorithms or specific steps can be implemented in any manner, so long as the end result is equivalent. In particular, the algorithms defined in this specification are intended to be easy to understand and are not intended to be performant. Implementers are encouraged to optimize.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[COMPOSITING-1]
Rik Cabanier; Nikos Andronikos. Compositing and Blending Level 1. 13 January 2015. CR. URL: https://www.w3.org/TR/compositing-1/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[GEOMETRY-1]
Simon Pieters; Chris Harrelson. Geometry Interfaces Module Level 1. 4 December 2018. CR. URL: https://www.w3.org/TR/geometry-1/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBGL-2]
Dean Jackson; Jeff Gilbert. WebGL 2.0 Specification. 12 August 2017. URL: https://www.khronos.org/registry/webgl/specs/latest/2.0/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/
[WEBXR]
Brandon Jones; Manish Goregaokar; Rik Cabanier. WebXR Device API. 24 December 2021. WD. URL: https://www.w3.org/TR/webxr/
[WEBXR-AR-MODULE-1]
Brandon Jones; Manish Goregaokar; Rik Cabanier. WebXR Augmented Reality Module - Level 1. 24 December 2021. WD. URL: https://www.w3.org/TR/webxr-ar-module-1/

Informative References

[PERMISSIONS-REQUEST]
Requesting Permissions. cg-draft. URL: https://wicg.github.io/permissions-request/

IDL Index

enum XRLayerLayout {
  "default",
  "mono",
  "stereo",
  "stereo-left-right",
  "stereo-top-bottom"
};

[Exposed=Window] interface XRCompositionLayer : XRLayer {
  readonly attribute XRLayerLayout layout;

  attribute boolean blendTextureSourceAlpha;
  attribute boolean? chromaticAberrationCorrection;
  readonly attribute unsigned long mipLevels;

  readonly attribute boolean needsRedraw;

  undefined destroy();
};

[Exposed=Window] interface XRProjectionLayer : XRCompositionLayer {
  readonly attribute unsigned long textureWidth;
  readonly attribute unsigned long textureHeight;
  readonly attribute unsigned long textureArrayLength;

  readonly attribute boolean ignoreDepthValues;
  attribute float? fixedFoveation;
};

[Exposed=Window] interface XRQuadLayer : XRCompositionLayer {
  attribute XRSpace space;
  attribute XRRigidTransform transform;

  attribute float width;
  attribute float height;

  // Events
  attribute EventHandler onredraw;
};

[Exposed=Window] interface XRCylinderLayer : XRCompositionLayer {
  attribute XRSpace space;
  attribute XRRigidTransform transform;

  attribute float radius;
  attribute float centralAngle;
  attribute float aspectRatio;

  // Events
  attribute EventHandler onredraw;
};

[Exposed=Window] interface XREquirectLayer : XRCompositionLayer {
  attribute XRSpace space;
  attribute XRRigidTransform transform;

  attribute float radius;
  attribute float centralHorizontalAngle;
  attribute float upperVerticalAngle;
  attribute float lowerVerticalAngle;

  // Events
  attribute EventHandler onredraw;
};

[Exposed=Window] interface XRCubeLayer : XRCompositionLayer {
  attribute XRSpace space;
  attribute DOMPointReadOnly orientation;

  // Events
  attribute EventHandler onredraw;
};

[Exposed=Window] interface XRSubImage {
  [SameObject] readonly attribute XRViewport viewport;
};

[Exposed=Window] interface XRWebGLSubImage : XRSubImage {
  [SameObject] readonly attribute WebGLTexture colorTexture;
  [SameObject] readonly attribute WebGLTexture? depthStencilTexture;
  readonly attribute unsigned long? imageIndex;
  readonly attribute unsigned long textureWidth;
  readonly attribute unsigned long textureHeight;
};

enum XRTextureType {
  "texture",
  "texture-array"
};

dictionary XRProjectionLayerInit {
  XRTextureType textureType = "texture";
  GLenum colorFormat = 0x1908; // RGBA
  GLenum depthFormat = 0x1902; // DEPTH_COMPONENT
  double scaleFactor = 1.0;
};

dictionary XRLayerInit {
  required XRSpace space;
  GLenum colorFormat = 0x1908; // RGBA
  GLenum? depthFormat;
  unsigned long mipLevels = 1;
  required unsigned long viewPixelWidth;
  required unsigned long viewPixelHeight;
  XRLayerLayout layout = "mono";
  boolean isStatic = false;
};

dictionary XRQuadLayerInit : XRLayerInit {
  XRTextureType textureType = "texture";
  XRRigidTransform? transform;
  float width = 1.0;
  float height = 1.0;
};

dictionary XRCylinderLayerInit : XRLayerInit {
  XRTextureType textureType = "texture";
  XRRigidTransform? transform;
  float radius = 2.0;
  float centralAngle = 0.78539;
  float aspectRatio = 2.0;
};

dictionary XREquirectLayerInit : XRLayerInit {
  XRTextureType textureType = "texture";
  XRRigidTransform? transform;
  float radius = 0;
  float centralHorizontalAngle = 6.28318;
  float upperVerticalAngle = 1.570795;
  float lowerVerticalAngle = -1.570795;
};

dictionary XRCubeLayerInit : XRLayerInit {
  DOMPointReadOnly? orientation;
};

[Exposed=Window] interface XRWebGLBinding {
  constructor(XRSession session, XRWebGLRenderingContext context);

  readonly attribute double nativeProjectionScaleFactor;
  readonly attribute boolean usesDepthValues;

  XRProjectionLayer createProjectionLayer(optional XRProjectionLayerInit init = {});
  XRQuadLayer createQuadLayer(optional XRQuadLayerInit init = {});
  XRCylinderLayer createCylinderLayer(optional XRCylinderLayerInit init = {});
  XREquirectLayer createEquirectLayer(optional XREquirectLayerInit init = {});
  XRCubeLayer createCubeLayer(optional XRCubeLayerInit init = {});

  XRWebGLSubImage getSubImage(XRCompositionLayer layer, XRFrame frame, optional XREye eye = "none");
  XRWebGLSubImage getViewSubImage(XRProjectionLayer layer, XRView view);
};

dictionary XRMediaLayerInit {
  required XRSpace space;
  XRLayerLayout layout = "mono";
  boolean invertStereo = false;
};

dictionary XRMediaQuadLayerInit : XRMediaLayerInit {
  XRRigidTransform? transform;
  float? width;
  float? height;
};

dictionary XRMediaCylinderLayerInit : XRMediaLayerInit {
  XRRigidTransform? transform;
  float radius = 2.0;
  float centralAngle = 0.78539;
  float? aspectRatio;
};

dictionary XRMediaEquirectLayerInit : XRMediaLayerInit {
  XRRigidTransform? transform;
  float radius = 0.0;
  float centralHorizontalAngle = 6.28318;
  float upperVerticalAngle = 1.570795;
  float lowerVerticalAngle = -1.570795;
};

[Exposed=Window] interface XRMediaBinding {
  constructor(XRSession session);

  XRQuadLayer createQuadLayer(HTMLVideoElement video, optional XRMediaQuadLayerInit init = {});
  XRCylinderLayer createCylinderLayer(HTMLVideoElement video, optional XRMediaCylinderLayerInit init = {});
  XREquirectLayer createEquirectLayer(HTMLVideoElement video, optional XRMediaEquirectLayerInit init = {});
};

[SecureContext, Exposed=Window] interface XRLayerEvent : Event {
  constructor(DOMString type, XRLayerEventInit eventInitDict);
  [SameObject] readonly attribute XRLayer layer;
};

dictionary XRLayerEventInit : EventInit {
  required XRLayer layer;
};

[SecureContext, Exposed=Window] partial interface XRRenderState {
  readonly attribute FrozenArray<XRLayer> layers;
};

Issues Index

this section needs clarification
this section needs clarification
the init dictionaries shouldn’t be optional. This is bikeshed issue 1566.
special case UA behavior if the size causes the layout to change (ie if the requested width exceeds a limit with "stereo-left-right")
the scaleFactor needs to be recalculated for the secondary views.
Define how cubemap sizes are determined.
How should space be handled. Can you walk to the edge of a cubemap?
determine the initial state of orientation.
the init dictionaries shouldn’t be optional. This is bikeshed issue 1566.
more clarification is needed on how the video is blitted to the layers.
add a better algorithm to describe the drawing.
define how the XREquirectLayer's parameters affect the video display.