Monado OpenXR Runtime
Swapchain Allocation and IPC

The control flow in Monado for allocating the images/buffers used for a given XrSwapchain can vary widely based on a number of factors.

Simple in-process

In the minimal case, which is not common for widespread deployment but which is useful for debugging, there is only a single process, with the entire runtime loaded into the "client" application. Despite the absence of IPC in this scenario, the same basic flow and interaction applies: images are conveyed using system ("native") handles.

%% Copyright 2024, Collabora, Ltd. and the Monado contributors %% SPDX-License-Identifier: BSL-1.0 %% Simple in-process case sequenceDiagram participant app participant cc as client compositor participant native_comp as xrt_compositor_native app->>+cc: xrCreateSwapchain cc->>+native_comp: xrt_comp_create_swapchain native_comp->>-cc: xrt_swapchain impl Note over cc: Keep reference to inner xrt_swapchain in
the object we create Note over cc: Import handles from
inner xrt_swapchain into client API cc->>-app: return swapchain

The control flow makes its way to the main compositor, which, in default implementations, uses Vulkan to allocate exportable images.

Simple out-of-process

The usual model on desktop is that the images for a given XrSwapchain are allocated in the service, as shown below.

%% Copyright 2024, Collabora, Ltd. and the Monado contributors %% SPDX-License-Identifier: BSL-1.0 %% Out of process, typical behavior (server-side allocation) sequenceDiagram box Client Process participant app participant cc as client compositor participant client_native as client process
native compositor
(IPC Stub) end box Server Process participant server_ipc_handler as Server IPC handler participant server_comp as Server xrt_compositor_native end app->>+cc: xrCreateSwapchain cc->>+client_native: xrt_comp_create_swapchain client_native->>+server_ipc_handler: xrt_comp_create_swapchain
(IPC call) server_ipc_handler->>+server_comp: xrt_comp_create_swapchain server_comp->>-server_ipc_handler: xrt_swapchain impl server_ipc_handler->>-client_native: swapchain ID and
image handles
(over IPC) client_native->>-cc: return ipc_swapchain
as inner xrt_swapchain Note over cc: Keep reference to inner xrt_swapchain in
the object we create Note over cc: Import handles from
inner xrt_swapchain into client API cc->>-app: return swapchain

However, there are two additional paths possible.

Client-side Allocation with XINA (Out-of-process)

In some builds, a "XINA" (like the warrior princess) is used: xrt_image_native_allocator. This allocates the "native" (system handle) images within the client process, in a central location. Currently only Android builds using AHardwareBuffer use this model, but ideally we would probably move toward this model for all systems. The main advantage is that the swapchain images are allocated in the application process and thus counted against application quotas, rather than the service/runtime quotas, avoiding security, privacy, and denial-of-service risks.

%% Copyright 2024, Collabora, Ltd. and the Monado contributors %% SPDX-License-Identifier: BSL-1.0 %% Out of process, with a "xina" in the IPC client (currently only android with AHB) sequenceDiagram box Client Process participant app participant cc as client compositor participant client_native as client process
native compositor
(IPC Stub) participant xina as xrt_image_native_allocator end box Server Process participant server_ipc_handler as Server IPC handler participant server_comp as Server xrt_compositor_native end app->>+cc: xrCreateSwapchain cc->>+client_native: xrt_comp_create_swapchain client_native->>+xina: create native images xina->>-client_native: collection of
native image handles client_native->>+server_ipc_handler: swapchain_import
(IPC call, passing handles) server_ipc_handler->>+server_comp: xrt_comp_import_swapchain server_comp->>-server_ipc_handler: xrt_swapchain impl server_ipc_handler->>-client_native: swapchain ID
(over IPC) client_native->>-cc: return ipc_swapchain
(handles allocated in client process)
as inner xrt_swapchain Note over cc: Keep reference to inner xrt_swapchain in
the object we create Note over cc: Import handles from
inner xrt_swapchain into client API cc->>-app: return swapchain

Generally a XINA used in this way is intended for client-process allocation. However, there is an implementation (disabled by default) of a "loopback XINA" in the IPC client, which implements the XINA API using the IPC interface. So using a XINA in that case would not result in client-process image allocation.

Allocation for D3D client apps (Out-of-process)

Direct3D cannot reliably and portably import images allocated in Vulkan. So, if an application uses Direct3D, the D3D client compositor does the allocation, on the client side, as shown below. The example shown is out-of-process.

%% Copyright 2024, Collabora, Ltd. and the Monado contributors %% SPDX-License-Identifier: BSL-1.0 %% Out of process, D3D client API sequenceDiagram box Client Process participant app participant cc as D3D client compositor participant client_native as client process
native compositor
(IPC Stub) end box Server Process participant server_ipc_handler as Server IPC handler participant server_comp as Server xrt_compositor_native end app->>+cc: xrCreateSwapchain Note over cc: create images
(because d3d cannot reliably import from Vulkan) Note over cc: export images to handles Note over cc: import handles to images for app cc->>+client_native: xrt_comp_import_swapchain(xrt_image_native[])
(import handles into xrt_swapchain_native) client_native->>+server_ipc_handler: swapchain_import
(IPC call, copies handles) server_ipc_handler->>+server_comp: xrt_comp_import_swapchain(xrt_image_native[]) server_comp->>-server_ipc_handler: xrt_swapchain impl server_ipc_handler->>-client_native: swapchain ID (over IPC) client_native->>-cc: return ipc_swapchain
as inner xrt_swapchain Note over cc: Keep reference to inner xrt_swapchain in
the object we create cc->>-app: return swapchain

Note that this pattern is used even when running in-process with D3D, the result is a hybrid of this diagram and the first (in-process) diagram, dropping the client process native compositor and server IPC handler from the diagram.