XR_ANDROID_spatial_component_subsumed_by

Name String

XR_ANDROID_spatial_component_subsumed_by

Extension Type

Instance extension

Registered Extension Number

792

Revision

1

Ratification Status

Not ratified

Extension and Version Dependencies

XR_EXT_spatial_entity
and
XR_EXT_spatial_plane_tracking

Last Modified Date

2025-08-19

IP Status

No known IP claims.

Contributors

Brian Chen, Google
Kyle Chen, Google
Levana Chen, Google
Nihav Jain, Google
Spencer Quin, Google

Overview

This extension builds on XR_EXT_spatial_entity and provides a new component for XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT to expose the XrSpatialEntityIdEXT that subsumes the current entity.

When the runtime has acquired enough environment information to detect that 2 tracked planes are actually the same, the XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID component with the ID of one of the planes is attached to the other. From then on, the application only needs to process the entity that does not have the XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID component.

This extension also introduces a new filter, which the application can chain to XrSpatialDiscoverySnapshotCreateInfoEXT to filter out any entities that have the XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID component.

Permissions

Android applications must have the android.permission.SCENE_UNDERSTANDING_COARSE permission listed in their manifest as this extension tracks planes in the environment. The android.permission.SCENE_UNDERSTANDING_COARSE permission is considered a dangerous permission.

(protection level: dangerous)

Runtime Support

If the runtime is capable of subsuming one plane into another, it must indicate this by enumerating XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID as a supported component for XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT capability in xrEnumerateSpatialCapabilityComponentTypesEXT .

All the component data of the XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID attached entity must be identical to the entity that subsumes it.

Subsumed By Component

Component data

XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID uses the XrSpatialEntityIdEXT structure for its data, which represents the ID of the subsuming entity.

Component list struct to query data

The XrSpatialComponentSubsumedByListANDROID structure is defined as:

typedef struct XrSpatialComponentSubsumedByListANDROID {
    XrStructureType          type;
    void*                    next;
    uint32_t                 subsumedUniqueIdCount;
    XrSpatialEntityIdEXT*    subsumedUniqueIds;
} XrSpatialComponentSubsumedByListANDROID;

Member Descriptions

  • type is the XrStructureType of this structure.
  • next is NULL or a pointer to the next structure in a structure chain.
  • subsumedUniqueIdCount is a uint32_t describing the count of elements in the subsumedUniqueIds array.
  • subsumedUniqueIds is an array of XrSpatialEntityIdEXT .

The application can query the XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID component of the spatial entities in an XrSpatialSnapshotEXT by adding XR_TYPE_SPATIAL_COMPONENT_SUBSUMED_BY_LIST_ANDROID to the next chain of the XrSpatialComponentDataQueryResultEXT .

The runtime must return XR_ERROR_VALIDATION_FAILURE from xrQuerySpatialComponentDataEXT if XR_TYPE_SPATIAL_COMPONENT_SUBSUMED_BY_LIST_ANDROID is in the next chain of XrSpatialComponentDataQueryResultEXT :: next but XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID is not included in XrSpatialComponentDataQueryConditionEXT :: componentTypes .

The runtime must return XR_ERROR_SIZE_INSUFFICIENT from xrQuerySpatialComponentDataEXT if subsumedUniqueIdCount is less than XrSpatialComponentDataQueryResultEXT :: entityIdCountOutput .

Valid Usage (Implicit)

  • The XR_ANDROID_spatial_component_subsumed_by extension must be enabled prior to using XrSpatialComponentSubsumedByListANDROID
  • type must be XR_TYPE_SPATIAL_COMPONENT_SUBSUMED_BY_LIST_ANDROID
  • next must be NULL or a valid pointer to the next structure in a structure chain
  • subsumedUniqueIds must be a pointer to an array of subsumedUniqueIdCount XrSpatialEntityIdEXT values
  • The subsumedUniqueIdCount parameter must be greater than 0

Configuration

If XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID is enumerated in XrSpatialCapabilityComponentTypesEXT :: componentTypes for XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT capability, the application can enable it by including the enum in the XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents list of the XrSpatialCapabilityConfigurationBaseHeaderEXT derived structure of the capability that supports this component.

Filter Subsumed Entities

The XrSpatialDiscoveryUniqueEntitiesFilterANDROID structure is defined as:

typedef struct XrSpatialDiscoveryUniqueEntitiesFilterANDROID {
    XrStructureType    type;
    const void*        next;
} XrSpatialDiscoveryUniqueEntitiesFilterANDROID;

Member Descriptions

  • type is the XrStructureType of this structure.
  • next is NULL or a pointer to the next structure in a structure chain.

The application can include XrSpatialDiscoveryUniqueEntitiesFilterANDROID in the next chain of XrSpatialDiscoverySnapshotCreateInfoEXT to get a snapshot with entities that are not subsumed by another entity.

If applications chain XrSpatialDiscoveryUniqueEntitiesFilterANDROID to XrSpatialDiscoverySnapshotCreateInfoEXT while including XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID component in the XrSpatialDiscoverySnapshotCreateInfoEXT :: componentTypes , the runtime must return XR_ERROR_VALIDATION_FAILURE .

If application chains XrSpatialDiscoveryUniqueEntitiesFilterANDROID to XrSpatialDiscoverySnapshotCreateInfoEXT but does not list any components in XrSpatialDiscoverySnapshotCreateInfoEXT :: componentTypes , the runtime must include all the spatial entities in the snapshot that have the set of components which are enumerated in XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents for the capabilities configured for spatialContext , except entities that have the XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID component.

Valid Usage (Implicit)

Example code

Configure Plane Tracking Capability

The following example code demonstrates how to create a spatial context with XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT capability that supports XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID .

// Check runtime supported capabilities
uint32_t capabilityCount = 0;
CHK_XR(xrEnumerateSpatialCapabilitiesEXT(instance, systemId, 0, &capabilityCount, nullptr));
std::vector<XrSpatialCapabilityEXT> capabilities(capabilityCount);
CHK_XR(xrEnumerateSpatialCapabilitiesEXT(instance, systemId, capabilityCount, &capabilityCount, capabilities.data()));

if (std::find(capabilities.begin(), capabilities.end(), XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT) == capabilities.end()) {
  return;
}

// Enumerate supported components for plane tracking capability
XrSpatialCapabilityComponentTypesEXT planeComponents{
  .type = XR_TYPE_SPATIAL_CAPABILITY_COMPONENT_TYPES_EXT,
};
CHK_XR(xrEnumerateSpatialCapabilityComponentTypesEXT(instance, systemId, XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT, &planeComponents));
std::vector<XrSpatialComponentTypeEXT> planeCapabilityComponents(planeComponents.componentTypeCountOutput);
planeComponents.componentTypeCapacityInput = planeCapabilityComponents.size();
planeComponents.componentTypes = planeCapabilityComponents.data();
CHK_XR(xrEnumerateSpatialCapabilityComponentTypesEXT(instance, systemId, XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT, &planeComponents));

const auto supportsComponent = [&planeCapabilityComponents](XrSpatialComponentTypeEXT component) {
  return std::find(planeCapabilityComponents.begin(), planeCapabilityComponents.end(), component) != planeCapabilityComponents.end();
};


std::vector<XrSpatialComponentTypeEXT> planeTrackingComponents {
  XR_SPATIAL_COMPONENT_TYPE_BOUNDED_2D_EXT,
  XR_SPATIAL_COMPONENT_TYPE_PLANE_ALIGNMENT_EXT,
};

if (supportsComponent(XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID)) {
  planeTrackingComponents.push_back(XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID);
}

// Create capability config for plane tracking
XrSpatialCapabilityConfigurationPlaneTrackingEXT planeTrackingConfig {
  .type = XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_PLANE_TRACKING_EXT,
  .next = nullptr,
  .capability = XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT,
  .enabledComponentCount = (uint32_t)planeTrackingComponents.size(),
  .enabledComponents = planeTrackingComponents.data(),
};

// Create spatial context
std::vector<const XrSpatialCapabilityConfigurationBaseHeaderEXT*> capabilityConfigs;
capabilityConfigs.push_back(reinterpret_cast<const XrSpatialCapabilityConfigurationBaseHeaderEXT*>(&planeTrackingConfig));

XrSpatialContextCreateInfoEXT contextCreateInfo {
  .type = XR_TYPE_SPATIAL_CONTEXT_CREATE_INFO_EXT,
  .next = nullptr,
  .capabilityConfigCount = (uint32_t)capabilityConfigs.size(),
  .capabilityConfigs = capabilityConfigs.data(),
};

CHK_XR(xrCreateSpatialContextAsyncEXT(session, &contextCreateInfo, &future))

// Completes creating spatial context
XrCreateSpatialContextCompletionEXT contextCompletion{
XR_TYPE_CREATE_SPATIAL_CONTEXT_COMPLETION_EXT};

CHK_XR(xrCreateSpatialContextCompleteEXT(session, future, &contextCompletion))

Query Component Data

The following example code demonstrates how to query XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID component data from context configured with XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT .

// previously created
XrSpatialSnapshotEXT snapshot;

// Query subsumed_by components
std::array<XrSpatialComponentTypeEXT, 1> enabledComponents = {
  XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID
};

XrSpatialComponentDataQueryConditionEXT queryCond {
  .type = XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_CONDITION_EXT,
  .componentTypeCount = 1,
  .componentTypes     = enabledComponents.data(),
};

XrSpatialComponentDataQueryResultEXT queryResult {
  .type = XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_RESULT_EXT,
};

CHK_XR(xrQuerySpatialComponentDataEXT(
           snapshot, &queryCond, &queryResult));

// Query again with allocated memory
std::vector<XrSpatialEntityIdEXT> subsumedUniqueIds;
subsumedUniqueIds.resize(queryResult.entityIdCountOutput);
XrSpatialComponentSubsumedByListANDROID subsumedByList {
  .type = XR_TYPE_SPATIAL_COMPONENT_SUBSUMED_BY_LIST_ANDROID,
  .subsumedUniqueIdCount = static_cast<uint32_t>(subsumedUniqueIds.size()),
  .subsumedUniqueIds = subsumedUniqueIds.data(),
};

queryResult.next = &subsumedByList;
CHK_XR(xrQuerySpatialComponentDataEXT(
           snapshot, &queryCond, &queryResult));

for (uint32_t i = 0; i < queryResult.entityIdCountOutput; ++i) {
  // Plane was subsumed, remove it from processing logic
  // removeEntityFromProcessingLogic(queryResult.entityIds[i], /*replaceWith=*/ subsumedByList.subsumedUniqueIds[i]);
}

// Cleanup
xrDestroySpatialSnapshotEXT(snapshot);

Filter Out Subsumed Entities

The following example code demonstrates how to filter out entities with XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID component attached from discovery snapshot using the filter, as well as query the entity id of the subsuming entities.

// Init filter
XrSpatialDiscoveryUniqueEntitiesFilterANDROID filter {
  .type = XR_TYPE_SPATIAL_DISCOVERY_UNIQUE_ENTITIES_FILTER_ANDROID,
};

// Chain filter to the snapshot create info
// WARNING: Chaining the filter while include subsumed_by component in the
// componentTypes is invalid
XrSpatialDiscoverySnapshotCreateInfoEXT discoverySnapshotCreateInfo {
  .type = XR_TYPE_SPATIAL_DISCOVERY_SNAPSHOT_CREATE_INFO_EXT,
  .next = &filter
};

XrFutureEXT future {XR_NULL_FUTURE_EXT};
CHK_XR(xrCreateSpatialDiscoverySnapshotAsyncEXT(spatialContext, &discoverySnapshotCreateInfo, &future))

waitUntilReady(future);

// Complete async operation.
XrCreateSpatialDiscoverySnapshotCompletionInfoEXT
  createSnapshotCompletionInfo {
    .type   = XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_INFO_EXT,
    .baseSpace = space,
    .time      = updateTime,
    .future    = future,
  };

XrCreateSpatialDiscoverySnapshotCompletionEXT completion {
  .type = XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_EXT,
};

CHK_XR(xrCreateSpatialDiscoverySnapshotCompleteEXT(
           spatialContext, &createSnapshotCompletionInfo,
           &completion));

if(completion.futureResult != XR_SUCCESS) return;

// Subsumed entities has already been filtered out in this snapshot,
// now query the various components of the entities.

// Cleanup
xrDestroySpatialSnapshotEXT(completion.snapshot);

New Structures

New Enum Constants

  • XR_ANDROID_SPATIAL_COMPONENT_SUBSUMED_BY_EXTENSION_NAME
  • XR_ANDROID_spatial_component_subsumed_by_SPEC_VERSION
  • Extending XrSpatialComponentTypeEXT :

    • XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID
  • Extending XrStructureType :

    • XR_TYPE_SPATIAL_COMPONENT_SUBSUMED_BY_LIST_ANDROID
    • XR_TYPE_SPATIAL_DISCOVERY_UNIQUE_ENTITIES_FILTER_ANDROID

Issues

Version History

  • Revision 1, 2025-11-19 (Brian Chen)

    • Initial extension description.