// Copyright (c) 2016-2024, The Khronos Group Inc.
//
// SPDX-License-Identifier: CC-BY-4.0
[[session]]
== Session

[open,refpage='XrSession',desc='Opaque handle to a session object',type='handles',xrefs='xrCreateSession xrDestroySession xrBeginSession xrEndSession']
--
include::{generated}/api/handles/XrSession.adoc[]

A session represents an application's intention to display XR content to the
user.

--

[[session-lifecycle]]
=== Session Lifecycle

[[fig-session-lifecycle]]
image::images/lifecycle.svg[opts=inline, align="center", title="Session Lifecycle"]

[NOTE]
====

A typical XR session coordinates the application and the runtime through
session control functions and session state events.

1. The application creates a session by choosing a <<system, system>> and a
graphics API and passing them into flink:xrCreateSession.
The newly created session is in the <<XR_SESSION_STATE_IDLE,
ename:XR_SESSION_STATE_IDLE>> state.

2. The application can regularly call flink:xrPollEvent to monitor for
session state changes via slink:XrEventDataSessionStateChanged events.

3. When the runtime determines that the system is ready to start
transitioning to this session's XR content, the application receives a
notification of session state change to <<XR_SESSION_STATE_READY,
ename:XR_SESSION_STATE_READY>>.
Once the application is also ready to proceed and display its XR content, it
calls flink:xrBeginSession and <<session-sync-frame-loop, starts its frame
loop>>, which begins <<session-running, a running session>>.

4. While the session is running, the application is expected to continuously
execute its frame loop by calling flink:xrWaitFrame, flink:xrBeginFrame and
flink:xrEndFrame each frame, establishing synchronization with the runtime.
Once the runtime is synchronized with the application's frame loop and ready
to display application's frames, the session moves into the
<<XR_SESSION_STATE_SYNCHRONIZED, ename:XR_SESSION_STATE_SYNCHRONIZED>>
state.
In this state, the submitted frames will not be displayed or visible to the
user yet.

5. When the runtime intends to display frames from the application, it
notifies with <<XR_SESSION_STATE_VISIBLE, ename:XR_SESSION_STATE_VISIBLE>>
state, and sets slink:XrFrameState::pname:shouldRender to code:true in
flink:xrWaitFrame.
The application should render XR content and submit the composition layers
to flink:xrEndFrame.

6. When the runtime determines the application is eligible to receive XR
inputs, e.g. motion controller or hand tracking inputs, it notifies with
<<XR_SESSION_STATE_FOCUSED, ename:XR_SESSION_STATE_FOCUSED>> state.
The application can expect to receive active <<input, action inputs>>.

7. When the runtime determines the application has lost XR input focus, it
moves the session state from <<XR_SESSION_STATE_FOCUSED,
ename:XR_SESSION_STATE_FOCUSED>> to <<XR_SESSION_STATE_VISIBLE,
ename:XR_SESSION_STATE_VISIBLE>> state.
The application may need to change its own internal state while input is
unavailable.
Since the session is still visible, the application needs to render and
submit frames at full frame rate, but may wish to change visually to
indicate its input suspended state.
When the runtime returns XR focus back to the application, it moves the
session state back to <<XR_SESSION_STATE_FOCUSED,
ename:XR_SESSION_STATE_FOCUSED>>.

8. When the runtime needs to end <<session-running, a running session>> due
to the user closing or switching the application, the runtime will change
the session state through appropriate intermediate ones and finally to
<<XR_SESSION_STATE_STOPPING, ename:XR_SESSION_STATE_STOPPING>>.
When the application receives the <<XR_SESSION_STATE_STOPPING,
ename:XR_SESSION_STATE_STOPPING>> event, it should stop its frame loop and
then call flink:xrEndSession to tell the runtime to <<session-running, stop
the running session>>.

9. After flink:xrEndSession, the runtime transitions the session state to
<<XR_SESSION_STATE_IDLE, ename:XR_SESSION_STATE_IDLE>>.
If the XR session is temporarily paused in the background, the runtime will
keep the session state at <<XR_SESSION_STATE_IDLE,
ename:XR_SESSION_STATE_IDLE>> and later transition the session state back to
<<XR_SESSION_STATE_READY, ename:XR_SESSION_STATE_READY>> when the XR session
is resumed.
If the runtime determines that its use of this XR session has concluded, it
will transition the session state from <<XR_SESSION_STATE_IDLE,
ename:XR_SESSION_STATE_IDLE>> to <<XR_SESSION_STATE_EXITING,
ename:XR_SESSION_STATE_EXITING>>.

10. When the application receives the <<XR_SESSION_STATE_EXITING,
ename:XR_SESSION_STATE_EXITING>> event, it releases the resources related to
the session and calls flink:xrDestroySession.

====

[[session-running]]
A session is considered **running** after a successful call to
flink:xrBeginSession and remains running until any call is made to
flink:xrEndSession.
Certain functions are only valid to call when a session is running, such as
flink:xrWaitFrame, or else the ename:XR_ERROR_SESSION_NOT_RUNNING error
must: be returned by the runtime.

[[session-not-running]]
A session is considered **not running** before a successful call to
flink:xrBeginSession and becomes not running again after any call is made to
flink:xrEndSession.
Certain functions are only valid to call when a session is not running, such
as flink:xrBeginSession, or else the ename:XR_ERROR_SESSION_RUNNING error
must: be returned by the runtime.

If an error is returned from flink:xrBeginSession, the session remains in
its current running or not running state.
Calling flink:xrEndSession always transitions a session to the not running
state, regardless of any errors returned.

Only running sessions may become focused sessions that receive XR input.
When a session <<session-not-running, is not running>>, the application
must: not submit frames.
This is important because without a running session, the runtime no longer
has to spend resources on sub-systems (tracking etc.) that are no longer
needed by the application.

An application must: call flink:xrBeginSession when the session is in the
<<XR_SESSION_STATE_READY, ename:XR_SESSION_STATE_READY>> state, or
ename:XR_ERROR_SESSION_NOT_READY will be returned; it must: call
flink:xrEndSession when the session is in the <<XR_SESSION_STATE_STOPPING,
ename:XR_SESSION_STATE_STOPPING>> state, otherwise
ename:XR_ERROR_SESSION_NOT_STOPPING will be returned.
This is to allow the runtimes to seamlessly transition from one
application's session to another.

The application can: call flink:xrDestroySession at any time during the
session life cycle, however, it must: stop using the slink:XrSession handle
immediately in all threads and stop using any related resources.
Therefore, it's typically undesirable to destroy <<session-running, a
running session>> and instead it's recommended to wait for
<<XR_SESSION_STATE_EXITING, ename:XR_SESSION_STATE_EXITING>> to destroy a
session.

[[session-creation]]
=== Session Creation

To present graphical content on an output device, OpenXR applications need
to pick a graphics API which is supported by the runtime.
Unextended OpenXR does not support any graphics APIs natively but provides a
number of extensions of which each runtime can support any subset.
These extensions can be activated during slink:XrInstance create time.

During slink:XrSession creation the application must: provide information
about which graphics API it intends to use by adding an
stext:XrGraphicsBinding* struct of one (and only one) of the enabled
graphics API extensions to the next chain of slink:XrSessionCreateInfo.
The application must: call the ftext:xrGet*GraphicsRequirements method
(where `*` is a placeholder) provided by the chosen graphics API extension
before attempting to create the session (for example,
ifdef::XR_KHR_d3d11_enable[]
flink:xrGetD3D11GraphicsRequirementsKHR
endif::XR_KHR_d3d11_enable[]
ifdef::XR_KHR_d3d12_enable[]
flink:xrGetD3D12GraphicsRequirementsKHR
endif::XR_KHR_d3d12_enable[]
ifdef::XR_KHR_opengl_enable[]
flink:xrGetOpenGLGraphicsRequirementsKHR
endif::XR_KHR_opengl_enable[]
ifdef::XR_KHR_opengles_enable[]
flink:xrGetOpenGLESGraphicsRequirementsKHR
endif::XR_KHR_opengles_enable[]
ifdef::XR_KHR_vulkan_enable[]
flink:xrGetVulkanGraphicsRequirementsKHR
endif::XR_KHR_vulkan_enable[]
ifdef::XR_KHR_vulkan_enable2[]
flink:xrGetVulkanGraphicsRequirements2KHR
endif::XR_KHR_vulkan_enable2[]
).

Unless specified differently in the graphics API extension, the application
is responsible for creating a valid graphics device binding based on the
requirements returned by ftext:xrGet*GraphicsRequirements methods (for
details refer to the extension specification of the graphics API).

[open,refpage='xrCreateSession',desc='Creates an XrSession',type='protos',xrefs='xrDestroySession xrBeginSession xrEndSession XrSessionCreateInfo XrSessionCreateFlags XrExtensionProperties']
--
The flink:xrCreateSession function is defined as:

include::{generated}/api/protos/xrCreateSession.adoc[]

.Parameter Descriptions
****
* pname:instance is the instance from which
  slink:XrSessionCreateInfo::pname:systemId was retrieved.
* pname:createInfo is a pointer to an slink:XrSessionCreateInfo structure
  containing information about how to create the session.
* pname:session is a pointer to a handle in which the created
  slink:XrSession is returned.
****

Creates a session using the provided pname:createInfo and returns a handle
to that session.
This session is created in the ename:XR_SESSION_STATE_IDLE state, and a
corresponding slink:XrEventDataSessionStateChanged event to the
ename:XR_SESSION_STATE_IDLE state must: be generated as the first such event
for the new session.

The runtime must: return ename:XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING
(ename:XR_ERROR_VALIDATION_FAILURE may be returned due to legacy behavior)
on calls to flink:xrCreateSession if a function named like
ftext:xrGet*GraphicsRequirements has not been called for the same
pname:instance and slink:XrSessionCreateInfo::pname:systemId.
(See graphics binding extensions for details.)

include::{generated}/validity/protos/xrCreateSession.adoc[]
--

[open,refpage='XrSessionCreateInfo',desc='Creates a session',type='structs',xrefs='xrCreateSession XrSessionCreateFlags']
--

The slink:XrSessionCreateInfo structure is defined as:
include::{generated}/api/structs/XrSessionCreateInfo.adoc[]

.Member Descriptions
****
* pname:type is the elink:XrStructureType of this structure.
* pname:next is code:NULL or a pointer to the next structure in a structure
  chain.
  No such structures are defined in core OpenXR.
  Note that in most cases one graphics API extension specific struct needs
  to be in this next chain.
* pname:createFlags identifies elink:XrSessionCreateFlags that apply to the
  creation.
* pname:systemId is the basetype:XrSystemId representing the system of
  devices to be used by this session.
****

.Valid Usage
****
* pname:systemId must: be a valid basetype:XrSystemId or
  ename:XR_ERROR_SYSTEM_INVALID must: be returned.
* pname:next, unless otherwise specified via an extension, must: contain
  exactly one graphics API binding structure (a structure whose name begins
  with "`XrGraphicsBinding`") or ename:XR_ERROR_GRAPHICS_DEVICE_INVALID
  must: be returned.
****

include::{generated}/validity/structs/XrSessionCreateInfo.adoc[]
--

[open,refpage='XrSessionCreateFlags',desc='Session Creation Flags',type='flags',xrefs='XrSessionCreateFlagBits xrCreateSession XrSessionCreateInfo']
--
The slink:XrSessionCreateInfo::pname:createFlags member is of the following
type, and contains a bitwise-OR of zero or more of the bits defined in
elink:XrSessionCreateFlagBits.

include::{generated}/api/flags/XrSessionCreateFlags.adoc[]
--

[open,refpage='XrSessionCreateFlagBits',desc='Session Creation Flags',type='enums',xrefs='XrSessionCreateFlags xrCreateSession XrSessionCreateInfo']
--
Valid bits for elink:XrSessionCreateFlags are defined by
elink:XrSessionCreateFlagBits.

include::{generated}/api/enums/XrSessionCreateFlagBits.adoc[]

There are currently no session creation flags.
This is reserved for future use.

--

[open,refpage='xrDestroySession',desc='Destroys an XrSession',type='protos',xrefs='xrCreateSession xrBeginSession xrEndSession']
--
The flink:xrDestroySession function is defined as.
include::{generated}/api/protos/xrDestroySession.adoc[]

.Parameter Descriptions
****
* pname:session is the session to destroy.
****

slink:XrSession handles are destroyed using flink:xrDestroySession.
When an slink:XrSession is destroyed, all handles that are children of that
slink:XrSession are also destroyed.

The application is responsible for ensuring that it has no calls using
pname:session in progress when the session is destroyed.

flink:xrDestroySession can be called when the session is in any session
state.

include::{generated}/validity/protos/xrDestroySession.adoc[]
--

[[session-control]]
=== Session Control

[open,refpage='xrBeginSession',desc='Begins an XrSession',type='protos',xrefs='xrCreateSession xrDestroySession xrEndSession XrSessionBeginInfo']
--
The flink:xrBeginSession function is defined as:

include::{generated}/api/protos/xrBeginSession.adoc[]

.Parameter Descriptions
****
* pname:session is a valid slink:XrSession handle.
* pname:beginInfo is a pointer to an slink:XrSessionBeginInfo structure.
****

When the application receives slink:XrEventDataSessionStateChanged event
with the ename:XR_SESSION_STATE_READY state, the application should: then
call flink:xrBeginSession to start rendering frames for display to the user.

After this function successfully returns, the session <<session-running, is
considered to be running>>.
The application should: then start its frame loop consisting of some
sequence of flink:xrWaitFrame/flink:xrBeginFrame/flink:xrEndFrame calls.

If the session <<session-running, is already running>> when the application
calls flink:xrBeginSession, the runtime must: return error
ename:XR_ERROR_SESSION_RUNNING.
If the session <<session-not-running, is not running>> when the application
calls flink:xrBeginSession, but the session is not yet in the
ename:XR_SESSION_STATE_READY state, the runtime must: return error
ename:XR_ERROR_SESSION_NOT_READY.

Note that a runtime may: decide not to show the user any given frame from a
session at any time, for example if the user has switched to a different
application's running session.
The application should check whether flink:xrWaitFrame returns
slink:XrFrameState::pname:shouldRender set to true before rendering a given
frame to determine whether that frame will be visible to the user.

Runtime session frame state must: start in a reset state when a session
transitions to <<session-running, running>> so that no state is carried over
from when the same session was previously running.
Frame state in this context includes flink:xrWaitFrame, flink:xrBeginFrame,
and flink:xrEndFrame call order enforcement.

If slink:XrSessionBeginInfo::pname:primaryViewConfigurationType in
pname:beginInfo is not supported by the basetype:XrSystemId used to create
the pname:session, the runtime must: return
ename:XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED.

include::{generated}/validity/protos/xrBeginSession.adoc[]
--

[open,refpage='XrSessionBeginInfo',desc='Struct containing session begin info',type='structs',xrefs='xrBeginSession']
--

The slink:XrSessionBeginInfo structure is defined as:
include::{generated}/api/structs/XrSessionBeginInfo.adoc[]

.Member Descriptions
****
* pname:type is the elink:XrStructureType of this structure.
* pname:next is code:NULL or a pointer to the next structure in a structure
  chain.
  No such structures are defined in core OpenXR.
* pname:primaryViewConfigurationType is the elink:XrViewConfigurationType to
  use during this session to provide images for the form factor's primary
  displays.
****

include::{generated}/validity/structs/XrSessionBeginInfo.adoc[]
--

[open,refpage='xrEndSession',desc='Ends an XrSession',type='protos',xrefs='xrCreateSession xrDestroySession xrBeginSession']
--
The flink:xrEndSession function is defined as:

include::{generated}/api/protos/xrEndSession.adoc[]

.Parameter Descriptions
****
* pname:session is a handle to a <<session-running, running>>
  slink:XrSession.
****

When the application receives slink:XrEventDataSessionStateChanged event
with the ename:XR_SESSION_STATE_STOPPING state, the application should stop
its frame loop and then call flink:xrEndSession to end the
<<session-running, running>> session.
This function signals to the runtime that the application will no longer
call flink:xrWaitFrame, flink:xrBeginFrame or flink:xrEndFrame from any
thread allowing the runtime to safely transition the session to
ename:XR_SESSION_STATE_IDLE.
The application must: also avoid reading input state or sending haptic
output after calling flink:xrEndSession.

If the session <<session-not-running, is not running>> when the application
calls flink:xrEndSession, the runtime must: return error
ename:XR_ERROR_SESSION_NOT_RUNNING.
If the session <<session-running, is still running>> when the application
calls flink:xrEndSession, but the session is not yet in the
ename:XR_SESSION_STATE_STOPPING state, the runtime must: return error
ename:XR_ERROR_SESSION_NOT_STOPPING.

If the application wishes to exit a running session, the application can
call flink:xrRequestExitSession so that the session transitions from
ename:XR_SESSION_STATE_IDLE to ename:XR_SESSION_STATE_EXITING.

include::{generated}/validity/protos/xrEndSession.adoc[]
--

[open,refpage='xrRequestExitSession',desc='Request to exit a running session.',type='protos',xrefs='xrDestroySession xrEndSession']
--
When an application wishes to exit a <<session-running, running>> session,
it can: call flink:xrRequestExitSession, requesting that the runtime
transition through the various intermediate session states including
ename:XR_SESSION_STATE_STOPPING to ename:XR_SESSION_STATE_EXITING.

On platforms where an application's lifecycle is managed by the system,
session state changes may be implicitly triggered by application lifecycle
state changes.
On such platforms, using platform-specific methods to alter application
lifecycle state may be the preferred method of provoking session state
changes.
The behavior of flink:xrRequestExitSession is not altered, however explicit
session exit may: not interact with the platform-specific application
lifecycle.

The flink:xrRequestExitSession function is defined as:

include::{generated}/api/protos/xrRequestExitSession.adoc[]

.Parameter Descriptions
****
* pname:session is a handle to a running slink:XrSession.
****

If pname:session <<session-not-running, is not running>> when
flink:xrRequestExitSession is called, ename:XR_ERROR_SESSION_NOT_RUNNING
must: be returned.

include::{generated}/validity/protos/xrRequestExitSession.adoc[]
--

[[session-states]]
=== Session States

While events can be expanded upon, there are a minimum set of lifecycle
events which can occur which all OpenXR applications must be aware of.
These events are detailed below.

==== XrEventDataSessionStateChanged

[open,refpage='XrEventDataSessionStateChanged',desc='Event indicating session state changed',type='structs',xrefs='xrPollEvent XrEventDataBaseHeader']
--

The slink:XrEventDataSessionStateChanged structure is defined as:
include::{generated}/api/structs/XrEventDataSessionStateChanged.adoc[]

.Member Descriptions
****
* pname:type is the elink:XrStructureType of this structure.
* pname:next is code:NULL or a pointer to the next structure in a structure
  chain.
  No such structures are defined in core OpenXR.
* pname:session is the slink:XrSession which has changed state.
* pname:state is the current elink:XrSessionState of the pname:session.
* pname:time is an basetype:XrTime which indicates the time of the state
  change.
****

Receiving the slink:XrEventDataSessionStateChanged event structure indicates
that the application has changed lifecycle state.

include::{generated}/validity/structs/XrEventDataSessionStateChanged.adoc[]
--

[open,refpage='XrSessionState',desc='Session lifecycle state',type='enums',xrefs='xrPollEvent XrEventDataSessionStateChanged']
--
The elink:XrSessionState enumerates the possible session lifecycle states:

include::{generated}/api/enums/XrSessionState.adoc[]

.Enumerant Descriptions
****
* ename:XR_SESSION_STATE_UNKNOWN.
  An unknown state.
  The runtime must: not return this value in an
  slink:XrEventDataSessionStateChanged event.
* ename:XR_SESSION_STATE_IDLE.
  The initial state after calling flink:xrCreateSession or returned to after
  calling flink:xrEndSession.
* ename:XR_SESSION_STATE_READY.
  The application is ready to call flink:xrBeginSession and
  <<session-sync-frame-loop, sync its frame loop with the runtime.>>
* ename:XR_SESSION_STATE_SYNCHRONIZED.
  The application has synced its frame loop with the runtime but is not
  visible to the user.
* ename:XR_SESSION_STATE_VISIBLE.
  The application has <<session-sync-frame-loop, synced its frame loop with
  the runtime>> and is visible to the user but cannot receive XR input.
* ename:XR_SESSION_STATE_FOCUSED.
  The application has <<session-sync-frame-loop, synced its frame loop with
  the runtime>>, is visible to the user and can receive XR input.
* ename:XR_SESSION_STATE_STOPPING.
  The application should exit its frame loop and call flink:xrEndSession.
* ename:XR_SESSION_STATE_LOSS_PENDING.
  The session is in the process of being lost.
  The application should destroy the current session and can optionally
  recreate it.
* ename:XR_SESSION_STATE_EXITING.
  The application should end its XR experience and not automatically restart
  it.
****

The ename:XR_SESSION_STATE_UNKNOWN state must: not be returned by the
runtime, and is only defined to avoid code:0 being a valid state.

[[XR_SESSION_STATE_IDLE]]
Receiving the ename:XR_SESSION_STATE_IDLE state indicates that the runtime
considers the session is idle.
Applications in this state should: minimize resource consumption but
continue to call flink:xrPollEvent at some reasonable cadence.

[[XR_SESSION_STATE_READY]]
Receiving the ename:XR_SESSION_STATE_READY state indicates that the runtime
desires the application to prepare rendering resources, begin its session
and synchronize its frame loop with the runtime.
[[session-sync-frame-loop]]
The application does this by successfully calling flink:xrBeginSession and
then running its frame loop by calling flink:xrWaitFrame, flink:xrBeginFrame
and flink:xrEndFrame in a loop.
If the runtime wishes to return the session to the
ename:XR_SESSION_STATE_IDLE state, it must: wait until the application calls
flink:xrBeginSession.
After returning from the flink:xrBeginSession call, the runtime may then
immediately transition forward through the
ename:XR_SESSION_STATE_SYNCHRONIZED state to the
ename:XR_SESSION_STATE_STOPPING state, to request that the application end
this session.
If the system supports a user engagement sensor and runtime is in
ename:XR_SESSION_STATE_IDLE state, the runtime may: wait until the user
starts engaging with the device before transitioning to the
ename:XR_SESSION_STATE_READY state.

[[XR_SESSION_STATE_SYNCHRONIZED]]
Receiving the ename:XR_SESSION_STATE_SYNCHRONIZED state indicates that the
application has <<session-sync-frame-loop, synchronized its frame loop with
the runtime>>, but its frames are not visible to the user.
The application should: continue running its frame loop by calling
flink:xrWaitFrame, flink:xrBeginFrame and flink:xrEndFrame, although it
should avoid heavy GPU work so that other visible applications can take CPU
and GPU precedence.
The application can save resources here by skipping rendering and not
submitting any composition layers until flink:xrWaitFrame returns an
slink:XrFrameState with pname:shouldRender set to true.
A runtime may: use this frame synchronization to facilitate seamless
switching from a previous XR application to this application on a frame
boundary.

[[XR_SESSION_STATE_VISIBLE]]
Receiving the ename:XR_SESSION_STATE_VISIBLE state indicates that the
application has <<session-sync-frame-loop, synchronized its frame loop with
the runtime>>, and the session's frames will be visible to the user, but the
session is not eligible to receive XR input.
An application may be visible but not have focus, for example when the
runtime is composing a modal pop-up on top of the application's rendered
frames.
The application should: continue running its frame loop, rendering and
submitting its composition layers, although it may wish to pause its
experience, as users cannot interact with the application at this time.
It is important for applications to continue rendering when visible, even
when they do not have focus, so the user continues to see something
reasonable underneath modal pop-ups.
Runtimes should: make input actions inactive while the application is
unfocused, and applications should react to an inactive input action by
skipping rendering of that action's input avatar (depictions of hands or
other tracked objects controlled by the user).

[[XR_SESSION_STATE_FOCUSED]]
Receiving the ename:XR_SESSION_STATE_FOCUSED state indicates that the
application has <<session-sync-frame-loop, synchronized its frame loop with
the runtime>>, the session's frames will be visible to the user, and the
session is eligible to receive XR input.
The runtime should: only give one session XR input focus at any given time.
The application should: be running its frame loop, rendering and submitting
composition layers, including input avatars (depictions of hands or other
tracked objects controlled by the user) for any input actions that are
active.
The runtime should: avoid rendering its own input avatars when an
application is focused, unless input from a given source is being captured
by the runtime at the moment.

[[XR_SESSION_STATE_STOPPING]]
Receiving the ename:XR_SESSION_STATE_STOPPING state indicates that the
runtime has determined that the application should halt its rendering loop.
Applications should: exit their rendering loop and call flink:xrEndSession
when in this state.
A possible reason for this would be to minimize contention between multiple
applications.
If the system supports a user engagement sensor and the session is running,
the runtime may: transition to the ename:XR_SESSION_STATE_STOPPING state
when the user stops engaging with the device.

[[XR_SESSION_STATE_EXITING]]
Receiving the ename:XR_SESSION_STATE_EXITING state indicates the runtime
wishes the application to terminate its XR experience, typically due to a
user request via a runtime user interface.
Applications should: gracefully end their process when in this state if they
do not have a non-XR user experience.

[[XR_SESSION_STATE_LOSS_PENDING]]
Receiving the ename:XR_SESSION_STATE_LOSS_PENDING state indicates the
runtime is no longer able to operate with the current session, for example
due to the loss of a display hardware connection.
An application should: call flink:xrDestroySession and may: end its process
or decide to poll flink:xrGetSystem at some reasonable cadence to get a new
basetype:XrSystemId, and re-initialize all graphics resources related to the
new system, and then create a new session using flink:xrCreateSession.
After the event is queued, subsequent calls to functions that accept
slink:XrSession parameters must: no longer return any success code other
than ename:XR_SESSION_LOSS_PENDING for the given slink:XrSession handle.
The ename:XR_SESSION_LOSS_PENDING success result is returned for an
unspecified grace period of time, and the functions that return it simulate
success in their behavior.
If the runtime has no reasonable way to successfully complete a given
function (e.g. flink:xrCreateSwapchain) when a lost session is pending, or
if the runtime is not able to provide the application a grace period, the
runtime may: return ename:XR_ERROR_SESSION_LOST.
Thereafter, functions which accept slink:XrSession parameters for the lost
session may: return ename:XR_ERROR_SESSION_LOST to indicate that the
function failed and the given session was lost.
The slink:XrSession handle and child handles are henceforth unusable and
should: be destroyed by the application in order to immediately free up
resources associated with those handles.

--
