The open source OpenXR runtime
at main 267 lines 6.0 kB view raw
1// Copyright 2023, Collabora, Ltd. 2// Copyright 2024-2025, NVIDIA CORPORATION. 3// SPDX-License-Identifier: BSL-1.0 4/*! 5 * @file 6 * @brief Helper to implement @ref xrt_system. 7 * @author Jakob Bornecrantz <jakob@collabora.com> 8 * @ingroup aux_util 9 */ 10 11#include "xrt/xrt_compositor.h" 12 13#include "os/os_threading.h" 14 15#include "util/u_system.h" 16#include "util/u_session.h" 17#include "util/u_misc.h" 18#include "util/u_logging.h" 19 20#include <stdio.h> 21 22/* 23 * 24 * Helpers. 25 * 26 */ 27 28static inline struct u_system * 29u_system(struct xrt_system *xsys) 30{ 31 return (struct u_system *)xsys; 32} 33 34 35/* 36 * 37 * Member functions. 38 * 39 */ 40 41static xrt_result_t 42push_event(struct xrt_session_event_sink *xses, const union xrt_session_event *xse) 43{ 44 struct u_system *usys = container_of(xses, struct u_system, broadcast); 45 46 u_system_broadcast_event(usys, xse); 47 48 return XRT_SUCCESS; 49} 50 51static xrt_result_t 52create_session(struct xrt_system *xsys, 53 const struct xrt_session_info *xsi, 54 struct xrt_session **out_xs, 55 struct xrt_compositor_native **out_xcn) 56{ 57 struct u_system *usys = u_system(xsys); 58 xrt_result_t xret = XRT_SUCCESS; 59 60 if (out_xcn != NULL && usys->xsysc == NULL) { 61 U_LOG_E("No system compositor in system, can't create native compositor."); 62 return XRT_ERROR_COMPOSITOR_NOT_SUPPORTED; 63 } 64 65 struct u_session *us = u_session_create(usys); 66 67 // Skip making a native compositor if not asked for. 68 if (out_xcn == NULL) { 69 goto out_session; 70 } 71 72 xret = xrt_syscomp_create_native_compositor( // 73 usys->xsysc, // 74 xsi, // 75 &us->sink, // 76 out_xcn); // 77 if (xret != XRT_SUCCESS) { 78 goto err; 79 } 80 81out_session: 82 *out_xs = &us->base; 83 84 return XRT_SUCCESS; 85 86err: 87 return xret; 88} 89 90static void 91destroy(struct xrt_system *xsys) 92{ 93 struct u_system *usys = u_system(xsys); 94 95 // Use shared fini function. 96 u_system_fini(usys); 97 98 free(usys); 99} 100 101 102/* 103 * 104 * 'Exported' functions. 105 * 106 */ 107 108struct u_system * 109u_system_create(void) 110{ 111 struct u_system *usys = U_TYPED_CALLOC(struct u_system); 112 113 // Use init function, then add the common destroy function. 114 if (!u_system_init(usys, destroy)) { 115 free(usys); 116 return NULL; 117 } 118 119 return usys; 120} 121 122bool 123u_system_init(struct u_system *usys, void (*destroy_fn)(struct xrt_system *)) 124{ 125 // xrt_system fields. 126 usys->base.create_session = create_session; 127 usys->base.destroy = destroy_fn; 128 129 // xrt_session_event_sink fields. 130 usys->broadcast.push_event = push_event; 131 132 usys->sessions.capacity = 2; 133 usys->sessions.pairs = U_TYPED_ARRAY_CALLOC(struct u_system_session_pair, usys->sessions.capacity); 134 if (usys->sessions.pairs == NULL) { 135 U_LOG_E("Failed to allocate session array"); 136 return false; 137 } 138 139 // u_system fields. 140 XRT_MAYBE_UNUSED int ret = os_mutex_init(&usys->sessions.mutex); 141 assert(ret == 0); 142 143 return true; 144} 145 146void 147u_system_fini(struct u_system *usys) 148{ 149 // Just in case, should never happen. 150 if (usys->sessions.count > 0) { 151 U_LOG_E("Number of sessions not zero, things will crash!"); 152 } 153 154 free(usys->sessions.pairs); 155 usys->sessions.count = 0; 156 157 // Mutex needs to be destroyed. 158 os_mutex_destroy(&usys->sessions.mutex); 159} 160 161void 162u_system_add_session(struct u_system *usys, struct xrt_session *xs, struct xrt_session_event_sink *xses) 163{ 164 assert(xs != NULL); 165 assert(xses != NULL); 166 167 os_mutex_lock(&usys->sessions.mutex); 168 169 const uint32_t new_count = usys->sessions.count + 1; 170 171 if (new_count > usys->sessions.capacity) { 172 usys->sessions.capacity *= 2; 173 const size_t size = usys->sessions.capacity * sizeof(*usys->sessions.pairs); 174 struct u_system_session_pair *tmp = realloc(usys->sessions.pairs, size); 175 if (tmp == NULL) { 176 U_LOG_E("Failed to reallocate session array"); 177 goto add_unlock; 178 } 179 usys->sessions.pairs = tmp; 180 } 181 182 usys->sessions.pairs[usys->sessions.count++] = (struct u_system_session_pair){xs, xses}; 183 184add_unlock: 185 os_mutex_unlock(&usys->sessions.mutex); 186} 187 188void 189u_system_remove_session(struct u_system *usys, struct xrt_session *xs, struct xrt_session_event_sink *xses) 190{ 191 os_mutex_lock(&usys->sessions.mutex); 192 193 uint32_t count = usys->sessions.count; 194 uint32_t dst = 0; 195 196 // Find where the session we are removing is. 197 while (dst < count) { 198 if (usys->sessions.pairs[dst].xs == xs) { 199 break; 200 } else { 201 dst++; 202 } 203 } 204 205 // Guards against empty array as well as not finding the session. 206 if (dst >= count) { 207 U_LOG_E("Could not find session to remove!"); 208 goto remove_unlock; 209 } 210 211 // Should not be true with above check. 212 assert(count > 0); 213 214 /* 215 * Do copies if we are not removing the last session, 216 * this also guards against uint32_t::max. 217 */ 218 if (dst < count - 1) { 219 // Copy from every follow down one. 220 for (uint32_t src = dst + 1; src < count; src++, dst++) { 221 usys->sessions.pairs[dst] = usys->sessions.pairs[src]; 222 } 223 } 224 225 count--; 226 // This ensures that the memory returned in add is always zero initialized. 227 U_ZERO(&usys->sessions.pairs[count]); 228 229 usys->sessions.count = count; 230 231remove_unlock: 232 os_mutex_unlock(&usys->sessions.mutex); 233} 234 235void 236u_system_broadcast_event(struct u_system *usys, const union xrt_session_event *xse) 237{ 238 xrt_result_t xret; 239 240 os_mutex_lock(&usys->sessions.mutex); 241 242 for (uint32_t i = 0; i < usys->sessions.count; i++) { 243 xret = xrt_session_event_sink_push(usys->sessions.pairs[i].xses, xse); 244 if (xret != XRT_SUCCESS) { 245 U_LOG_W("Failed to push event to session, dropping."); 246 } 247 } 248 249 os_mutex_unlock(&usys->sessions.mutex); 250} 251 252void 253u_system_set_system_compositor(struct u_system *usys, struct xrt_system_compositor *xsysc) 254{ 255 assert(usys->xsysc == NULL); 256 257 usys->xsysc = xsysc; 258} 259 260void 261u_system_fill_properties(struct u_system *usys, const char *name) 262{ 263 usys->base.properties.vendor_id = 42; 264 // The magical 247 number, is to silence warnings. 265 snprintf(usys->base.properties.name, XRT_MAX_SYSTEM_NAME_SIZE, "Monado: %.*s", 247, name); 266 usys->base.properties.form_factor = XRT_FORM_FACTOR_HMD; 267}