The open source OpenXR runtime
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}