The open source OpenXR runtime
1// Copyright 2022-2023, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief Helpers for @ref xrt_builder implementations.
6 * @author Jakob Bornecrantz <jakob@collabora.com>
7 * @ingroup aux_util
8 */
9
10#include "xrt/xrt_prober.h"
11#include "xrt/xrt_system.h"
12#include "xrt/xrt_tracking.h"
13
14#include "util/u_debug.h"
15#include "util/u_builders.h"
16#include "util/u_system_helpers.h"
17#include "util/u_space_overseer.h"
18
19
20DEBUG_GET_ONCE_FLOAT_OPTION(tracking_origin_offset_x, "XRT_TRACKING_ORIGIN_OFFSET_X", 0.0f)
21DEBUG_GET_ONCE_FLOAT_OPTION(tracking_origin_offset_y, "XRT_TRACKING_ORIGIN_OFFSET_Y", 0.0f)
22DEBUG_GET_ONCE_FLOAT_OPTION(tracking_origin_offset_z, "XRT_TRACKING_ORIGIN_OFFSET_Z", 0.0f)
23
24
25/*
26 *
27 * Helper functions.
28 *
29 */
30
31static void
32apply_offset(struct xrt_vec3 *position, struct xrt_vec3 *offset)
33{
34 position->x += offset->x;
35 position->y += offset->y;
36 position->z += offset->z;
37}
38
39
40/*
41 *
42 * 'Exported' function.
43 *
44 */
45
46struct xrt_prober_device *
47u_builder_find_prober_device(struct xrt_prober_device *const *xpdevs,
48 size_t xpdev_count,
49 uint16_t vendor_id,
50 uint16_t product_id,
51 enum xrt_bus_type bus_type)
52{
53 for (size_t i = 0; i < xpdev_count; i++) {
54 struct xrt_prober_device *xpdev = xpdevs[i];
55 if (xpdev->product_id != product_id || //
56 xpdev->vendor_id != vendor_id || //
57 xpdev->bus != bus_type) {
58 continue;
59 }
60
61 return xpdev;
62 }
63
64 return NULL;
65}
66
67void
68u_builder_search(struct xrt_prober *xp,
69 struct xrt_prober_device *const *xpdevs,
70 size_t xpdev_count,
71 const struct u_builder_search_filter *filters,
72 size_t filter_count,
73 struct u_builder_search_results *results)
74{
75 for (size_t i = 0; i < xpdev_count; i++) {
76 struct xrt_prober_device *xpdev = xpdevs[i];
77 bool match = false;
78
79 for (size_t k = 0; k < filter_count; k++) {
80 struct u_builder_search_filter f = filters[k];
81
82 if (xpdev->product_id != f.product_id || //
83 xpdev->vendor_id != f.vendor_id || //
84 xpdev->bus != f.bus_type) { //
85 continue;
86 }
87
88 match = true;
89 break;
90 }
91
92 if (!match) {
93 continue;
94 }
95
96 results->xpdevs[results->xpdev_count++] = xpdev;
97
98 // Exit if full.
99 if (results->xpdev_count >= ARRAY_SIZE(results->xpdevs)) {
100 return;
101 }
102 }
103}
104
105void
106u_builder_setup_tracking_origins(struct xrt_device *head,
107 struct xrt_device *left,
108 struct xrt_device *right,
109 struct xrt_device *gamepad,
110 struct xrt_vec3 *global_tracking_origin_offset)
111{
112 struct xrt_tracking_origin *head_origin = head ? head->tracking_origin : NULL;
113 struct xrt_tracking_origin *left_origin = left ? left->tracking_origin : NULL;
114 struct xrt_tracking_origin *right_origin = right ? right->tracking_origin : NULL;
115 struct xrt_tracking_origin *gamepad_origin = gamepad ? gamepad->tracking_origin : NULL;
116
117 if (left_origin != NULL && left_origin->type == XRT_TRACKING_TYPE_NONE) {
118 left_origin->initial_offset.position.x = -0.2f;
119 left_origin->initial_offset.position.y = 1.3f;
120 left_origin->initial_offset.position.z = -0.5f;
121 }
122
123 if (right_origin != NULL && right_origin->type == XRT_TRACKING_TYPE_NONE) {
124 right_origin->initial_offset.position.x = 0.2f;
125 right_origin->initial_offset.position.y = 1.3f;
126 right_origin->initial_offset.position.z = -0.5f;
127 }
128
129 if (gamepad_origin != NULL && gamepad_origin->type == XRT_TRACKING_TYPE_NONE) {
130 gamepad_origin->initial_offset.position.x = 0.0f;
131 gamepad_origin->initial_offset.position.y = 1.3f;
132 gamepad_origin->initial_offset.position.z = -0.5f;
133 }
134
135 // Head comes last, because left and right may share tracking origin.
136 if (head_origin != NULL && head_origin->type == XRT_TRACKING_TYPE_NONE) {
137 // "nominal height" 1.6m
138 head_origin->initial_offset.position.x = 0.0f;
139 head_origin->initial_offset.position.y = 1.6f;
140 head_origin->initial_offset.position.z = 0.0f;
141 }
142
143 if (head_origin) {
144 apply_offset(&head_origin->initial_offset.position, global_tracking_origin_offset);
145 }
146 if (left_origin && left_origin != head_origin) {
147 apply_offset(&left->tracking_origin->initial_offset.position, global_tracking_origin_offset);
148 }
149 if (right_origin && right_origin != head_origin && right_origin != left_origin) {
150 apply_offset(&right->tracking_origin->initial_offset.position, global_tracking_origin_offset);
151 }
152 if (gamepad_origin && gamepad_origin != head_origin && gamepad_origin != right_origin &&
153 gamepad_origin != left_origin) {
154 apply_offset(&gamepad->tracking_origin->initial_offset.position, global_tracking_origin_offset);
155 }
156}
157
158void
159u_builder_create_space_overseer_legacy(struct xrt_session_event_sink *broadcast,
160 struct xrt_device *head,
161 struct xrt_device *left,
162 struct xrt_device *right,
163 struct xrt_device *gamepad,
164 struct xrt_device **xdevs,
165 uint32_t xdev_count,
166 bool root_is_unbounded,
167 bool per_app_local_spaces,
168 struct xrt_space_overseer **out_xso)
169{
170 /*
171 * Tracking origins.
172 */
173
174 struct xrt_vec3 global_tracking_origin_offset = {
175 debug_get_float_option_tracking_origin_offset_x(),
176 debug_get_float_option_tracking_origin_offset_y(),
177 debug_get_float_option_tracking_origin_offset_z(),
178 };
179
180 u_builder_setup_tracking_origins( //
181 head, //
182 left, //
183 right, //
184 gamepad, //
185 &global_tracking_origin_offset); //
186
187
188 /*
189 * Space overseer.
190 */
191
192 struct u_space_overseer *uso = u_space_overseer_create(broadcast);
193
194 struct xrt_pose T_stage_local = XRT_POSE_IDENTITY;
195 T_stage_local.position.y = 1.6;
196
197 u_space_overseer_legacy_setup( //
198 uso, // uso
199 xdevs, // xdevs
200 xdev_count, // xdev_count
201 head, // head
202 &T_stage_local, // local_offset
203 root_is_unbounded, // root_is_unbounded
204 per_app_local_spaces // per_app_local_spaces
205 );
206
207 *out_xso = (struct xrt_space_overseer *)uso;
208}
209
210xrt_result_t
211u_builder_roles_helper_open_system(struct xrt_builder *xb,
212 cJSON *config,
213 struct xrt_prober *xp,
214 struct xrt_session_event_sink *broadcast,
215 struct xrt_system_devices **out_xsysd,
216 struct xrt_space_overseer **out_xso,
217 u_builder_open_system_fn fn)
218{
219 struct u_builder_roles_helper ubrh = XRT_STRUCT_INIT;
220 xrt_result_t xret;
221
222 // Use the static system devices helper, no dynamic roles.
223 struct u_system_devices_static *usysds = u_system_devices_static_allocate();
224 struct xrt_tracking_origin *origin = &usysds->base.origin;
225 struct xrt_system_devices *xsysd = &usysds->base.base;
226 struct xrt_frame_context *xfctx = &usysds->base.xfctx;
227
228 xret = fn( //
229 xb, // xb
230 config, // config
231 xp, // xp
232 origin, // origin
233 xsysd, // xsysd
234 xfctx, // xfctx
235 &ubrh); // ubrh
236 if (xret != XRT_SUCCESS) {
237 xrt_system_devices_destroy(&xsysd);
238 return xret;
239 }
240
241 /*
242 * Assign to role(s).
243 */
244
245 xsysd->static_roles.head = ubrh.head;
246#define U_SET_HT_ROLE(SRC) \
247 xsysd->static_roles.hand_tracking.SRC.left = ubrh.hand_tracking.SRC.left; \
248 xsysd->static_roles.hand_tracking.SRC.right = ubrh.hand_tracking.SRC.right;
249 U_SET_HT_ROLE(unobstructed)
250 U_SET_HT_ROLE(conforming)
251#undef U_SET_HT_ROLE
252
253 u_system_devices_static_finalize( //
254 usysds, // usysds
255 ubrh.left, // left
256 ubrh.right, // right
257 ubrh.gamepad); // gamepad
258
259
260 /*
261 * Create the space overseer.
262 */
263
264 *out_xsysd = xsysd;
265 u_builder_create_space_overseer_legacy( //
266 broadcast, // broadcast
267 ubrh.head, // head
268 ubrh.left, // left
269 ubrh.right, // right
270 ubrh.gamepad, // gamepad
271 xsysd->xdevs, // xdevs
272 xsysd->xdev_count, // xdev_count
273 false, // root_is_unbounded
274 true, // per_app_local_spaces
275 out_xso); // out_xso
276
277 return XRT_SUCCESS;
278}
279
280xrt_result_t
281u_builder_open_system_static_roles(struct xrt_builder *xb,
282 cJSON *config,
283 struct xrt_prober *xp,
284 struct xrt_session_event_sink *broadcast,
285 struct xrt_system_devices **out_xsysd,
286 struct xrt_space_overseer **out_xso)
287{
288 struct u_builder *ub = (struct u_builder *)xb;
289
290 return u_builder_roles_helper_open_system( //
291 xb, //
292 config, //
293 xp, //
294 broadcast, //
295 out_xsysd, //
296 out_xso, //
297 ub->open_system_static_roles); //
298}