The open source OpenXR runtime
at main 327 lines 8.5 kB view raw
1// Copyright 2020-2024, Collabora, Ltd. 2// Copyright 2025, NVIDIA CORPORATION. 3// SPDX-License-Identifier: BSL-1.0 4/*! 5 * @file 6 * @brief Client side wrapper of instance. 7 * @author Jakob Bornecrantz <jakob@collabora.com> 8 * @author Korcan Hussein <korcan.hussein@collabora.com> 9 * @ingroup ipc_client 10 */ 11 12#include "xrt/xrt_results.h" 13#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 14#define _CRT_SECURE_NO_WARNINGS 15#endif 16 17#include "xrt/xrt_instance.h" 18#include "xrt/xrt_handles.h" 19#include "xrt/xrt_config_os.h" 20#include "xrt/xrt_config_android.h" 21 22#include "util/u_var.h" 23#include "util/u_misc.h" 24#include "util/u_file.h" 25#include "util/u_debug.h" 26#include "util/u_git_tag.h" 27#include "util/u_system_helpers.h" 28 29#include "shared/ipc_protocol.h" 30#include "shared/ipc_shmem.h" 31#include "client/ipc_client.h" 32#include "client/ipc_client_interface.h" 33#include "client/ipc_client_connection.h" 34 35#include "ipc_client_generated.h" 36 37 38#include <stdio.h> 39#if defined(XRT_OS_WINDOWS) 40#include <timeapi.h> 41#else 42#include <sys/socket.h> 43#include <sys/un.h> 44#include <sys/types.h> 45#include <sys/stat.h> 46#include <sys/mman.h> 47#include <errno.h> 48#include <fcntl.h> 49#include <unistd.h> 50#endif 51#include <limits.h> 52 53#ifdef XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER 54#include "android/android_ahardwarebuffer_allocator.h" 55#endif 56 57#ifdef XRT_OS_ANDROID 58#include "xrt/xrt_android.h" 59#include "android/ipc_client_android.h" 60#include "android/android_instance_base.h" 61#endif // XRT_OS_ANDROID 62 63DEBUG_GET_ONCE_LOG_OPTION(ipc_log, "IPC_LOG", U_LOGGING_WARN) 64 65 66/* 67 * 68 * Struct and helpers. 69 * 70 */ 71 72/*! 73 * @implements xrt_instance 74 */ 75struct ipc_client_instance 76{ 77 //! @public Base 78 struct xrt_instance base; 79 80 struct ipc_connection ipc_c; 81 82#ifdef XRT_OS_ANDROID 83 struct android_instance_base android; 84#endif 85}; 86 87static inline struct ipc_client_instance * 88ipc_client_instance(struct xrt_instance *xinst) 89{ 90 return (struct ipc_client_instance *)xinst; 91} 92 93static xrt_result_t 94create_system_compositor(struct ipc_client_instance *ii, 95 struct xrt_device *xdev, 96 struct xrt_system_compositor **out_xsysc) 97{ 98 struct xrt_system_compositor *xsysc = NULL; 99 struct xrt_image_native_allocator *xina = NULL; 100 xrt_result_t xret; 101 102#ifdef XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER 103 // On Android, we allocate images natively on the client side. 104 xina = android_ahardwarebuffer_allocator_create(); 105#endif // XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER 106 107 xret = ipc_client_create_system_compositor(&ii->ipc_c, xina, xdev, &xsysc); 108 IPC_CHK_WITH_GOTO(&ii->ipc_c, xret, "ipc_client_create_system_compositor", err_xina); 109 110 // Paranoia. 111 if (xsysc == NULL) { 112 xret = XRT_ERROR_IPC_FAILURE; 113 IPC_ERROR(&ii->ipc_c, "Variable xsysc NULL!"); 114 goto err_xina; 115 } 116 117 *out_xsysc = xsysc; 118 119 return XRT_SUCCESS; 120 121err_xina: 122 xrt_images_destroy(&xina); 123 return xret; 124} 125 126 127/* 128 * 129 * Member functions. 130 * 131 */ 132 133static xrt_result_t 134ipc_client_instance_is_system_available(struct xrt_instance *xinst, bool *out_available) 135{ 136 struct ipc_client_instance *ii = ipc_client_instance(xinst); 137 xrt_result_t xret = ipc_call_instance_is_system_available(&ii->ipc_c, out_available); 138 IPC_CHK_ALWAYS_RET(&ii->ipc_c, xret, "ipc_call_instance_is_system_available"); 139} 140 141static xrt_result_t 142ipc_client_instance_create_system(struct xrt_instance *xinst, 143 struct xrt_system **out_xsys, 144 struct xrt_system_devices **out_xsysd, 145 struct xrt_space_overseer **out_xso, 146 struct xrt_system_compositor **out_xsysc) 147{ 148 struct ipc_client_instance *ii = ipc_client_instance(xinst); 149 xrt_result_t xret = XRT_SUCCESS; 150 151 assert(out_xsys != NULL); 152 assert(*out_xsys == NULL); 153 assert(out_xsysd != NULL); 154 assert(*out_xsysd == NULL); 155 assert(out_xsysc == NULL || *out_xsysc == NULL); 156 157 struct xrt_system_compositor *xsysc = NULL; 158 159 // Allocate a helper xrt_system_devices struct. 160 struct ipc_client_system_devices *icsd = ipc_client_system_devices_create(&ii->ipc_c); 161 struct xrt_system_devices *xsysd = &icsd->base.base; 162 163 uint32_t count = 0; 164 struct xrt_tracking_origin *xtrack = NULL; 165 struct ipc_shared_memory *ism = ii->ipc_c.ism; 166 167 // Query the server for how many tracking origins it has. 168 count = 0; 169 for (uint32_t i = 0; i < ism->itrack_count; i++) { 170 xtrack = U_TYPED_CALLOC(struct xrt_tracking_origin); 171 172 memcpy(xtrack->name, ism->itracks[i].name, sizeof(xtrack->name)); 173 174 xtrack->type = ism->itracks[i].type; 175 xtrack->initial_offset = ism->itracks[i].offset; 176 icsd->xtracks[count++] = xtrack; 177 178 u_var_add_root(xtrack, "Tracking origin", true); 179 u_var_add_ro_text(xtrack, xtrack->name, "name"); 180 u_var_add_pose(xtrack, &xtrack->initial_offset, "offset"); 181 } 182 icsd->xtrack_count = count; 183 184 // Query the server for how many devices it has. 185 count = 0; 186 for (uint32_t i = 0; i < ism->isdev_count; i++) { 187 struct ipc_shared_device *isdev = &ism->isdevs[i]; 188 xtrack = icsd->xtracks[isdev->tracking_origin_index]; 189 190 if (isdev->device_type == XRT_DEVICE_TYPE_HMD) { 191 xsysd->xdevs[count++] = ipc_client_hmd_create(&ii->ipc_c, xtrack, i); 192 } else { 193 xsysd->xdevs[count++] = ipc_client_device_create(&ii->ipc_c, xtrack, i); 194 } 195 } 196 xsysd->xdev_count = count; 197 198#define SET_ROLE(ROLE) \ 199 do { \ 200 int32_t index = ii->ipc_c.ism->roles.ROLE; \ 201 xsysd->static_roles.ROLE = index >= 0 ? xsysd->xdevs[index] : NULL; \ 202 } while (false) 203 204 SET_ROLE(head); 205 SET_ROLE(eyes); 206 SET_ROLE(face); 207 SET_ROLE(body); 208 SET_ROLE(hand_tracking.unobstructed.left); 209 SET_ROLE(hand_tracking.unobstructed.right); 210 SET_ROLE(hand_tracking.conforming.left); 211 SET_ROLE(hand_tracking.conforming.right); 212 213#undef SET_ROLE 214 215 // Done here now. 216 if (out_xsysc == NULL) { 217 goto out; 218 } 219 220 if (xsysd->static_roles.head == NULL) { 221 IPC_ERROR((&ii->ipc_c), "No head device found but asking for system compositor!"); 222 xret = XRT_ERROR_IPC_FAILURE; 223 goto err_destroy; 224 } 225 226 xret = create_system_compositor(ii, xsysd->static_roles.head, &xsysc); 227 if (xret != XRT_SUCCESS) { 228 goto err_destroy; 229 } 230 231out: 232 *out_xsys = ipc_client_system_create(&ii->ipc_c, xsysc); 233 *out_xsysd = xsysd; 234 *out_xso = ipc_client_space_overseer_create(&ii->ipc_c); 235 236 if (xsysc != NULL) { 237 assert(out_xsysc != NULL); 238 *out_xsysc = xsysc; 239 } 240 241 return XRT_SUCCESS; 242 243err_destroy: 244 xrt_system_devices_destroy(&xsysd); 245 246 return xret; 247} 248 249static xrt_result_t 250ipc_client_instance_get_prober(struct xrt_instance *xinst, struct xrt_prober **out_xp) 251{ 252 *out_xp = NULL; 253 254 return XRT_ERROR_PROBER_NOT_SUPPORTED; 255} 256 257static void 258ipc_client_instance_destroy(struct xrt_instance *xinst) 259{ 260 struct ipc_client_instance *ii = ipc_client_instance(xinst); 261 262 // service considers us to be connected until fd is closed 263 ipc_client_connection_fini(&ii->ipc_c); 264 265#ifdef XRT_OS_ANDROID 266 android_instance_base_cleanup(&(ii->android), xinst); 267 ipc_client_android_destroy(&(ii->ipc_c.ica)); 268#endif // XRT_OS_ANDROID 269 270#ifdef XRT_OS_WINDOWS 271 timeEndPeriod(1); 272#endif 273 274 ipc_shmem_destroy(&ii->ipc_c.ism_handle, (void **)&ii->ipc_c.ism, sizeof(struct ipc_shared_memory)); 275 276 free(ii); 277} 278 279 280/* 281 * 282 * Exported function(s). 283 * 284 */ 285 286/*! 287 * Constructor for xrt_instance IPC client proxy. 288 * 289 * @public @memberof ipc_instance 290 */ 291xrt_result_t 292ipc_instance_create(const struct xrt_instance_info *i_info, struct xrt_instance **out_xinst) 293{ 294 struct ipc_client_instance *ii = U_TYPED_CALLOC(struct ipc_client_instance); 295 ii->base.is_system_available = ipc_client_instance_is_system_available; 296 ii->base.create_system = ipc_client_instance_create_system; 297 ii->base.get_prober = ipc_client_instance_get_prober; 298 ii->base.destroy = ipc_client_instance_destroy; 299 300#ifdef XRT_OS_WINDOWS 301 timeBeginPeriod(1); 302#endif 303 304 xrt_result_t xret; 305#ifdef XRT_OS_ANDROID 306 xret = android_instance_base_init(&ii->android, &ii->base, i_info); 307 if (xret != XRT_SUCCESS) { 308 free(ii); 309 return xret; 310 } 311#endif 312 313 xret = ipc_client_connection_init(&ii->ipc_c, debug_get_log_option_ipc_log(), i_info); 314 if (xret != XRT_SUCCESS) { 315#ifdef XRT_OS_ANDROID 316 android_instance_base_cleanup(&(ii->android), &(ii->base)); 317#endif 318 free(ii); 319 return xret; 320 } 321 322 ii->base.startup_timestamp = ii->ipc_c.ism->startup_timestamp; 323 324 *out_xinst = &ii->base; 325 326 return XRT_SUCCESS; 327}