The open source OpenXR runtime
at main 263 lines 7.3 kB view raw
1// Copyright 2022-2023, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Builder for SimulaVR devices 6 * @author Moshi Turner <moshiturner@protonmail.com> 7 * @ingroup xrt_iface 8 */ 9 10#include "multi_wrapper/multi.h" 11#include "realsense/rs_interface.h" 12#include "tracking/t_hand_tracking.h" 13#include "tracking/t_tracking.h" 14 15#include "xrt/xrt_config_drivers.h" 16#include "xrt/xrt_device.h" 17#include "xrt/xrt_prober.h" 18 19#include "util/u_builders.h" 20#include "util/u_config_json.h" 21#include "util/u_debug.h" 22#include "util/u_device.h" 23#include "util/u_sink.h" 24#include "util/u_system_helpers.h" 25#include "util/u_file.h" 26 27#include "target_builder_interface.h" 28 29#include "simula/svr_interface.h" 30#include "v4l2/v4l2_interface.h" 31 32#include "xrt/xrt_frameserver.h" 33#include "xrt/xrt_results.h" 34#include "xrt/xrt_tracking.h" 35 36#include <assert.h> 37 38DEBUG_GET_ONCE_OPTION(simula_config_path, "SIMULA_CONFIG_PATH", NULL) 39DEBUG_GET_ONCE_LOG_OPTION(svr_log, "SIMULA_LOG", U_LOGGING_WARN) 40 41 42#define SVR_TRACE(...) U_LOG_IFL_T(debug_get_log_option_svr_log(), __VA_ARGS__) 43#define SVR_DEBUG(...) U_LOG_IFL_D(debug_get_log_option_svr_log(), __VA_ARGS__) 44#define SVR_INFO(...) U_LOG_IFL_I(debug_get_log_option_svr_log(), __VA_ARGS__) 45#define SVR_WARN(...) U_LOG_IFL_W(debug_get_log_option_svr_log(), __VA_ARGS__) 46#define SVR_ERROR(...) U_LOG_IFL_E(debug_get_log_option_svr_log(), __VA_ARGS__) 47 48static const char *driver_list[] = { 49 "simula", 50}; 51 52struct simula_builder 53{ 54 struct u_builder base; 55 56 struct svr_two_displays_distortion display_distortion; 57}; 58 59bool 60process_poly_values(const cJSON *values, struct svr_display_distortion_polynomial_values *out_values) 61{ 62 bool good = true; 63 good = good && u_json_get_float(u_json_get(values, "k1"), &out_values->k1); 64 good = good && u_json_get_float(u_json_get(values, "k3"), &out_values->k3); 65 good = good && u_json_get_float(u_json_get(values, "k5"), &out_values->k5); 66 good = good && u_json_get_float(u_json_get(values, "k7"), &out_values->k7); 67 good = good && u_json_get_float(u_json_get(values, "k9"), &out_values->k9); 68 return good; 69} 70 71static bool 72process_config(const char *config_path, struct svr_two_displays_distortion *out_dist) 73{ 74 char *file_content = u_file_read_content_from_path(config_path, NULL); 75 if (file_content == NULL) { 76 U_LOG_E("The file at \"%s\" was unable to load. Either there wasn't a file there or it was empty.", 77 config_path); 78 return false; 79 } 80 81 cJSON *config_json = cJSON_Parse(file_content); 82 83 84 85 if (config_json == NULL) { 86 const char *error_ptr = cJSON_GetErrorPtr(); 87 U_LOG_E("The JSON file at path \"%s\" was unable to parse", config_path); 88 if (error_ptr != NULL) { 89 U_LOG_E("because of an error before %s", error_ptr); 90 } 91 free((void *)file_content); 92 return false; 93 } 94 free((void *)file_content); 95 96 bool good = true; 97 98 99 const cJSON *dd = u_json_get(config_json, "display_distortion"); 100 101 if (dd == NULL) { 102 good = false; 103 goto end; 104 } 105 106 // struct svr_two_displays_distortion distortion = {0}; 107 108 const char *eye_names[] = {"left_eye", "right_eye"}; 109 for (int eye = 0; eye < 2; eye++) { 110 const cJSON *this_eye = u_json_get(dd, eye_names[eye]); 111 if (this_eye == NULL) { 112 good = false; 113 goto end; 114 } 115 // u_json does its own null checking from here on out 116 117 good = good && u_json_get_float(u_json_get(this_eye, "half_fov"), &out_dist->views[eye].half_fov); 118 good = good && u_json_get_float(u_json_get(this_eye, "display_size_mm_x"), 119 &out_dist->views[eye].display_size_mm.x); 120 good = good && u_json_get_float(u_json_get(this_eye, "display_size_mm_y"), 121 &out_dist->views[eye].display_size_mm.y); 122 123 good = good && process_poly_values(u_json_get(this_eye, "params_red"), &out_dist->views[eye].red); 124 good = good && process_poly_values(u_json_get(this_eye, "params_green"), &out_dist->views[eye].green); 125 good = good && process_poly_values(u_json_get(this_eye, "params_blue"), &out_dist->views[eye].blue); 126 } 127 128end: 129 130 131 132 cJSON_Delete(config_json); 133 134 return good; 135} 136 137 138/* 139 * 140 * Member functions. 141 * 142 */ 143 144static xrt_result_t 145svr_estimate_system(struct xrt_builder *xb, cJSON *config, struct xrt_prober *xp, struct xrt_builder_estimate *estimate) 146{ 147 struct simula_builder *sb = (struct simula_builder *)xb; 148 U_ZERO(estimate); 149 150 const char *config_path = debug_get_option_simula_config_path(); 151 152 if (config_path == NULL) { 153 // No failure occurred - the user just didn't ask for Simula 154 return XRT_SUCCESS; 155 } 156 157 bool config_valid = process_config(config_path, &sb->display_distortion); 158 159 if (!config_valid) { 160 U_LOG_E("Failed to parse SimulaVR config"); 161 return XRT_SUCCESS; 162 } 163 164 struct xrt_prober_device **xpdevs = NULL; 165 size_t xpdev_count = 0; 166 xrt_result_t xret = XRT_SUCCESS; 167 168 // Lock the device list 169 xret = xrt_prober_lock_list(xp, &xpdevs, &xpdev_count); 170 if (xret != XRT_SUCCESS) { 171 return xret; 172 } 173 174 bool movidius = u_builder_find_prober_device(xpdevs, xpdev_count, REALSENSE_MOVIDIUS_VID, 175 REALSENSE_MOVIDIUS_PID, XRT_BUS_TYPE_USB); 176 bool tm2 = 177 u_builder_find_prober_device(xpdevs, xpdev_count, REALSENSE_TM2_VID, REALSENSE_TM2_PID, XRT_BUS_TYPE_USB); 178 179 if (!movidius && !tm2) { 180 U_LOG_E("Simula enabled but couldn't find realsense device!"); 181 return XRT_SUCCESS; 182 } 183 184 // I think that ideally we want `movidius` - in that case I think when we grab the device, it reboots to 185 // `tm2` 186 187 188 estimate->maybe.head = true; 189 estimate->certain.head = true; 190 191 192 return XRT_SUCCESS; 193} 194 195static xrt_result_t 196svr_open_system_impl(struct xrt_builder *xb, 197 cJSON *config, 198 struct xrt_prober *xp, 199 struct xrt_tracking_origin *origin, 200 struct xrt_system_devices *xsysd, 201 struct xrt_frame_context *xfctx, 202 struct u_builder_roles_helper *ubrh) 203{ 204 struct simula_builder *sb = (struct simula_builder *)xb; 205 xrt_result_t result = XRT_SUCCESS; 206 207 struct xrt_device *t265_dev = rs_create_tracked_device_internal_slam(); 208 if (t265_dev == NULL) { 209 SVR_ERROR("Failed to open T265 device!"); 210 result = XRT_ERROR_DEVICE_CREATION_FAILED; 211 goto end; 212 } 213 214 struct xrt_device *svr_dev = svr_hmd_create(&sb->display_distortion); 215 216 struct xrt_pose ident = XRT_POSE_IDENTITY; 217 218 219 struct xrt_device *head_device = multi_create_tracking_override( 220 XRT_TRACKING_OVERRIDE_ATTACHED, svr_dev, t265_dev, XRT_INPUT_GENERIC_TRACKER_POSE, &ident); 221 222 // Add to device list. 223 xsysd->xdevs[xsysd->xdev_count++] = head_device; 224 225 // Assign to role(s). 226 ubrh->head = head_device; 227 228end: 229 return result; 230} 231 232static void 233svr_destroy(struct xrt_builder *xb) 234{ 235 free(xb); 236} 237 238 239/* 240 * 241 * 'Exported' functions. 242 * 243 */ 244 245struct xrt_builder * 246t_builder_simula_create(void) 247{ 248 struct simula_builder *sb = U_TYPED_CALLOC(struct simula_builder); 249 250 // xrt_builder fields. 251 sb->base.base.estimate_system = svr_estimate_system; 252 sb->base.base.open_system = u_builder_open_system_static_roles; 253 sb->base.base.destroy = svr_destroy; 254 sb->base.base.identifier = "simula"; 255 sb->base.base.name = "SimulaVR headset"; 256 sb->base.base.driver_identifiers = driver_list; 257 sb->base.base.driver_identifier_count = ARRAY_SIZE(driver_list); 258 259 // u_builder fields. 260 sb->base.open_system_static_roles = svr_open_system_impl; 261 262 return &sb->base.base; 263}