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