XR_EXT_spatial_container_self_rendering

Name String

XR_EXT_spatial_container_self_rendering

擴充功能類型

執行個體擴充功能

擴充功能註冊編號

814

修訂版本

1

批准狀態

未批准

擴充功能和版本依附元件

XR_EXT_spatial_container

上次修改日期

2026-08-06

IP 狀態

沒有已知的智慧財產權聲明。

著作人

Lachlan Ford,Google
Andreas Loeve Selvik,Meta Platforms
Adam Gousetis,Meta Platforms
Bjorn Swenson,LÖVR
Cass Everitt,Meta Platforms
Christian Kruse,Meta Platforms
Denny Rönngren,Varjo Technologies
Fredia Huya-Kouadio,Godot Engine
Jakob Bornecrantz,NVIDIA
Jared Finder,Google
Jonathan Wright,Meta Platforms
Jian Zhang,ByteDance
Kurtis Eveleigh,Qualcomm
Mauricio Narvaez,Meta Platforms
Nick Klingensmith,Qualcomm
Nikita Lutsenko,Meta Platforms
Praveen Babu J D,ByteDance
Rylie Pavlik,Collabora
Salar Khan,Google
Shuai Liu,ByteDance
Walter Luh,Meta Platforms
Yin Li,Microsoft

總覽

這項擴充功能會定義空間容器的「自我算繪」功能。自行算繪的空間容器像素全由應用程式產生,並使用標準 OpenXR 交換鏈和組合層提交至執行階段。由於空間容器不一定會占用螢幕的所有像素,執行階段會通知應用程式每個空間容器的建議解析度和檢視畫面設定,讓應用程式更有效率地算繪。

這項擴充功能與 XR_EXT_spatial_container 搭配使用,可提供傳統 OpenXR 1.x 核心組合層算繪功能的超集。支援圖形算繪和這項擴充功能的 OpenXR 1.x 執行階段必須將 XrSystemSpatialContainerPropertiesEXT :: supportsImmersive 設為 true,表示支援沉浸式空間容器。

空間容器算繪生命週期

如要對空間容器使用自行算繪功能,應用程式會在呼叫 xrCreateSpatialContainerEXT 時,將 XrSpatialContainerCreateInfoEXT :: graphicsPresentation 設為 XR_SPATIAL_CONTAINER_GRAPHICS_PRESENTATION_SELF_RENDERING_EXT。接著,應用程式可以呼叫 xrBeginSpatialContainerRenderingEXT 和 xrEndSpatialContainerRenderingEXT 函式,管理空間容器是否主動算繪。這些函式會取代 xrBeginSession 和 xrEndSession。這些作業並非以影格為單位,例如 xrBeginFrame 和 xrEndFrame。

應用程式在每個影格都會執行下列步驟:

刪除 XrSpatialContainerEXT 控制代碼,會隱含地將其從有效算繪集中移除。即使應用程式成功呼叫 xrBeginSpatialContainerRenderingEXT,但未與對應的 xrEndSpatialContainerRenderingEXT 呼叫建立關聯,仍可能會刪除空間容器。如果 xrDestroySpatialContainerEXT 成功傳回,執行階段必須在實作初期視需要隱含呼叫 xrEndSpatialContainerRenderingEXT。

當應用程式收到有效算繪集中容器的 XrEventDataSpatialContainerClosedEXT 事件時,應呼叫 xrEndSpatialContainerRenderingEXT,並刪除 XrSpatialContainerEXT 控制代碼。

xrBeginSpatialContainerRenderingEXT 函式會將空間容器新增至每個工作階段的作用中算繪集,讓應用程式能將空間容器的組合層提交至 xrEndFrame。

XrResult xrBeginSpatialContainerRenderingEXT(
    XrSession                                   session,
    const XrSpatialContainerBeginInfoEXT*       beginInfo);

參數說明

應用程式通常會呼叫這個函式,以回應 XrEventDataSpatialContainerVisibleChangedEXT :: visible 設為 true 的可見度變更事件。

如果呼叫 xrCreateSpatialContainerEXT 時,空間容器並非使用 XR_SPATIAL_CONTAINER_GRAPHICS_PRESENTATION_SELF_RENDERING_EXT 建立,則執行階段「必須」傳回 XR_ERROR_SPATIAL_CONTAINER_GRAPHICS_PRESENTATION_MISSING_EXT。

如果空間容器已在有效算繪集中,執行階段必須傳回 XR_ERROR_SPATIAL_CONTAINER_IS_RENDERING_EXT。

如果應用程式無法呼叫 xrWaitFrame (即在 xrBeginFrame 和 xrEndFrame 視窗內),卻呼叫 xrBeginSpatialContainerRenderingEXT,執行階段必須傳回 XR_ERROR_CALL_ORDER_INVALID。

有效用途 (隱含)

執行緒安全

傳回代碼

成功

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

失敗

  • XR_ERROR_CALL_ORDER_INVALID
  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_SPATIAL_CONTAINER_GRAPHICS_PRESENTATION_MISSING_EXT
  • XR_ERROR_SPATIAL_CONTAINER_IS_RENDERING_EXT
  • XR_ERROR_VALIDATION_FAILURE
  • XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED

XrSpatialContainerBeginInfoEXT 結構用於指定空間容器開始算繪的參數。

typedef struct XrSpatialContainerBeginInfoEXT {
    XrStructureType            type;
    const void*                next;
    XrSpatialContainerEXT      spatialContainer;
    XrViewConfigurationType    primaryViewConfigurationType;
} XrSpatialContainerBeginInfoEXT;

成員說明

primaryViewConfigurationType 是應用程式在算繪時要使用的檢視畫面設定。執行階段可能會將檢視畫面設定降級為檢視畫面較少的類型,以便進行最佳化 (例如容器距離很遠且很小,因此無法感知立體聲)。執行階段會從 xrLocateSpatialContainerViewsEXT 的呼叫傳回衰減檢視設定的詳細資料。

有效用途 (隱含)

xrEndSpatialContainerRenderingEXT 函式會從有效算繪集中移除空間容器。

XrResult xrEndSpatialContainerRenderingEXT(
    XrSession                                   session,
    const XrSpatialContainerEndInfoEXT*         endInfo);

參數說明

應用程式通常會呼叫這個函式,以回應 XrEventDataSpatialContainerVisibleChangedEXT :: visible 設為 false 的可見度變更事件。

如果空間容器不在有效算繪集中,執行階段必須傳回 XR_ERROR_SPATIAL_CONTAINER_NOT_RENDERING_EXT。

如果應用程式無法呼叫 xrWaitFrame 時 (即在 xrBeginFrame 和 xrEndFrame 呼叫之間),呼叫 xrEndSpatialContainerRenderingEXT,執行階段必須傳回 XR_ERROR_CALL_ORDER_INVALID。

有效用途 (隱含)

執行緒安全

傳回代碼

成功

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

失敗

  • XR_ERROR_CALL_ORDER_INVALID
  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_SPATIAL_CONTAINER_NOT_RENDERING_EXT
  • XR_ERROR_VALIDATION_FAILURE

XrSpatialContainerEndInfoEXT 結構用於指定結束空間容器算繪的參數。

typedef struct XrSpatialContainerEndInfoEXT {
    XrStructureType          type;
    const void*              next;
    XrSpatialContainerEXT    spatialContainer;
} XrSpatialContainerEndInfoEXT;

成員說明

有效用途 (隱含)

透過 xrLocateSpatialContainerViewsEXT 找出檢視畫面

xrLocateSpatialContainerViewsEXT 函式會找出空間容器組合的檢視畫面。

XrResult xrLocateSpatialContainerViewsEXT(
    XrSession                                   session,
    const XrSpatialContainerViewsLocateInfoEXT* locateInfo,
    uint32_t                                    viewStateCount,
    XrSpatialContainerViewStateEXT*             viewStates,
    uint32_t                                    viewCount,
    XrView*                                     views);

參數說明

這個函式會取代 xrLocateViews,讓應用程式同時查詢多個空間容器的檢視畫面。

所有空間容器的檢視畫面都會在單一 views 陣列中傳回。檢視畫面的排序依據,是 XrSpatialContainerViewsLocateInfoEXT :: viewLocateInfos 陣列中空間容器的索引,然後是該容器的檢視畫面索引。

舉例來說,如果應用程式在 XrSpatialContainerViewsLocateInfoEXT :: viewLocateInfos 中提供三個空間容器:

  • 指數 0:XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO (1 次觀看)
  • 索引 1:XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO (2 項資料檢視)
  • 索引 2:XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO_WITH_FOVEATED_INSET (4 項資料檢視)

接著,執行階段必須在 views 陣列中填入 7 個檢視畫面:

  • views [0] 是容器 0 的檢視畫面。
  • views [1] 是容器 1 的左眼檢視畫面。
  • views [2] 是容器 1 的右眼檢視畫面。
  • views [3] 是容器 2 的左眼檢視畫面。
  • views [4] 是容器 2 的右眼檢視畫面。
  • views [5] 是容器 2 的左眼插圖檢視畫面。
  • views [6] 是容器 2 的右眼插圖檢視畫面。

如果 viewCount 不等於每個空間容器要求的檢視設定類型檢視次數總和,執行階段必須傳回 XR_ERROR_VALIDATION_FAILURE。

執行階段可能會將檢視畫面設定降級為檢視畫面較少的類型,以便進行最佳化 (例如容器距離很遠且很小,因此無法感知立體聲)。如果執行階段降低檢視區塊設定,執行階段必須仍傳回該容器的原始檢視區塊數量,並以降低檢視區塊的重複項目填入額外的檢視區塊。舉例來說,如果 XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO 衰減為 XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO,則索引 0 和索引 1 都會包含單一單聲道檢視畫面。因此,views 陣列傳回的檢視畫面總數,與執行階段是否決定衰減任何檢視畫面設定無關。

執行階段應調整傳回的每個 XrView :: fov,讓平截頭體盡可能縮小,同時仍包含對應空間容器的完整邊界。執行階段可能會傳回非對稱的視野,例如空間容器與使用者視角呈斜角,或部分被其他物件遮擋。執行階段可以自由定位空間容器的目標算繪介面。由於多應用程式算繪的特性,空間容器會與使用者分離,因此執行階段可能會傳回不適合像素算繪的 XrView 值,例如,如果空間容器未顯示在螢幕上,就沒有有效值可設定 XrView :: fov。在這種情況下,執行階段必須將 XrSpatialContainerViewStateEXT :: shouldSubmitLayers 設為 false。

執行階段會在 viewStates 陣列中,傳回每個空間容器的額外算繪狀態資訊。如果 viewStateCount 不等於 XrSpatialContainerViewsLocateInfoEXT :: viewLocateInfoCount,執行階段必須傳回 XR_ERROR_VALIDATION_FAILURE。

執行階段將空間容器的 XrEventDataSpatialContainerClosedEXT 事件排入佇列後,這個函式必須在對應空間容器的 XrSpatialContainerViewStateEXT :: shouldSubmitLayers 中傳回 XR_FALSE,並在 XrSpatialContainerViewStateEXT :: viewStateFlags 中傳回 0。

如果空間容器在現實世界中的位置會主動變更,執行階段應在填寫 views 時考量容器的動作,盡量減少重新投影產生的不自然感。

如果針對目前不在有效算繪集中的一或多個空間容器呼叫 xrLocateSpatialContainerViewsEXT,執行階段必須傳回 XR_ERROR_SPATIAL_CONTAINER_NOT_RENDERING_EXT。

有效用途 (隱含)

傳回代碼

成功

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

失敗

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_SPATIAL_CONTAINER_NOT_RENDERING_EXT
  • XR_ERROR_TIME_INVALID
  • XR_ERROR_VALIDATION_FAILURE
  • XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED

XrSpatialContainerViewsLocateInfoEXT 結構包含用於在一組空間容器中定位檢視畫面的參數。

typedef struct XrSpatialContainerViewsLocateInfoEXT {
    XrStructureType                               type;
    const void*                                   next;
    XrTime                                        displayTime;
    uint32_t                                      viewLocateInfoCount;
    const XrSpatialContainerViewLocateInfoEXT*    viewLocateInfos;
} XrSpatialContainerViewsLocateInfoEXT;

成員說明

  • type 是這個結構的 XrStructureType。
  • next 是 NULL,或指向結構鏈中下一個結構的指標。
  • displayTime 是用於找出檢視畫面的 XrTime。
  • viewLocateInfoCount 是 viewLocateInfos 陣列中的項目數量。
  • viewLocateInfos 是指向 XrSpatialContainerViewLocateInfoEXT 結構陣列的指標。

有效用途 (隱含)

XrSpatialContainerViewLocateInfoEXT 結構包含個別空間容器的參數,用於找出檢視畫面。

typedef struct XrSpatialContainerViewLocateInfoEXT {
    XrStructureType            type;
    const void*                next;
    XrViewConfigurationType    viewConfigurationType;
    XrSpace                    space;
    XrSpatialContainerEXT      spatialContainer;
} XrSpatialContainerViewLocateInfoEXT;

成員說明

應用程式可以在 space 中提供任何有效的 XrSpace,但建議為 XrSpatialContainerViewLocateInfoEXT 結構中指定的對應 XrSpatialContainerEXT 提供空間容器空間。

有效用途 (隱含)

呼叫 xrLocateSpatialContainerViewsEXT 時,系統會填入 XrSpatialContainerViewStateEXT 結構,並提供每個空間容器的算繪適用性資訊。

typedef struct XrSpatialContainerViewStateEXT {
    XrStructureType            type;
    void*                      next;
    XrViewStateFlags           viewStateFlags;
    XrViewConfigurationType    viewConfigurationType;
    XrBool32                   shouldSubmitLayers;
    XrExtent2Di                recommendedImageExtent;
} XrSpatialContainerViewStateEXT;

成員說明

  • type 是這個結構的 XrStructureType。
  • next 是 NULL,或指向結構鏈中下一個結構的指標。
  • viewStateFlags 是 XrViewStateFlags 的位元遮罩。這些旗標的用途與核心 XrViewState 結構中的 viewStateFlags 相同。
  • viewConfigurationType 是 XrViewConfigurationType,表示執行階段用於空間容器的檢視畫面設定類型,執行階段可能會降級為檢視畫面數量低於要求的檢視畫面設定。
  • shouldSubmitLayers 是執行階段傳回的 XrBool32。如果 XR_FALSE,應用程式應避免為這個空間容器提交組合,因為該容器目前不可見,或處於不需要算繪的狀態。
  • recommendedImageExtent 是 XrExtent2Di 結構,代表空間容器的建議解析度。

與核心 OpenXR 檢視位置一樣,應用程式必須檢查 XrSpatialContainerViewStateEXT :: viewStateFlags,確保位置和方向有效且已追蹤,再使用檢視資料進行算繪。

應用程式應檢查 shouldSubmitLayers 和 viewConfigurationType,避免轉譯超過執行階段建議的數量。當 shouldSubmitLayers 為 false 時,應用程式會變更轉譯行為,如下所示:

  • 應用程式不得讀取對應的 XrView :: fov。
  • 應用程式不得讀取 recommendedImageExtent。
  • 應用程式應避免轉譯至交換鏈,並提交對應空間容器的組合層。
  • 應用程式應將 XrSpatialContainerLayerEXT :: retainPreviousSubmission 設為 true。如果應用程式選擇提交圖層,則由執行階段決定要如何處理圖層 (例如,執行階段可能會選擇捨棄圖層)。

recommendedImageExtent 專門用於根據容器位置或使用者檢視畫面更新的圖層。如果更新圖層時,內容取決於空間容器的位置或使用者檢視畫面 (例如一般 3D 內容),應用程式應算繪至這個較小的可視區域,而非預設的建議檢視畫面大小。如果更新圖層時,內容不取決於空間容器的位置或使用者視角 (例如靜態四邊形圖層),應用程式可以安全地忽略這些值。對於檢視畫面依附層,recommendedImageExtent 是執行階段向應用程式提出的建議,旨在盡可能減少鋸齒現象並提升算繪效能。應用程式可以自由選擇是否以完整解析度提交。

recommendedImageExtent 的 XrExtent2Di :: width 和 XrExtent2Di :: height「必須」一律為正整數,且小於或等於空間容器主要檢視畫面設定的 XrViewConfigurationView 的 XrViewConfigurationView :: recommendedImageRectWidth 和 XrViewConfigurationView :: recommendedImageRectHeight。應用程式不應僅因 recommendedImageExtent 變更而重新建立交換鏈,因為這是應用程式的動態提示,指定在提交的任何全解析度合成圖層的 XrSwapchainSubImage 中使用的 XrSwapchainSubImage :: imageRect,且可以變更每個影格。

有效用途 (隱含)

查看參考空間

檢視參考空間與 OpenXR 核心相同,維持不變。與核心一樣,不適用於算繪。

透過 xrEndFrame 提交圖層

如要算繪空間容器,應用程式必須將與各個空間容器相關聯的圖層清單提供給 xrEndFrame。這項作業是透過 XrSpatialContainerLayerFrameEndInfoEXT 結構完成。

typedef struct XrSpatialContainerLayerFrameEndInfoEXT {
    XrStructureType                      type;
    const void*                          next;
    uint32_t                             containerLayerCount;
    const XrSpatialContainerLayerEXT*    containerLayers;
} XrSpatialContainerLayerFrameEndInfoEXT;

成員說明

  • type 是這個結構的 XrStructureType。
  • next 是 NULL,或指向結構鏈中下一個結構的指標。
  • containerLayerCount 是 containerLayers 陣列中的元素數量。
  • containerLayers 是指向 XrSpatialContainerLayerEXT 結構陣列的指標。

containerLayers 陣列包含 XrSpatialContainerLayerEXT,用於有效算繪集中的每個空間容器 (由 xrBeginSpatialContainerRenderingEXT 和 xrEndSpatialContainerRenderingEXT 依工作階段管理的容器)。每個 XrSpatialContainerLayerEXT 都包含與指定空間容器相關聯的 XrCompositionLayerBaseHeader 指標清單。執行階段可以按照任何順序組合容器,不受 containerLayers 的順序影響。舉例來說,執行階段可能會根據容器與使用者的相對深度,合成容器、將空間容器做為背景層,或「固定」空間容器,使其一律位於頂端,無論深度為何。執行階段可能會使用不同策略,在有界或沉浸模式下為空間容器合成圖層。舉例來說,執行階段可能會將每個有界空間容器的合成圖層預先合成單一立體四邊形圖層,並在第二個合成步驟中與所有其他容器合併。

XrFrameEndInfo :: displayTime 和 XrFrameEndInfo :: environmentBlendMode 會套用至 XrSpatialContainerLayerFrameEndInfoEXT 中提供的所有空間容器。

當這個結構透過鏈結至 XrFrameEndInfo 傳遞至 xrEndFrame 時,系統會根據使用中的算繪集,新增下列額外錯誤案例:

  • 如果空間容器由多個 containerLayers 元素參照,執行階段必須傳回 XR_ERROR_SPATIAL_CONTAINER_DUPLICATE_EXT。
  • 如果有效算繪集中的空間容器未由 containerLayers 的元素參照,執行階段必須傳回 XR_ERROR_SPATIAL_CONTAINER_MISSING_EXT。
  • 如果 containerLayers 參照的空間容器不屬於有效算繪集,執行階段必須傳回 XR_ERROR_SPATIAL_CONTAINER_NOT_RENDERING_EXT。

此外,如果有效算繪集中有任何空間容器,且這個結構未鏈結至 XrFrameEndInfo,執行階段必須傳回 XR_ERROR_SPATIAL_CONTAINER_MISSING_EXT。

如果發生上述任何錯誤,執行階段不得為任何空間容器算繪任何內容。

如果有效算繪集中沒有空間容器,應用程式可以呼叫 xrEndFrame,前提是未提交任何組合層。

請注意,個別交換鏈可能會透過有效結構中的圖層提交至多個容器,例如透過單一交換鏈算繪的四邊形圖層提交至多個空間容器。這種情況會與其他算繪作業統一處理:執行階段「必須」在所有這類空間容器中算繪四邊形。

有效用途 (隱含)

XrSpatialContainerLayerEXT 結構會將標準組合圖層分組,並與特定空間容器建立關聯。

typedef struct XrSpatialContainerLayerEXT {
    XrStructureType                               type;
    const void*                                   next;
    XrSpatialContainerEXT                         spatialContainer;
    XrBool32                                      retainPreviousSubmission;
    uint32_t                                      layerCount;
    const XrCompositionLayerBaseHeader* const*    layers;
} XrSpatialContainerLayerEXT;

成員說明

  • type 是這個結構的 XrStructureType。
  • next 是 NULL,或指向結構鏈中下一個結構的指標。
  • spatialContainer 是 XrSpatialContainerEXT,用於識別目標容器。
  • retainPreviousSubmission 是 XrBool32。如果 XR_TRUE,執行階段會保留這個空間容器最後提交的影格。
  • layerCount 是 layers 陣列中的組合層數量。
  • layers 是指向 XrCompositionLayerBaseHeader 指標陣列的指標。

當 retainPreviousSubmission 為 XR_TRUE 時,執行階段必須重複使用組合層和交換鏈圖片內容,就像在最近一次 xrEndFrame 呼叫中,retainPreviousSubmission 為 XR_FALSE 時鎖定的內容一樣。後續對保留圖層使用的交換鏈進行任何修改,不得反映在算繪輸出中。

對於為個別空間容器提交的圖層 (容器內算繪),執行階段必須遵循已指定的圖層組合排序規則。也就是說,容器內的圖層「必須」按照指定的順序繪製,並透過畫家演算法組成。

「清除」空間容器是指移除空間容器中的所有內容,導致目前影格中不會為該容器算繪任何內容。執行階段必須將此視為應用程式為容器內的每個像素提交透明黑色 (所有位元均為 0)。「保留」空間容器是指執行階段繼續顯示該容器最近提交的一組圖層。

對於每個空間容器,應用程式可以指定是否要提交新圖層、保留先前提交的內容,或清除空間容器:

  • 如要提交新圖層,應用程式會提供非零的 layerCount 和有效的 layers 指標。
  • 如要清除空間容器,其項目的 layerCount 必須為 0,且 retainPreviousSubmission 必須為 XR_FALSE。
  • 如要保留上次提交的圖層和交換鏈映像檔 (保留),其項目的 layerCount「必須」為 0,且 retainPreviousSubmission「必須」為 XR_TRUE。

這種明確的個別容器控制項,可確保應用程式的意圖在每個影格中都能清楚傳達。

如果 retainPreviousSubmission 為 XR_TRUE,且 layerCount 不為 0,則執行階段「必須」傳回 XR_ERROR_VALIDATION_FAILURE。

如果 XrSpatialContainerCompositionLayerViewConfigurationEXT 未鏈結至空間容器中的 XrCompositionLayerProjection,執行階段必須傳回 XR_ERROR_VALIDATION_FAILURE。這個結構僅適用於 XrCompositionLayerProjection 圖層。如果與其他圖層類型 (例如四邊形或圓柱圖層) 鏈結,執行階段必須傳回 XR_ERROR_VALIDATION_FAILURE。

有效用途 (隱含)

指定投影層的檢視畫面設定

XrSpatialContainerCompositionLayerViewConfigurationEXT 結構用於指定檢視畫面設定,以便為空間容器算繪投影層。

typedef struct XrSpatialContainerCompositionLayerViewConfigurationEXT {
    XrStructureType            type;
    const void*                next;
    XrViewConfigurationType    viewConfigurationType;
} XrSpatialContainerCompositionLayerViewConfigurationEXT;

成員說明

為空間容器提交 XrCompositionLayerProjection 時,應用程式必須指定用於算繪圖層的檢視畫面設定。這是因為應用程式可以選擇每個影格,是否要使用空間容器的主要檢視設定,或執行階段建議的衰減檢視設定 (如有) 進行轉譯。

鏈結 XrSpatialContainerCompositionLayerViewConfigurationEXT 時,應用程式必須確保 XrCompositionLayerProjection :: viewCount 是鏈結結構中指定 XrViewConfigurationType 的有效檢視畫面數量。鏈結結構中指定的 viewConfigurationType「必須」是容器啟動時指定的 XrSpatialContainerBeginInfoEXT :: primaryViewConfigurationType、執行階段在 XrSpatialContainerViewStateEXT 中傳回的降級檢視設定類型,或透過擴充功能啟用的其他值。

有效用途 (隱含)

像素裁剪行為

應用程式應在提交組合圖層時,鏈結 XrSpatialContainerLayerVolumeClippingEXT,通知執行階段是否在空間容器邊界外算繪像素。

typedef struct XrSpatialContainerLayerVolumeClippingEXT {
    XrStructureType                        type;
    const void*                            next;
    XrSpatialContainerVolumeClippingEXT    volumeClipping;
} XrSpatialContainerLayerVolumeClippingEXT;

成員說明

這個結構可做為提示,指出應用程式是否在空間容器邊界外算繪像素。當空間容器處於沉浸模式時,由於邊界無限,因此這項提示沒有意義。

對於使用自行算繪的有界空間容器,執行階段需要推論 3D 體積邊界和 2D 像素邊界。3D 體積邊界會從 xrGetSpatialContainerBoundsEXT 傳回。2D 像素邊界是 3D 體積邊界在系統各螢幕上的投影。

執行階段必須捨棄 2D 像素邊界以外的交換鏈圖片像素,但不得捨棄 2D 像素邊界內、3D 體積邊界外的像素。立體效果可能會讓內容看起來超出容器的 3D 體積邊界,或出現在容器前方。應用程式可以捨棄有界空間容器 3D 體積邊界外的像素,減少深度悖論,並應根據捨棄方式設定 volumeClipping。深度悖論通常會導致眼睛疲勞和使用者不適。

執行階段可能會使用 volumeClipping 調整特定空間容器的顯示方式。舉例來說,如果設為 XR_SPATIAL_CONTAINER_VOLUME_CLIPPING_STRICT_EXT,執行階段可能會算繪 3D 體積邊界的背面,如果空間容器在容器的 3D 體積邊界後方繪製像素,就會導致深度悖論。

日後擴充功能可能會允許在提交深度資訊時,根據 3D 體積邊界進行裁剪。

有效用途 (隱含)

新指令

新結構

新列舉常數

  • XR_EXT_SPATIAL_CONTAINER_SELF_RENDERING_EXTENSION_NAME
  • XR_EXT_spatial_container_self_rendering_SPEC_VERSION
  • 擴充 XrResult:

    • XR_ERROR_SPATIAL_CONTAINER_DUPLICATE_EXT
    • XR_ERROR_SPATIAL_CONTAINER_GRAPHICS_PRESENTATION_MISSING_EXT
    • XR_ERROR_SPATIAL_CONTAINER_IS_RENDERING_EXT
    • XR_ERROR_SPATIAL_CONTAINER_MISSING_EXT
    • XR_ERROR_SPATIAL_CONTAINER_NOT_RENDERING_EXT
  • 擴充 XrSpatialContainerGraphicsPresentationEXT:

    • XR_SPATIAL_CONTAINER_GRAPHICS_PRESENTATION_SELF_RENDERING_EXT
  • 擴充 XrStructureType:

    • XR_TYPE_SPATIAL_CONTAINER_BEGIN_INFO_EXT
    • XR_TYPE_SPATIAL_CONTAINER_COMPOSITION_LAYER_VIEW_CONFIGURATION_EXT
    • XR_TYPE_SPATIAL_CONTAINER_END_INFO_EXT
    • XR_TYPE_SPATIAL_CONTAINER_LAYER_EXT
    • XR_TYPE_SPATIAL_CONTAINER_LAYER_FRAME_END_INFO_EXT
    • XR_TYPE_SPATIAL_CONTAINER_LAYER_VOLUME_CLIPPING_EXT
    • XR_TYPE_SPATIAL_CONTAINER_VIEWS_LOCATE_INFO_EXT
    • XR_TYPE_SPATIAL_CONTAINER_VIEW_LOCATE_INFO_EXT
    • XR_TYPE_SPATIAL_CONTAINER_VIEW_STATE_EXT

程式碼範例

// Example: Complete lifecycle, view location, and frame submission for spatial containers
PFN_xrBeginSpatialContainerRenderingEXT xrBeginSpatialContainerRenderingEXT; // previously initialized
PFN_xrEndSpatialContainerRenderingEXT xrEndSpatialContainerRenderingEXT; // previously initialized
PFN_xrLocateSpatialContainerViewsEXT xrLocateSpatialContainerViewsEXT; // previously initialized

XrSession session; // previously initialized

// We want to update this container
XrSpatialContainerEXT containerA; // previously initialized with XR_SPATIAL_CONTAINER_GRAPHICS_PRESENTATION_SELF_RENDERING_EXT
XrSpace containerASpace; // previously initialized

// We want to retain this container
XrSpatialContainerEXT containerB; // previously initialized with XR_SPATIAL_CONTAINER_GRAPHICS_PRESENTATION_SELF_RENDERING_EXT
XrSpace containerBSpace; // previously initialized

// 1. Add to active render set when the app is ready to start submitting layers
XrSpatialContainerBeginInfoEXT beginInfoA {
  .type = XR_TYPE_SPATIAL_CONTAINER_BEGIN_INFO_EXT,
  .spatialContainer = containerA,
  .primaryViewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO,
};
CHK_XR(xrBeginSpatialContainerRenderingEXT(session, &beginInfoA));

XrSpatialContainerBeginInfoEXT beginInfoB {
  .type = XR_TYPE_SPATIAL_CONTAINER_BEGIN_INFO_EXT,
  .spatialContainer = containerB,
  .primaryViewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO,
};
CHK_XR(xrBeginSpatialContainerRenderingEXT(session, &beginInfoB));

// ... Frame Loop ...


XrTime displayTime; // returned from xrWaitFrame

const std::vector<XrSpatialContainerEXT> containers = {containerA, containerB};
const std::vector<XrSpace> containerSpaces = {containerASpace, containerBSpace};
uint32_t containerCount = static_cast<uint32_t>(containers.size());

// 2. Setup individual locate info for each container
std::vector<XrSpatialContainerViewLocateInfoEXT> containerLocateInfos(containerCount, {
  .type = XR_TYPE_SPATIAL_CONTAINER_VIEW_LOCATE_INFO_EXT,
});

for (uint32_t i = 0; i < containerCount; ++i) {
    containerLocateInfos[i].viewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
    containerLocateInfos[i].space = containerSpaces[i]; // Recommended to use container's own space
    containerLocateInfos[i].spatialContainer = containers[i];
}

// Setup bulk locate info
XrSpatialContainerViewsLocateInfoEXT locateInfo {
  .type = XR_TYPE_SPATIAL_CONTAINER_VIEWS_LOCATE_INFO_EXT,
  .displayTime = displayTime,
  .viewLocateInfoCount = containerCount,
  .viewLocateInfos = containerLocateInfos.data(),
};

// Prepare states to be populated by the runtime
std::vector<XrSpatialContainerViewStateEXT> viewStates(containerCount, {
  .type = XR_TYPE_SPATIAL_CONTAINER_VIEW_STATE_EXT,
});

// Call the dedicated locate views function
// We know the required view count is 2 per container for STEREO
const uint32_t viewsPerConfig = 2;
uint32_t totalViewCount = containerCount * viewsPerConfig;
std::vector<XrView> views(totalViewCount, {.type = XR_TYPE_VIEW});

CHK_XR(xrLocateSpatialContainerViewsEXT(session, &locateInfo, containerCount, viewStates.data(), totalViewCount, views.data()));

// Process results
for (uint32_t i = 0; i < containerCount; ++i) {
    XrBool32 shouldSubmitLayers = viewStates[i].shouldSubmitLayers;
    XrExtent2Di recommendedImageExtent = viewStates[i].recommendedImageExtent;
    XrViewConfigurationType viewConfigurationType = viewStates[i].viewConfigurationType;
    bool isDecayedToMono = (viewConfigurationType == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO);
    if (shouldSubmitLayers) {
        // App is expected to also verify viewStates[i].viewStateFlags has valid orientation/position bits before rendering
        XrView& leftView = views[i * viewsPerConfig];
        XrView& rightView = views[i * viewsPerConfig + 1];
        // If isDecayedToMono is true, left and right will be identical.
    } else {
        // Skip layer submission but retain previous submission when calling
        // xrEndFrame.
    }
}

// 3. Setup projection layer for container A
XrCompositionLayerProjection projectionLayer = {.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION};
// ... standard projection layer setup (space, viewCount, views, etc.) ...

// Specify which view configuration was used to render this specific layer
XrSpatialContainerCompositionLayerViewConfigurationEXT containerViewConfig {
  .type = XR_TYPE_SPATIAL_CONTAINER_COMPOSITION_LAYER_VIEW_CONFIGURATION_EXT,
  // Even if the runtime decayed to MONO, we indicate what we actually rendered
  .viewConfigurationType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO,
};

// Chain it to the projection layer
projectionLayer.next = &containerViewConfig;
const XrCompositionLayerBaseHeader* layersA[1] = {reinterpret_cast<const XrCompositionLayerBaseHeader*>(&projectionLayer)};

// Note: In a real app, you are required to submit ALL active containers in the render set.

XrSpatialContainerLayerVolumeClippingEXT containerClippingA = {
  .type = XR_TYPE_SPATIAL_CONTAINER_LAYER_VOLUME_CLIPPING_EXT,
  // Set volumeClipping appropriately for the rendering done.
  .volumeClipping = XR_SPATIAL_CONTAINER_VOLUME_CLIPPING_STRICT_EXT,
};

// Setup container A (Update with new pixels)
XrSpatialContainerLayerEXT containerLayerA {
  .type = XR_TYPE_SPATIAL_CONTAINER_LAYER_EXT,
  .next = &containerClippingA,
  .spatialContainer = containerA,
  .retainPreviousSubmission = XR_FALSE,
  .layerCount = 1,
  .layers = layersA,
};

XrSpatialContainerLayerVolumeClippingEXT containerClippingB {
  .type = XR_TYPE_SPATIAL_CONTAINER_LAYER_VOLUME_CLIPPING_EXT,
  // Set volumeClipping appropriately for the rendering done.
  .volumeClipping = XR_SPATIAL_CONTAINER_VOLUME_CLIPPING_STRICT_EXT,
};

// Setup container B (Explicitly retain previous frame)
XrSpatialContainerLayerEXT containerLayerB {
  .type = XR_TYPE_SPATIAL_CONTAINER_LAYER_EXT,
  .next = &containerClippingB,
  .spatialContainer = containerB,
  .retainPreviousSubmission = XR_TRUE,
  .layerCount = 0, // Required to be 0 when retaining
  .layers = nullptr,
};

// Aggregate all container layers
XrSpatialContainerLayerEXT containerLayers[] = { containerLayerA, containerLayerB };

XrSpatialContainerLayerFrameEndInfoEXT spatialEndInfo {
  .type = XR_TYPE_SPATIAL_CONTAINER_LAYER_FRAME_END_INFO_EXT,
  .containerLayerCount = 2, // Must equal the number of active containers
  .containerLayers = containerLayers,
};

XrFrameEndInfo frameEndInfo {
  .type = XR_TYPE_FRAME_END_INFO,
  .next = &spatialEndInfo,
  .displayTime = displayTime,
  .environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND,
  .layerCount = 0, // MANDATORY: Must be 0 for self rendering extension
};

CHK_XR(xrEndFrame(session, &frameEndInfo));

// ... End Frame Loop ...

// 4. Remove from active render set when the container is destroyed or no longer needs rendering
XrSpatialContainerEndInfoEXT endInfoA {
  .type = XR_TYPE_SPATIAL_CONTAINER_END_INFO_EXT,
  .spatialContainer = containerA,
};
CHK_XR(xrEndSpatialContainerRenderingEXT(session, &endInfoA));

XrSpatialContainerEndInfoEXT endInfoB {
  .type = XR_TYPE_SPATIAL_CONTAINER_END_INFO_EXT,
  .spatialContainer = containerB,
};
CHK_XR(xrEndSpatialContainerRenderingEXT(session, &endInfoB));

版本記錄

  • 修訂版本 1,2026-08-06 (Lachlan Ford)

    • 初始擴充功能說明