Develop
Develop
Select your platform

Upgrade Guide For Production API

This document describes migrating from experimental versions of Local Spatial Anchors to the production API that we are releasing with V40.

Before (Experimental)

In experimental versions of the XR_FB_spatial_entity extensions, the experimental version had to be specified before each header include as below:
#include <openxr/openxr.h>

#ifndef XR_FB_spatial_entity
#define XR_FB_spatial_entity_EXPERIMENTAL_VERSION 2
#include <openxr/fb_spatial_entity.h>
#endif

#ifndef XR_FB_spatial_entity_storage
#define XR_FB_spatial_entity_storage_EXPERIMENTAL_VERSION 2
#include <openxr/fb_spatial_entity_storage.h>
#endif

#ifndef XR_FB_spatial_entity_query
#define XR_FB_spatial_entity_query_EXPERIMENTAL_VERSION 2
#include <openxr/fb_spatial_entity_query.h>
#endif

After (Production with Headers from Meta OpenXR SDK)

To switch to production versions of the XR_FB_spatial_entity extensions, do not specify the experimental version.
#include <openxr/openxr.h>
Specifying required extensions when enumerating extensions will be the same as before since removing the experimental version definitions should switch the extension names from experimental to their production counterparts.
You should switch the function pointer acquisition to use the new function names listed below.
OXR(xrGetInstanceProcAddr(
  instance,
  "xrCreateSpatialAnchorFB",
  (PFN_xrVoidFunction*)(&app.FunPtrs.xrCreateSpatialAnchorFB)));

OXR(xrGetInstanceProcAddr(
  instance,
  "xrEnumerateSpaceSupportedComponentsFB",
  (PFN_xrVoidFunction*)(&app.FunPtrs.xrEnumerateSpaceSupportedComponentsFB)));

OXR(xrGetInstanceProcAddr(
  instance,
  "xrGetSpaceComponentStatusFB",
  (PFN_xrVoidFunction*)(&app.FunPtrs.xrGetSpaceComponentStatusFB)));

OXR(xrGetInstanceProcAddr(
  instance,
  "xrSetSpaceComponentStatusFB",
  (PFN_xrVoidFunction*)(&app.FunPtrs.xrSetSpaceComponentStatusFB)));

OXR(xrGetInstanceProcAddr(
  instance, "xrQuerySpacesFB", (PFN_xrVoidFunction*)(&app.FunPtrs.xrQuerySpacesFB)));

OXR(xrGetInstanceProcAddr(
  instance,
  "xrRetrieveSpaceQueryResultsFB",
  (PFN_xrVoidFunction*)(&app.FunPtrs.xrRetrieveSpaceQueryResultsFB)));

OXR(xrGetInstanceProcAddr(
  instance, "xrSaveSpaceFB", (PFN_xrVoidFunction*)(&app.FunPtrs.xrSaveSpaceFB)));

OXR(xrGetInstanceProcAddr(
  instance, "xrEraseSpaceFB", (PFN_xrVoidFunction*)(&app.FunPtrs.xrEraseSpaceFB)));

After (Production with Headers from Khronos SDK)

Once we have included the XR_FB_spatial_entity extensions in the Khronos SDK, you will no longer need to include the extension headers separately:
#include <openxr/openxr.h>
The function pointer acquisition and extension enumeration tasks remain the same, as documented below.

Flow Changes

Asynchronous Spatial Anchor Creation

Spatial Anchor Creation is now asynchronous.
 Before (Experimental)After (Production)
Function name (no change)
xrCreateSpatialAnchorFB
xrCreateSpatialAnchorFB
Function signature
(XrSession, XrSpatialAnchorCreateInfoFB, *XrSpace)
 
(XrSession, XrSpatialAnchorCreateInfoFB, *XrAsyncRequestIdFB)
 
 
Create complete EventData
(N/A, synchronous completion)
XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB
EventData struct
(N/A, synchronous completion)
XrEventDataSpatialAnchorCreateCompleteFB

Example Code (Production API)

// Assumptions:
//   ContentObject is some app-defined class representing content
//     that can be attached to an Anchor.
//   contentToAttachToNewAnchor is some std::vector of content objects
//     that was populated before initiating the xrCreateSpatialAnchorFB(3)
//     call.

// These maps should be visible from both the code making the
// xrCreateSpatialAnchorFB call and from the event handler code.
std::unordered_map<XrAsyncRequestId, std::vector<ContentObject>> anchorCreationRequests;
std::unordered_map<XrSpace, std::vector<ContentObject>> anchorToContentMap;
. . .
XrSpatialAnchorCreateInfoFB anchorCreateInfo = {XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_FB};
anchorCreateInfo.space = app.LocalSpace;
anchorCreateInfo.poseInSpace = ToXrPosef(localFromRightAim);
anchorCreateInfo.time = frameState.predictedDisplayTime;
XrAsyncRequestIdFB createRequest;
OXR(app.FunPtrs.xrCreateSpatialAnchorFB(app.Session, &anchorCreateInfo, &createRequest));

// Associate the content to be attached with the creation request ID
// so that it can be attached to the Anchor on completion of the create operation.
anchorCreationRequests.insert_or_assign(createRequest, contentToAttachToNewAnchor);

. . .

. . .

// Event handler code
case XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB: {
  const XrEventDataSpatialAnchorCreateCompleteFB* createAnchorResult =
    (XrEventDataSpatialAnchorCreateCompleteFB*)(baseEventHeader);
  XrSpace space = createAnchorResult->space;

  // Set up the content attachment to Spatial Anchor.
  XrAsyncRequestIdFB creationRequestId = createAnchorResult->requestId;
  if (anchorCreationRequests.contains(creationRequestId) {
    anchorToContentMap.insert_or_assign(
        space, anchorCreationRequests[creationRequestId]);
    anchorCreationRequests.erase(creationRequestId);
  }

  // The optional blob below is an example of immediately saving
  // (persisting) the Spatial Anchor that was just created.
  if (IsComponentSupported(space, XR_SPACE_COMPONENT_TYPE_STORABLE_FB)) {
    XrSpaceComponentStatusSetInfoFB request = {
      XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB,
      nullptr,
      XR_SPACE_COMPONENT_TYPE_STORABLE_FB,
      XR_TRUE,
      0};

    XrAsyncRequestIdFB requestId;
    XrResult res = FunPtrs.xrSetSpaceComponentStatusFB(space,
      &request, &saveRequestId);
    if (res == XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB) {
      XrSpaceSaveInfoFB saveInfo = {
        XR_TYPE_SPACE_SAVE_INFO_FB,
        nullptr,
        space,
        XR_SPACE_STORAGE_LOCATION_LOCAL_FB,
        XR_SPACE_PERSISTENCE_MODE_INDEFINITE_FB};

      // save the space
      OXR(FunPtrs.xrSaveSpaceFB(Session, &saveInfo, &requestId));
    }
  }
} break;
. . .

Anchor Query Results Retrieval

 Before (Experimental)After (Production)
Query complete EventData type (no functional change)
XR_TYPE_EVENT_SPATIAL_ENTITY_QUERY_COMPLETE_FB
XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB
Query results EventData type
XR_TYPE_EVENT_SPATIAL_ENTITY_QUERY_RESULTS_AVAILABLE_FB
XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB
Query results EventData struct name (no field changes)
XrEventSpatialEntityQueryResultsAvailableFB
XrEventDataSpaceQueryResultsAvailableFB
Fetching query results function
(N/A, results come in the query results EventData payload)
xrRetrieveSpaceQueryResultsFB
Fetching query results function signature
(N/A, results come in the query results EventData payload)
(XrAsyncRequestIdFB, uint32_t (resultCapacityInput), uint32_t* (resultCountOutput), XrSpatialEntityQueryResultFB*)
Fetching query results synchronous, 2-call idiom
(N/A, results come in the query results EventData payload)
xrRetrieveSpaceQueryResultsFB called twice following OpenXR two-call idiom

Query Flow

Before (Experimental)After (Production)
Call xrQuerySpatialEntityFB to initiate a query request. Await the XR_TYPE_EVENT_SPATIAL_ENTITY_QUERY_RESULTS_FB event and access the data in the XrSpatialEntityQueryResultFB struct directly.
Call xrQuerySpacesFB to initiate a query request. Await the XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB event. Call xrRetrieveSpaceQueryResultsFB two times using the 2-call idiom to first populate the length of the results, and then to populate the results themselves in the XrSpaceQueryResultsFB struct.

Example Code (Production API)

case XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB: {
  const auto resultsAvailable =
    (XrEventDataSpaceQueryResultsAvailableFB*)baseEventHeader;
  XrResult res = XR_SUCCESS;
  XrSpaceQueryResultsFB queryResults{XR_TYPE_SPACE_QUERY_RESULTS_FB};
  res = FunPtrs.xrRetrieveSpaceQueryResultsFB(
    Session, resultsAvailable->requestId, &queryResults);
  if (res != XR_SUCCESS) {
    break;
  }
  std::vector<XrSpaceQueryResultFB> results(queryResults.resultCountOutput);
  queryResults.resultCapacityInput = results.size();
  queryResults.results = results.data();
  res = FunPtrs.xrRetrieveSpaceQueryResultsFB(
    Session, resultsAvailable->requestId, &queryResults);
  for (uint32_t i = 0; i < queryResults.resultCountOutput; ++i) {
    . . .
  }
} break;

Renamed Functions

Before (Experimental)After (Production)
xrCreateSpatialAnchorFB
xrCreateSpatialAnchorFB
xrSetComponentEnabledFB
xrSetSpaceComponentStatusFB
xrGetComponentStatusFB
xrGetSpaceComponentStatusFB
xrEnumerateSupportedComponentsFB
xrEnumerateSpaceSupportedComponentsFB
xrSpatialEntityStorageSaveFB
xrSaveSpaceFB
xrSpatialEntityStorageEraseFB
xrEraseSpaceFB
xrQuerySpatialEntityFB
xrQuerySpacesFB
(new)
xrRetrieveSpaceQueryResultsFB

Renamed Function Pointer Types

Before (Experimental)After (Production)
PFN_xrCreateSpatialAnchorFB
PFN_xrCreateSpatialAnchorFB
PFN_xrSetComponentEnabledFB
PFN_xrSetSpaceComponentStatusFB
PFN_xrGetComponentStatusFB
PFN_xrGetSpaceComponentStatusFB
PFN_xrEnumerateSupportedComponentsFB
PFN_xrEnumerateSpaceSupportedComponentsFB
PFN_xrSpatialEntityStorageSaveFB
PFN_xrSaveSpaceFB
PFN_xrSpatialEntityStorageEraseFB
PFN_xrEraseSpaceFB
PFN_xrQuerySpatialEntityFB
PFN_xrQuerySpacesFB
(new)
PFN_xrRetrieveSpaceQueryResultsFB

Renamed Structs

Before (Experimental)After (Production)
XrSpatialEntityUuid
*XrUuidEXT
XrSpatialAnchorCreateInfoFB
XrSpatialAnchorCreateInfo (no change)
XrComponentEnableRequestFB
XrSpaceComponentStatusSetInfoFB
XrComponentStatusFB
XrSpaceComponentStatusFB
XrSpatialEntityStorageSaveInfoFB
XrSpaceSaveInfoFB
XrSpatialEntityStorageEraseInfoFB
XrSpaceEraseInfoFB
XrSpatialEntityQueryInfoBaseHeaderFB
XrSpaceQueryInfoBaseHeaderFB
XrSpatialEntityFilterInfoBaseHeaderFB
XrSpaceFilterInfoBaseHeaderFB
XrSpatialEntityStorageLocationFilterInfoFB
XrSpaceStorageLocationFilterInfoFB
XrSpatialEntityQueryFilterIdsFB
XrSpaceUuidFilterInfoFB
XrSpatialEntityQueryResultFB
XrSpaceQueryResultFB

Renamed Struct Types

Before (Experimental)After (Production)
XR_TYPE_COMPONENT_ENABLE_REQUEST_FB
XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB
XR_TYPE_COMPONENT_STATUS_FB
XR_TYPE_SPACE_COMPONENT_STATUS_FB
XR_TYPE_SPATIAL_ENTITY_STORAGE_SAVE_INFO_FB
XR_TYPE_SPACE_SAVE_INFO_FB
XR_TYPE_SPATIAL_ENTITY_STORAGE_ERASE_INFO_FB
XR_TYPE_SPACE_ERASE_INFO_FB
XR_TYPE_SPATIAL_ENTITY_STORAGE_LOCATION_FILTER_INFO_FB
XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB
XR_TYPE_SPATIAL_ENTITY_QUERY_FILTER_IDS_FB
XR_TYPE_SPACE_UUID_FILTER_INFO_FB
XR_TYPE_SPATIAL_ENTITY_QUERY_RESULT_FB
XR_TYPE_SPACE_QUERY_RESULT_FB

EventData Struct Changes

Below is a summary of the structs that have been renamed:
Before (Experimental)After (Production)
(New)
XrEventDataSpatialAnchorCreateCompleteFB
XrEventDataSetComponentEnableResultFB
XrEventDataSpaceSetStatusCompleteFB
XrEventSpatialEntityQueryResultsFB
XrEventDataSpaceQueryResultsAvailableFB
XrEventSpatialEntityQueryCompleteFB
XrEventDataSpaceQueryCompleteFB
XrEventSpatialEntityStorageSaveResultFB
XrEventDataSpaceSaveCompleteFB
XrEventSpatialEntityStorageEraseResultFB
XrEventDataSpaceEraseCompleteFB

EventData Struct Property Changes

XrEventDataSpatialAnchorCreateCompleteFB (Experimental)

This struct is new in production and did not exist in the experimental release.

XrEventDataSpatialAnchorCreateCompleteFB (Production)

typedef struct XrEventDataSpatialAnchorCreateCompleteFB {
  XrStructureType type;
  const void* XR_MAY_ALIAS   next;
  XrAsyncRequestIdFB         requestId;
  XrResult                   result;
  XrSpace                    space;
  XrUuidEXT                  uuid;
} XrEventDataSpatialAnchorCreateCompleteFB;

XrEventDataSetComponentEnableResultFB (Experimental)

typedef struct XrEventDataSetComponentEnableResultFB {
  XrStructureType type;
  const void* XR_MAY_ALIAS   next;
  XrAsyncRequestIdFB         requestId;
  XrResult                   result;
  XrComponentTypeFB          componentType;
  XrSpace                    space;</code>
} XrEventDataSetComponentEnableResultFB;

XrEventDataSpaceSetStatusCompleteFB (Production)

typedef struct XrEventDataSpaceSetStatusCompleteFB {
  XrStructureType            type;
  const void* XR_MAY_ALIAS   next;
  XrAsyncRequestIdFB         requestId;
  XrResult                   result;
  XrSpace                    space;
  XrUuidEXT                  uuid;
  XrSpaceComponentTypeFB     componentType;
  XrBool32                   enabled;
} XrEventDataSpaceSetStatusCompleteFB;

XrEventSpatialEntityQueryResultsFB (Experimental)

typedef struct XrEventSpatialEntityQueryResultsFB {
  XrStructureType                type;
  const void* XR_MAY_ALIAS       next;
  XrAsyncRequestIdFB             request;
  uint32_t                       numResults;
  XrSpatialEntityQueryResultFB[] results;
} XrEventSpatialEntityQueryResultsFB;

XrEventDataSpaceQueryResultsAvailableFB (Production)

typedef struct XrEventDataSpaceQueryResultsAvailableFB {
  XrStructureType            type;
  const void* XR_MAY_ALIAS   next;
  XrAsyncRequestIdFB         requestId;
} XrEventDataSpaceQueryResultsAvailableFB;

XrEventSpatialEntityQueryCompleteFB (Experimental)

typedef struct XrEventSpatialEntityQueryCompleteFB {
  XrStructureType            type;
  const void* XR_MAY_ALIAS   next;
  XrResult                   result;
  int32_t                    numSpacesFound;
  XrAsyncRequestIdFB         request;
} XrEventSpatialEntityQueryCompleteFB;

XrEventDataSpaceQueryCompleteFB (Production)

typedef struct XrEventDataSpaceQueryCompleteFB {
  XrStructureType            type;
  const void* XR_MAY_ALIAS   next;
  XrAsyncRequestIdFB         requestId;
  XrResult                   result;
} XrEventDataSpaceQueryCompleteFB;

XrEventSpatialEntityStorageSaveResultFB (Experimental)

typedef struct XrEventSpatialEntityStorageSaveResultFB {
  XrStructureType            type;
  const void* XR_MAY_ALIAS   next;
  XrResult                   result;
  XrSpace                    space;
  XrSpatialEntityUuidFB      uuid;
  XrAsyncRequestIdFB         request;
} XrEventSpatialEntityStorageSaveResultFB;

XrEventDataSpaceSaveCompleteFB (Production)

typedef struct XrEventDataSpaceSaveCompleteFB {
  XrStructureType            type;
  const void* XR_MAY_ALIAS   next;
  XrAsyncRequestIdFB         requestId;
  XrResult                   result;
  XrSpace                    space;
  XrUuidEXT                  uuid;
  XrSpaceStorageLocationFB   location;
} XrEventDataSpaceSaveCompleteFB;

XrEventSpatialEntityStorageEraseResultFB (Experimental)

typedef struct XrEventSpatialEntityStorageEraseResultFB {
  XrStructureType                  type;
  const void* XR_MAY_ALIAS         next;
  XrResult                         result;
  XrSpatialEntityStorageLocationFB location;
  XrSpatialEntityUuidFB            uuid;
  XrAsyncRequestIdFB               request;
} XrEventSpatialEntityStorageEraseResultFB;

XrEventDataSpaceEraseCompleteFB (Production)

typedef struct XrEventDataSpaceEraseCompleteFB {
  XrStructureType            type;
  const void* XR_MAY_ALIAS   next;
  XrAsyncRequestIdFB         requestId;
  XrResult                   result;
  XrSpace                    space;
  XrUuidEXT                  uuid;
  XrSpaceStorageLocationFB   location;
} XrEventDataSpaceEraseCompleteFB;

Renamed EventData Types

Before (Experimental)After (Production)
(N/A, synchronous creation)
XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB
XR_TYPE_EVENT_DATA_SET_COMPONENT_ENABLE_RESULT_FB
XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB
XR_TYPE_EVENT_SPATIAL_ENTITY_STORAGE_SAVE_RESULT_FB
XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB
XR_TYPE_EVENT_SPATIAL_ENTITY_STORAGE_ERASE_RESULT_FB
XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB
XR_TYPE_EVENT_SPATIAL_ENTITY_QUERY_RESULTS_FB
XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB
XR_TYPE_EVENT_SPATIAL_ENTITY_QUERY_COMPLETE_FB
XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB

Renamed Enums

Before (Experimental)After (Production)
XrComponentTypeFB
XrSpaceComponentTypeFB
XrSpatialEntityStoragePersistenceModeFB
XrSpacePersistenceModeFB
XrSpatialEntityStorageLocationFB
XrSpaceStorageLocationFB
XrSpatialEntityQueryPredicateFB
XrSpaceQueryActionFB

Renamed Enum Values

Before (Experimental)After (Production)
XR_COMPONENT_TYPE_LOCATABLE_FB
XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB
XR_COMPONENT_TYPE_STORABLE_FB
XR_SPACE_COMPONENT_TYPE_STORABLE_FB
XR_SPATIAL_ENTITY_STORAGE_PERSISTENCE_MODE_INDEFINITE_HIGH_PRI_FB
XR_SPACE_PERSISTENCE_MODE_INDEFINITE_FB
XR_SPATIAL_ENTITY_STORAGE_LOCATION_LOCAL_FB
XR_SPACE_STORAGE_LOCATION_LOCAL_FB
XR_SPATIAL_ENTITY_QUERY_PREDICATE_LOAD_FB
XR_SPACE_QUERY_ACTION_LOAD_FB
Did you find this page helpful?