XR_EXT_spatial_persistence
Name String
XR_EXT_spatial_persistence
Extension Type
Instance extension
Registered Extension Number
764
Revision
1
Ratification Status
Ratified
Extension and Version Dependencies
XR_EXT_spatial_entity
and
XR_EXT_future
Contributors
Nihav Jain, Google
Jared Finder, Google
Natalie Fleury, Meta
Yuichi Taguchi, Meta
Ron Bessems, Meta
Yin Li, Microsoft
Jimmy Alamparambil, ByteDance
Zhipeng Liu, ByteDance
Jun Yan, ByteDance
Overview
This extension allows applications to discover and correlate spatial entities across application sessions, OpenXR sessions and multiple OpenXR spatial contexts within a session. The XR_EXT_spatial_entity extension established that an entity within an XrSpatialContextEXT is represented by an XrSpatialEntityIdEXT . This extension extends on that concept by establishing that an entity, if persisted, is represented by an XrUuid across application and OpenXR sessions i.e. an application can use the XrUuid provided by this extension to identify an entity across sessions. This extension also provides useful overlaps with the XR_EXT_spatial_entity extension to discover persisted entities in the user’s environment and the ability to query their component data.
Spatial Persistence Context
Create a spatial persistence context
XR_DEFINE_HANDLE(XrSpatialPersistenceContextEXT)
The XrSpatialPersistenceContextEXT handle represents the connection to a persistent spatial entity storage.
The xrCreateSpatialPersistenceContextAsyncEXT function is defined as:
XrResult xrCreateSpatialPersistenceContextAsyncEXT(
XrSession session,
const XrSpatialPersistenceContextCreateInfoEXT* createInfo,
XrFutureEXT* future);
Parameter Descriptions
sessionis an XrSession in which the spatial persistence context will be active.createInfois the XrSpatialPersistenceContextCreateInfoEXT used to specify the spatial persistence context parameters.futureis a pointer to anXrFutureEXT.
An application can create an XrSpatialPersistenceContextEXT handle using the xrCreateSpatialPersistenceContextAsyncEXT function and configure the scope of the persistence context in createInfo .
The runtime must return XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_UNSUPPORTED_EXT if XrSpatialPersistenceContextCreateInfoEXT :: scope is not enumerated by xrEnumerateSpatialPersistenceScopesEXT .
If a runtime enforces a permission system to control application access to the persistence storage represented by XrSpatialPersistenceContextEXT , then the runtime must return XR_ERROR_PERMISSION_INSUFFICIENT if those permissions have not been granted to this application.
Valid Usage (Implicit)
- The
XR_EXT_spatial_persistenceextension must be enabled prior to calling xrCreateSpatialPersistenceContextAsyncEXT -
sessionmust be a valid XrSession handle -
createInfomust be a pointer to a valid XrSpatialPersistenceContextCreateInfoEXT structure -
futuremust be a pointer to anXrFutureEXTvalue
Return Codes
XR_SUCCESSXR_SESSION_LOSS_PENDING
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALIDXR_ERROR_INSTANCE_LOSTXR_ERROR_LIMIT_REACHEDXR_ERROR_OUT_OF_MEMORYXR_ERROR_RUNTIME_FAILUREXR_ERROR_SESSION_LOSTXR_ERROR_SPATIAL_PERSISTENCE_SCOPE_UNSUPPORTED_EXTXR_ERROR_VALIDATION_FAILURE
The XrSpatialPersistenceContextCreateInfoEXT structure is defined as:
typedef struct XrSpatialPersistenceContextCreateInfoEXT {
XrStructureType type;
const void* next;
XrSpatialPersistenceScopeEXT scope;
} XrSpatialPersistenceContextCreateInfoEXT;
Member Descriptions
typeis the XrStructureType of this structure.nextisNULLor a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension.scopeis an XrSpatialPersistenceScopeEXT defining the storage scope of the persistence context.
The XrSpatialPersistenceContextCreateInfoEXT structure describes the information to create an XrSpatialPersistenceContextEXT handle.
Valid Usage (Implicit)
- The
XR_EXT_spatial_persistenceextension must be enabled prior to using XrSpatialPersistenceContextCreateInfoEXT -
typemust beXR_TYPE_SPATIAL_PERSISTENCE_CONTEXT_CREATE_INFO_EXT -
nextmust beNULLor a valid pointer to the next structure in a structure chain -
scopemust be a valid XrSpatialPersistenceScopeEXT value
typedef enum XrSpatialPersistenceScopeEXT {
XR_SPATIAL_PERSISTENCE_SCOPE_SYSTEM_MANAGED_EXT = 1,
XR_SPATIAL_PERSISTENCE_SCOPE_LOCAL_ANCHORS_EXT = 1000781000,
XR_SPATIAL_PERSISTENCE_SCOPE_MAX_ENUM_EXT = 0x7FFFFFFF
} XrSpatialPersistenceScopeEXT;
The XrSpatialPersistenceScopeEXT enumeration identifies the different types of persistence context scopes.
The enums have the following meanings:
Enum Description
XR_SPATIAL_PERSISTENCE_SCOPE_SYSTEM_MANAGED_EXT
Provides the application with read-only access (i.e. application cannot modify the store associated with this scope) to spatial entities persisted and managed by the system. The application can use the UUID in the persistence component for this scope to correlate entities across spatial contexts and device reboots.
XR_SPATIAL_PERSISTENCE_SCOPE_LOCAL_ANCHORS_EXT
Persistence operations and data access is limited to spatial anchors, on the same device, for the same user and same app (Added by the XR_EXT_spatial_persistence_operations extension)
The xrEnumerateSpatialPersistenceScopesEXT function is defined as:
XrResult xrEnumerateSpatialPersistenceScopesEXT(
XrInstance instance,
XrSystemId systemId,
uint32_t persistenceScopeCapacityInput,
uint32_t* persistenceScopeCountOutput,
XrSpatialPersistenceScopeEXT* persistenceScopes);
Parameter Descriptions
instanceis a handle to an XrInstance .systemIdis theXrSystemIdwhose spatial persistence scopes will be enumerated.persistenceScopeCapacityInputis the capacity of thepersistenceScopesarray, or 0 to indicate a request to retrieve the required capacity.persistenceScopeCountOutputis the number of persistence scopes, or the required capacity in the case thatpersistenceScopeCapacityInputis insufficient.persistenceScopesis an array of XrSpatialPersistenceScopeEXT . It can beNULLifpersistenceScopeCapacityInputis 0.- See Buffer Size Parameters chapter for a detailed description of retrieving the required
persistenceScopessize.
The application can enumerate the list of spatial persistence scopes supported by a given XrSystemId using xrEnumerateSpatialPersistenceScopesEXT .
Valid Usage (Implicit)
- The
XR_EXT_spatial_persistenceextension must be enabled prior to calling xrEnumerateSpatialPersistenceScopesEXT -
instancemust be a valid XrInstance handle -
persistenceScopeCountOutputmust be a pointer to auint32_tvalue - If
persistenceScopeCapacityInputis not0,persistenceScopesmust be a pointer to an array ofpersistenceScopeCapacityInputXrSpatialPersistenceScopeEXT values
Return Codes
XR_SUCCESS
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALIDXR_ERROR_INSTANCE_LOSTXR_ERROR_RUNTIME_FAILUREXR_ERROR_SIZE_INSUFFICIENTXR_ERROR_SYSTEM_INVALIDXR_ERROR_VALIDATION_FAILURE
The xrCreateSpatialPersistenceContextCompleteEXT function is defined as:
XrResult xrCreateSpatialPersistenceContextCompleteEXT(
XrSession session,
XrFutureEXT future,
XrCreateSpatialPersistenceContextCompletionEXT* completion);
Parameter Descriptions
sessionis the XrSession previously passed to xrCreateSpatialPersistenceContextAsyncEXT ::session.futureis theXrFutureEXTreceived from xrCreateSpatialPersistenceContextAsyncEXT .completionis a pointer to an XrCreateSpatialPersistenceContextCompletionEXT .
xrCreateSpatialPersistenceContextCompleteEXT completes the asynchronous operation started by xrCreateSpatialPersistenceContextAsyncEXT . The runtime must return XR_ERROR_FUTURE_PENDING_EXT if future is not in ready state. The runtime must return XR_ERROR_FUTURE_INVALID_EXT if future has already been completed or cancelled.
Valid Usage (Implicit)
- The
XR_EXT_spatial_persistenceextension must be enabled prior to calling xrCreateSpatialPersistenceContextCompleteEXT -
sessionmust be a valid XrSession handle -
completionmust be a pointer to an XrCreateSpatialPersistenceContextCompletionEXT structure
Return Codes
XR_SUCCESSXR_SESSION_LOSS_PENDING
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_FUTURE_INVALID_EXTXR_ERROR_FUTURE_PENDING_EXTXR_ERROR_HANDLE_INVALIDXR_ERROR_INSTANCE_LOSTXR_ERROR_LIMIT_REACHEDXR_ERROR_OUT_OF_MEMORYXR_ERROR_RUNTIME_FAILUREXR_ERROR_SESSION_LOSTXR_ERROR_VALIDATION_FAILURE
The XrCreateSpatialPersistenceContextCompletionEXT structure is defined as:
typedef struct XrCreateSpatialPersistenceContextCompletionEXT {
XrStructureType type;
void* next;
XrResult futureResult;
XrSpatialPersistenceContextResultEXT createResult;
XrSpatialPersistenceContextEXT persistenceContext;
} XrCreateSpatialPersistenceContextCompletionEXT;
Member Descriptions
typeis the XrStructureType of this structure.nextisNULLor a pointer to the next structure in a structure chain.futureResultis the XrResult of the spatial persistence context creation operation.createResultis the XrSpatialPersistenceContextResultEXT of the spatial persistence context creation operation.persistenceContextis an XrSpatialPersistenceContextEXT created using the data and configuration in xrCreateSpatialPersistenceContextAsyncEXT ::createInfo.
Future Return Codes
futureResult values:
XR_SUCCESSXR_SESSION_LOSS_PENDING
XR_ERROR_RUNTIME_FAILUREXR_ERROR_INSTANCE_LOSTXR_ERROR_SESSION_LOSTXR_ERROR_OUT_OF_MEMORYXR_ERROR_LIMIT_REACHEDXR_ERROR_PERMISSION_INSUFFICIENT
If futureResult and createResult are both success codes, persistenceContext must be valid. If persistenceContext is valid, it must remain so within the lifecycle of xrCreateSpatialPersistenceContextAsyncEXT :: session or until the application uses xrDestroySpatialPersistenceContextEXT with persistenceContext , whichever comes first.
The runtime must set createResult only if futureResult is a success code.
Valid Usage (Implicit)
- The
XR_EXT_spatial_persistenceextension must be enabled prior to using XrCreateSpatialPersistenceContextCompletionEXT -
typemust beXR_TYPE_CREATE_SPATIAL_PERSISTENCE_CONTEXT_COMPLETION_EXT -
nextmust beNULLor a valid pointer to the next structure in a structure chain -
futureResultmust be a valid XrResult value -
createResultmust be a valid XrSpatialPersistenceContextResultEXT value -
persistenceContextmust be a valid XrSpatialPersistenceContextEXT handle
typedef enum XrSpatialPersistenceContextResultEXT {
XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_SUCCESS_EXT = 0,
XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_ENTITY_NOT_TRACKING_EXT = -1000781001,
XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_PERSIST_UUID_NOT_FOUND_EXT = -1000781002,
XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_MAX_ENUM_EXT = 0x7FFFFFFF
} XrSpatialPersistenceContextResultEXT;
The XrSpatialPersistenceContextResultEXT enumeration identifies the different types of result codes for a persistence operation. Failures during persistence operations are not always in control of the application and this enumeration is used for conveying such cases. Similar to XrResult , success codes in the XrSpatialPersistenceContextResultEXT enumeration are non-negative values, and failure codes are negative values.
The enums have the following meanings:
Enum Description
XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_SUCCESS_EXT
The persistence context operation was a success.
XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_ENTITY_NOT_TRACKING_EXT
The persistence operation failed because the entity could not be tracked by the runtime. (Added by the XR_EXT_spatial_persistence_operations extension)
XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_PERSIST_UUID_NOT_FOUND_EXT
The provided persist UUID was not found in the storage. (Added by the XR_EXT_spatial_persistence_operations extension)
Destroy the spatial persistence context
The xrDestroySpatialPersistenceContextEXT function is defined as:
XrResult xrDestroySpatialPersistenceContextEXT(
XrSpatialPersistenceContextEXT persistenceContext);
Parameter Descriptions
persistenceContextis an XrSpatialPersistenceContextEXT previously created by xrCreateSpatialPersistenceContextAsyncEXT .
The application can use xrDestroySpatialPersistenceContextEXT to release the persistenceContext handle when it is finished with spatial persistence tasks.
The runtime must not destroy the underlying resources for persistenceContext when xrDestroySpatialPersistenceContextEXT is called if there are any valid XrSpatialContextEXT handles that persistenceContext was linked to via XrSpatialContextPersistenceConfigEXT . This is because the persistence context’s resources are still used by the spatial context for discovering persisted entities. Destroying the persistence context handle in such a situation only removes the application’s access to these resources.
The resources for a destroyed XrSpatialPersistenceContextEXT must be freed when all the XrSpatialContextEXT handles the persistence context was linked to are destroyed.
Valid Usage (Implicit)
- The
XR_EXT_spatial_persistenceextension must be enabled prior to calling xrDestroySpatialPersistenceContextEXT -
persistenceContextmust be a valid XrSpatialPersistenceContextEXT handle
Thread Safety
- Access to
persistenceContext, and any child handles, must be externally synchronized
Return Codes
XR_SUCCESS
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALIDXR_ERROR_RUNTIME_FAILURE
Discover persisted entities
Persistence component
Persisted spatial entities have the persistence component on them which the runtime must include in the discovery and update snapshots if XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT is enabled during the creation of XrSpatialContextEXT and included in XrSpatialDiscoverySnapshotCreateInfoEXT :: componentTypes or XrSpatialUpdateSnapshotCreateInfoEXT :: componentTypes .
Component Data
The XrSpatialPersistenceDataEXT structure is defined as:
typedef struct XrSpatialPersistenceDataEXT {
XrUuid persistUuid;
XrSpatialPersistenceStateEXT persistState;
} XrSpatialPersistenceDataEXT;
Member Descriptions
persistUuidis an XrUuid .persistStateis an XrSpatialPersistenceStateEXT representing the persistence state ofpersistUuid
Valid Usage (Implicit)
- The
XR_EXT_spatial_persistenceextension must be enabled prior to using XrSpatialPersistenceDataEXT -
persistStatemust be a valid XrSpatialPersistenceStateEXT value
typedef enum XrSpatialPersistenceStateEXT {
XR_SPATIAL_PERSISTENCE_STATE_LOADED_EXT = 1,
XR_SPATIAL_PERSISTENCE_STATE_NOT_FOUND_EXT = 2,
XR_SPATIAL_PERSISTENCE_STATE_MAX_ENUM_EXT = 0x7FFFFFFF
} XrSpatialPersistenceStateEXT;
The XrSpatialPersistenceStateEXT enumeration identifies the different states of the persisted uuid.
The enums have the following meanings:
Enum Description
XR_SPATIAL_PERSISTENCE_STATE_LOADED_EXT
The persisted UUID has been successfully loaded from the storage.
XR_SPATIAL_PERSISTENCE_STATE_NOT_FOUND_EXT
The persisted UUID was not found in the storage and was either removed from it or never was in it.
Component list structure to query data
The XrSpatialComponentPersistenceListEXT structure is defined as:
typedef struct XrSpatialComponentPersistenceListEXT {
XrStructureType type;
void* next;
uint32_t persistDataCount;
XrSpatialPersistenceDataEXT* persistData;
} XrSpatialComponentPersistenceListEXT;
Member Descriptions
typeis the XrStructureType of this structure.nextisNULLor a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension.persistDataCountis auint32_tdescribing the count of elements in thepersistDataarray.persistDatais an array of XrSpatialPersistenceDataEXT .
The runtime must return XR_ERROR_VALIDATION_FAILURE from xrQuerySpatialComponentDataEXT if XrSpatialComponentPersistenceListEXT is in the next chain of XrSpatialComponentDataQueryResultEXT :: next but XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT is not included in XrSpatialComponentDataQueryConditionEXT :: componentTypes .
The runtime must return XR_ERROR_SIZE_INSUFFICIENT from xrQuerySpatialComponentDataEXT if persistDataCount is less than XrSpatialComponentDataQueryResultEXT :: entityIdCountOutput .
Unlike the other components, the runtime must set the data for XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT regardless of the XrSpatialEntityTrackingStateEXT .
Valid Usage (Implicit)
- The
XR_EXT_spatial_persistenceextension must be enabled prior to using XrSpatialComponentPersistenceListEXT -
typemust beXR_TYPE_SPATIAL_COMPONENT_PERSISTENCE_LIST_EXT -
nextmust beNULLor a valid pointer to the next structure in a structure chain -
persistDatamust be a pointer to an array ofpersistDataCountXrSpatialPersistenceDataEXT structures - The
persistDataCountparameter must be greater than0
Configuration
If XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT is enumerated in XrSpatialCapabilityComponentTypesEXT :: componentTypes for some capability, the application can enable it by including the enum in the XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents list. This component does not require any special configuration to be included in the next chain of XrSpatialCapabilityConfigurationBaseHeaderEXT . If the application is including XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT in the enabled component list, it must also include XrSpatialContextPersistenceConfigEXT in the next chain of XrSpatialContextCreateInfoEXT otherwise the runtime must return XR_ERROR_SPATIAL_CAPABILITY_CONFIGURATION_INVALID_EXT from xrCreateSpatialContextAsyncEXT .
Configure spatial context with persistence contexts
The XrSpatialContextPersistenceConfigEXT structure is defined as:
typedef struct XrSpatialContextPersistenceConfigEXT {
XrStructureType type;
const void* next;
uint32_t persistenceContextCount;
const XrSpatialPersistenceContextEXT* persistenceContexts;
} XrSpatialContextPersistenceConfigEXT;
Member Descriptions
typeis the XrStructureType of this structure.nextisNULLor a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension.persistenceContextCountis auint32_tdescribing the count of elements in thepersistenceContextsarray.persistenceContextsis an an array of XrSpatialPersistenceContextEXT .
An application can add XrSpatialContextPersistenceConfigEXT to the next chain of XrSpatialContextCreateInfoEXT . This will configure the created XrSpatialContextEXT with persistenceContexts and allow the application to discover the spatial entities persisted in the storage represented by the XrSpatialPersistenceContextEXT handles in persistenceContexts .
Valid Usage (Implicit)
- The
XR_EXT_spatial_persistenceextension must be enabled prior to using XrSpatialContextPersistenceConfigEXT -
typemust beXR_TYPE_SPATIAL_CONTEXT_PERSISTENCE_CONFIG_EXT -
nextmust beNULLor a valid pointer to the next structure in a structure chain -
persistenceContextsmust be a pointer to an array ofpersistenceContextCountvalid XrSpatialPersistenceContextEXT handles - The
persistenceContextCountparameter must be greater than0
Create discovery snapshot
Discover entities with specific UUIDs
The XrSpatialDiscoveryPersistenceUuidFilterEXT structure is defined as:
typedef struct XrSpatialDiscoveryPersistenceUuidFilterEXT {
XrStructureType type;
const void* next;
uint32_t persistedUuidCount;
const XrUuid* persistedUuids;
} XrSpatialDiscoveryPersistenceUuidFilterEXT;
Member Descriptions
typeis the XrStructureType of this structure.nextisNULLor a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension.persistedUuidCountis auint32_tdescribing the count of elements in thepersistedUuidsarraypersistedUuidsis an array of XrUuid .
The application can use XrSpatialDiscoveryPersistenceUuidFilterEXT in the next chain of XrSpatialDiscoverySnapshotCreateInfoEXT to scope the discovery operation to just the entities whose persisted UUIDs are in the set of the UUIDs provided in persistedUuids .
If the application adds XrSpatialDiscoveryPersistenceUuidFilterEXT in the next chain of XrSpatialDiscoverySnapshotCreateInfoEXT but the xrCreateSpatialDiscoverySnapshotAsyncEXT :: spatialContext was not configured with any XrSpatialPersistenceContextEXT using XrSpatialContextPersistenceConfigEXT , the runtime must return XR_ERROR_VALIDATION_FAILURE from xrCreateSpatialDiscoverySnapshotAsyncEXT .
The runtime must treat the XrSpatialDiscoveryPersistenceUuidFilterEXT filter as an 'AND' condition with any other filters provided in XrSpatialDiscoverySnapshotCreateInfoEXT or its next chain. The runtime must treat the persistedUuids array itself as an 'OR' condition i.e. filter for entities that have any of the UUIDs provided in that array.
The runtime must include one entry in the created snapshot for each of the UUIDs in persistedUuids for which it was able to determine the XrSpatialPersistenceStateEXT state at this time.
If the runtime has successfully found the UUID in its storage, then -
- The runtime must set the XrSpatialPersistenceStateEXT in the XrSpatialPersistenceDataEXT of this entity to
XR_SPATIAL_PERSISTENCE_STATE_LOADED_EXT. - The runtime must include a valid
XrSpatialEntityIdEXTfor this entity in the created snapshot. - The runtime must set the XrSpatialEntityTrackingStateEXT of that entity to
XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXTif it is actively tracking the entity and has valid data for its components. Otherwise, the runtime must set the XrSpatialEntityTrackingStateEXT toXR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT.
- The runtime must set the XrSpatialPersistenceStateEXT in the XrSpatialPersistenceDataEXT of this entity to
If the runtime has determined that the UUID is not present in its storage (regardless of whether that UUID was never in the storage or has was present once but has since been unpersisted), then -
- The runtime must set the XrSpatialPersistenceStateEXT in the XrSpatialPersistenceDataEXT of this entity to
XR_SPATIAL_PERSISTENCE_STATE_NOT_FOUND_EXTto indicate to the application that this UUID is no longer present in the storage. - The runtime must set the
XrSpatialEntityIdEXTfor this entity in the created snapshot to XR_NULL_SPATIAL_ENTITY_ID_EXT . - The runtime must set the XrSpatialEntityTrackingStateEXT of that entity to
XR_SPATIAL_ENTITY_TRACKING_STATE_STOPPED_EXTto indicate to the application that this entity will never be tracked.
- The runtime must set the XrSpatialPersistenceStateEXT in the XrSpatialPersistenceDataEXT of this entity to
If the runtime was not able to determine if the UUID is present in its storage or not, it must not include it in the snapshot.
The application can also use XrSpatialDiscoveryPersistenceUuidFilterEXT in the next chain of XrSpatialComponentDataQueryConditionEXT to query for entities of specific UUIDs in existing snapshots. When used with XrSpatialComponentDataQueryConditionEXT , if XrSpatialDiscoveryPersistenceUuidFilterEXT :: persistedUuids contains any XrUuid that is not in the XrSpatialSnapshotEXT , the runtime must not include an entry for that XrUuid in the query result. Also, the order (sequence) of entities in the query result may not match the order of UUIDs provided in XrSpatialDiscoveryPersistenceUuidFilterEXT :: persistedUuids . Application should include XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT in XrSpatialComponentDataQueryConditionEXT :: componentTypes and XrSpatialComponentPersistenceListEXT in the next chain of XrSpatialComponentDataQueryResultEXT and then check the XrSpatialPersistenceDataEXT :: persistUuid of the each query result index to understand which UUID the current result index corresponds to.
Valid Usage (Implicit)
- The
XR_EXT_spatial_persistenceextension must be enabled prior to using XrSpatialDiscoveryPersistenceUuidFilterEXT -
typemust beXR_TYPE_SPATIAL_DISCOVERY_PERSISTENCE_UUID_FILTER_EXT -
nextmust beNULLor a valid pointer to the next structure in a structure chain -
persistedUuidsmust be a pointer to an array ofpersistedUuidCountXrUuid structures - The
persistedUuidCountparameter must be greater than0
Discover all persisted entities
If the application uses xrCreateSpatialDiscoverySnapshotAsyncEXT without XrSpatialDiscoveryPersistenceUuidFilterEXT and with an XrSpatialContextEXT which has been configured with an XrSpatialPersistenceContextEXT , then the runtime must include those entities in the created snapshot that are persisted in the storage represented by XrSpatialPersistenceContextEXT and satisfy the filters provided in XrSpatialDiscoverySnapshotCreateInfoEXT . For those entities -
- The runtime must set the XrSpatialPersistenceStateEXT in the XrSpatialPersistenceDataEXT of this entity to
XR_SPATIAL_PERSISTENCE_STATE_LOADED_EXT. - The runtime must include a valid
XrSpatialEntityIdEXTfor this entity in the created snapshot. - The runtime must set the XrSpatialEntityTrackingStateEXT of that entity to
XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXTif it is actively tracking the entity and has valid data for its components. Otherwise, the runtime must set the XrSpatialEntityTrackingStateEXT toXR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT.
New Object Types
New Commands
- xrCreateSpatialPersistenceContextAsyncEXT
- xrCreateSpatialPersistenceContextCompleteEXT
- xrDestroySpatialPersistenceContextEXT
- xrEnumerateSpatialPersistenceScopesEXT
New Structures
- XrCreateSpatialPersistenceContextCompletionEXT
- XrSpatialPersistenceContextCreateInfoEXT
- XrSpatialPersistenceDataEXT
Extending XrSpatialComponentDataQueryResultEXT :
Extending XrSpatialContextCreateInfoEXT :
Extending XrSpatialDiscoverySnapshotCreateInfoEXT , XrSpatialComponentDataQueryConditionEXT :
New Enums
New Enum Constants
XR_EXT_SPATIAL_PERSISTENCE_EXTENSION_NAMEXR_EXT_spatial_persistence_SPEC_VERSIONExtending XrObjectType :
XR_OBJECT_TYPE_SPATIAL_PERSISTENCE_CONTEXT_EXT
Extending XrResult :
XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_UNSUPPORTED_EXT
Extending XrSpatialComponentTypeEXT :
XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT
Extending XrStructureType :
XR_TYPE_CREATE_SPATIAL_PERSISTENCE_CONTEXT_COMPLETION_EXTXR_TYPE_SPATIAL_COMPONENT_PERSISTENCE_LIST_EXTXR_TYPE_SPATIAL_CONTEXT_PERSISTENCE_CONFIG_EXTXR_TYPE_SPATIAL_DISCOVERY_PERSISTENCE_UUID_FILTER_EXTXR_TYPE_SPATIAL_PERSISTENCE_CONTEXT_CREATE_INFO_EXT
Example Code
Create Persistence Context
// Check if the required persistence scope supported
uint32_t scopeCount;
CHK_XR(xrEnumerateSpatialPersistenceScopesEXT(instance, systemId, 0, &scopeCount, nullptr));
std::vector<XrSpatialPersistenceScopeEXT> persistenceScopes(scopeCount);
CHK_XR(xrEnumerateSpatialPersistenceScopesEXT(instance, systemId, scopeCount, &scopeCount, persistenceScopes.data()));
if (std::find(persistenceScopes.begin(), persistenceScopes.end(), XR_SPATIAL_PERSISTENCE_SCOPE_SYSTEM_MANAGED_EXT) == persistenceScopes.end()) {
return;
}
XrSpatialPersistenceContextEXT persistenceContext{};
XrSpatialPersistenceContextCreateInfoEXT persistenceContextCreateInfo{XR_TYPE_SPATIAL_PERSISTENCE_CONTEXT_CREATE_INFO_EXT};
persistenceContextCreateInfo.scope = XR_SPATIAL_PERSISTENCE_SCOPE_SYSTEM_MANAGED_EXT;
XrFutureEXT createContextFuture;
CHK_XR(xrCreateSpatialPersistenceContextAsyncEXT(session, &persistenceContextCreateInfo, &createContextFuture));
waitUntilReady(createContextFuture);
XrCreateSpatialPersistenceContextCompletionEXT completion{XR_TYPE_CREATE_SPATIAL_PERSISTENCE_CONTEXT_COMPLETION_EXT};
CHK_XR(xrCreateSpatialPersistenceContextCompleteEXT(session, createContextFuture, &completion));
if (completion.futureResult != XR_SUCCESS || completion.createResult != XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_SUCCESS_EXT) {
return;
}
persistenceContext = completion.persistenceContext;
// ...
// Connect persistence context to a spatial context and discover persisted entities.
// ...
CHK_XR(xrDestroySpatialPersistenceContextEXT(persistenceContext));
Connect Persistence Context to a Spatial Context
// Note: Anchor capability is just used as an example here. Persistence can be
// supported by other capabilities too. xrEnumerateSpatialCapabilityComponentTypesEXT() can
// be used to check if a certain capability supports persistence.
if (!isSpatialCapabilitySupported(instance, systemId, XR_SPATIAL_CAPABILITY_ANCHOR_EXT)) {
return;
}
const bool supportsPersistenceComponent = isSpatialComponentSupported(instance, systemId, XR_SPATIAL_CAPABILITY_ANCHOR_EXT, XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT);
// Create a spatial spatial context
XrSpatialContextEXT spatialContext{};
{
std::vector<XrSpatialComponentTypeEXT> enabledComponents = {
XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT,
};
if (supportsPersistenceComponent) {
enabledComponents.push_back(XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT);
}
XrSpatialCapabilityConfigurationAnchorEXT anchorConfig{XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXT};
anchorConfig.capability = XR_SPATIAL_CAPABILITY_ANCHOR_EXT;
anchorConfig.enabledComponentCount = enabledComponents.size();
anchorConfig.enabledComponents = enabledComponents.data();
std::array<XrSpatialCapabilityConfigurationBaseHeaderEXT*, 1> capabilityConfigs = {
reinterpret_cast<XrSpatialCapabilityConfigurationBaseHeaderEXT*>(&anchorConfig),
};
XrSpatialContextCreateInfoEXT spatialContextCreateInfo{XR_TYPE_SPATIAL_CONTEXT_CREATE_INFO_EXT};
spatialContextCreateInfo.capabilityConfigCount = capabilityConfigs.size();
spatialContextCreateInfo.capabilityConfigs = capabilityConfigs.data();
XrSpatialContextPersistenceConfigEXT persistenceConfig{XR_TYPE_SPATIAL_CONTEXT_PERSISTENCE_CONFIG_EXT};
persistenceConfig.persistenceContextCount = 1;
persistenceConfig.persistenceContexts = &persistenceContext;
if (supportsPersistenceComponent) {
spatialContextCreateInfo.next = &persistenceConfig;
}
XrFutureEXT createContextFuture;
CHK_XR(xrCreateSpatialContextAsyncEXT(session, &spatialContextCreateInfo, &createContextFuture));
waitUntilReady(createContextFuture);
XrCreateSpatialContextCompletionEXT completion{XR_TYPE_CREATE_SPATIAL_CONTEXT_COMPLETION_EXT};
CHK_XR(xrCreateSpatialContextCompleteEXT(session, createContextFuture, &completion));
if (completion.futureResult != XR_SUCCESS) {
return;
}
spatialContext = completion.spatialContext;
}
// ...
// Discover persisted anchors.
// ...
CHK_XR(xrDestroySpatialContextEXT(spatialContext));
Discover all persisted entities
XrFutureEXT future = XR_NULL_FUTURE_EXT;
// We want to look for entities that have the following components.
std::vector<XrSpatialComponentTypeEXT> snapshotComponents = {
XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT,
};
auto discoverSpatialEntities = [&](XrSpatialContextEXT spatialContext, XrTime time) {
XrSpatialDiscoverySnapshotCreateInfoEXT snapshotCreateInfo{XR_TYPE_SPATIAL_DISCOVERY_SNAPSHOT_CREATE_INFO_EXT};
snapshotCreateInfo.componentTypeCount = snapshotComponents.size();
snapshotCreateInfo.componentTypes = snapshotComponents.data();
CHK_XR(xrCreateSpatialDiscoverySnapshotAsyncEXT(spatialContext, &snapshotCreateInfo, &future));
waitUntilReady(future);
XrCreateSpatialDiscoverySnapshotCompletionInfoEXT completionInfo{XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_INFO_EXT};
completionInfo.baseSpace = localSpace;
completionInfo.time = time;
completionInfo.future = future;
XrCreateSpatialDiscoverySnapshotCompletionEXT completion{XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_EXT};
CHK_XR(xrCreateSpatialDiscoverySnapshotCompleteEXT(spatialContext, &completionInfo, &completion));
if (completion.futureResult == XR_SUCCESS) {
// Query for the semantic label component data
XrSpatialComponentDataQueryConditionEXT queryCond{XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_CONDITION_EXT};
queryCond.componentTypeCount = snapshotComponents.size();
queryCond.componentTypes = snapshotComponents.data();
XrSpatialComponentDataQueryResultEXT queryResult{XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_RESULT_EXT};
CHK_XR(xrQuerySpatialComponentDataEXT(completion.snapshot, &queryCond, &queryResult));
std::vector<XrSpatialEntityIdEXT> entityIds(queryResult.entityIdCountOutput);
std::vector<XrSpatialEntityTrackingStateEXT> entityStates(queryResult.entityIdCountOutput);
queryResult.entityIdCapacityInput = entityIds.size();
queryResult.entityIds = entityIds.data();
queryResult.entityStateCapacityInput = entityStates.size();
queryResult.entityStates = entityStates.data();
std::vector<XrSpatialPersistenceDataEXT> persistenceData(queryResult.entityIdCountOutput);
XrSpatialComponentPersistenceListEXT persistenceDataList{XR_TYPE_SPATIAL_COMPONENT_PERSISTENCE_LIST_EXT};
persistenceDataList.persistDataCount = persistenceData.size();
persistenceDataList.persistData = persistenceData.data();
queryResult.next = &persistenceDataList;
CHK_XR(xrQuerySpatialComponentDataEXT(completion.snapshot, &queryCond, &queryResult));
for (int32_t i = 0; i < queryResult.entityIdCountOutput; ++i) {
// persistenceData[i].persistUuid is the UUID of the persisted entity whose entity ID is entityIds[i].
// The persistenceData array is essentially the uuids persisted in the scope that the current
// XrSpatialPersistenceContextEXT is configured with.
}
CHK_XR(xrDestroySpatialSnapshotEXT(completion.snapshot));
}
};
while (1) {
// ...
// For every frame in frame loop
// ...
XrFrameState frameState; // previously returned from xrWaitFrame
const XrTime time = frameState.predictedDisplayTime;
// Poll for the XR_TYPE_EVENT_DATA_SPATIAL_DISCOVERY_RECOMMENDED_EXT event
XrEventDataBuffer event = {XR_TYPE_EVENT_DATA_BUFFER};
XrResult result = xrPollEvent(instance, &event);
if (result == XR_SUCCESS) {
switch (event.type) {
case XR_TYPE_EVENT_DATA_SPATIAL_DISCOVERY_RECOMMENDED_EXT: {
const XrEventDataSpatialDiscoveryRecommendedEXT& eventdata =
*reinterpret_cast<XrEventDataSpatialDiscoveryRecommendedEXT*>(&event);
// Discover spatial entities for the context that we received the "discovery
// recommended" event for.
discoverSpatialEntities(eventdata.spatialContext, time);
break;
}
}
}
// ...
// Finish frame loop
// ...
}
Discover entities with specific UUIDs
XrFutureEXT future = XR_NULL_FUTURE_EXT;
// Load up the uuids that the app has stored on its own i.e. the uuids it is interested in.
std::vector<XrUuid> uuidsStoredByApp = loadPersistedUuids();
// We want to look for entities that have the following components.
std::vector<XrSpatialComponentTypeEXT> snapshotComponents = {
XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT,
};
auto discoverSpatialEntities = [&](XrSpatialContextEXT spatialContext, XrTime time) {
XrSpatialDiscoveryPersistenceUuidFilterEXT persistenceFilter{XR_TYPE_SPATIAL_DISCOVERY_PERSISTENCE_UUID_FILTER_EXT};
persistenceFilter.persistedUuidCount = uuidsStoredByApp.size();
persistenceFilter.persistedUuids = uuidsStoredByApp.data();
XrSpatialDiscoverySnapshotCreateInfoEXT snapshotCreateInfo{XR_TYPE_SPATIAL_DISCOVERY_SNAPSHOT_CREATE_INFO_EXT};
snapshotCreateInfo.componentTypeCount = snapshotComponents.size();
snapshotCreateInfo.componentTypes = snapshotComponents.data();
snapshotCreateInfo.next = &persistenceFilter;
CHK_XR(xrCreateSpatialDiscoverySnapshotAsyncEXT(spatialContext, &snapshotCreateInfo, &future));
waitUntilReady(future);
XrCreateSpatialDiscoverySnapshotCompletionInfoEXT completionInfo{XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_INFO_EXT};
completionInfo.baseSpace = localSpace;
completionInfo.time = time;
completionInfo.future = future;
XrCreateSpatialDiscoverySnapshotCompletionEXT completion{XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_EXT};
CHK_XR(xrCreateSpatialDiscoverySnapshotCompleteEXT(spatialContext, &completionInfo, &completion));
if (completion.futureResult == XR_SUCCESS) {
// Query for the semantic label component data
XrSpatialComponentDataQueryConditionEXT queryCond{XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_CONDITION_EXT};
queryCond.componentTypeCount = snapshotComponents.size();
queryCond.componentTypes = snapshotComponents.data();
XrSpatialComponentDataQueryResultEXT queryResult{XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_RESULT_EXT};
CHK_XR(xrQuerySpatialComponentDataEXT(completion.snapshot, &queryCond, &queryResult));
std::vector<XrSpatialEntityIdEXT> entityIds(queryResult.entityIdCountOutput);
std::vector<XrSpatialEntityTrackingStateEXT> entityStates(queryResult.entityIdCountOutput);
queryResult.entityIdCapacityInput = entityIds.size();
queryResult.entityIds = entityIds.data();
queryResult.entityStateCapacityInput = entityStates.size();
queryResult.entityStates = entityStates.data();
std::vector<XrSpatialPersistenceDataEXT> persistenceData(queryResult.entityIdCountOutput);
XrSpatialComponentPersistenceListEXT persistenceDataList{XR_TYPE_SPATIAL_COMPONENT_PERSISTENCE_LIST_EXT};
persistenceDataList.persistDataCount = persistenceData.size();
persistenceDataList.persistData = persistenceData.data();
queryResult.next = &persistenceDataList;
CHK_XR(xrQuerySpatialComponentDataEXT(completion.snapshot, &queryCond, &queryResult));
for (int32_t i = 0; i < queryResult.entityIdCountOutput; ++i) {
if (persistenceData[i].persistState == XR_SPATIAL_PERSISTENCE_STATE_LOADED_EXT) {
// persistenceData[i].persistUuid, requested by the app, is present in the persistence scope
// and its corresponding entity ID and state are entityIds[i] & entityStates[i] respectively.
} else if (persistenceData[i].persistState == XR_SPATIAL_PERSISTENCE_STATE_NOT_FOUND_EXT) {
// persistenceData[i].persistUuid, requested by the app, is NOT present in the persistence scope
// and its corresponding entity ID (entityIds[i]) would be XR_NULL_SPATIAL_ENTITY_ID_EXT
// and tracking state (entityStates[i]) would be XR_SPATIAL_ENTITY_TRACKING_STATE_STOPPED_EXT.
}
}
CHK_XR(xrDestroySpatialSnapshotEXT(completion.snapshot));
}
};
while (1) {
// ...
// For every frame in frame loop
// ...
XrFrameState frameState; // previously returned from xrWaitFrame
const XrTime time = frameState.predictedDisplayTime;
// Poll for the XR_TYPE_EVENT_DATA_SPATIAL_DISCOVERY_RECOMMENDED_EXT event
XrEventDataBuffer event = {XR_TYPE_EVENT_DATA_BUFFER};
XrResult result = xrPollEvent(instance, &event);
if (result == XR_SUCCESS) {
switch (event.type) {
case XR_TYPE_EVENT_DATA_SPATIAL_DISCOVERY_RECOMMENDED_EXT: {
const XrEventDataSpatialDiscoveryRecommendedEXT& eventdata =
*reinterpret_cast<XrEventDataSpatialDiscoveryRecommendedEXT*>(&event);
// Discover spatial entities for the context that we received the "discovery
// recommended" event for.
discoverSpatialEntities(eventdata.spatialContext, time);
break;
}
}
}
// ...
// Finish frame loop
// ...
}
Issues
Version History
Revision 1, 2024-08-29 (Nihav Jain, Google)
- Initial extension description