The open source OpenXR runtime
at prediction-2 257 lines 7.1 kB view raw
1// Copyright 2020-2023, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Simulated HMD device. 6 * @author Jakob Bornecrantz <jakob@collabora.com> 7 * @ingroup drv_simulated 8 */ 9 10#include "xrt/xrt_device.h" 11 12#include "os/os_time.h" 13 14#include "math/m_api.h" 15#include "math/m_mathinclude.h" 16 17#include "util/u_debug.h" 18#include "util/u_device.h" 19#include "util/u_distortion_mesh.h" 20#include "util/u_logging.h" 21#include "util/u_misc.h" 22#include "util/u_pretty_print.h" 23#include "util/u_time.h" 24#include "util/u_var.h" 25 26#include "simulated_interface.h" 27 28#include <stdio.h> 29 30 31/* 32 * 33 * Structs and defines. 34 * 35 */ 36 37/*! 38 * A example HMD device. 39 * 40 * @implements xrt_device 41 */ 42struct simulated_hmd 43{ 44 struct xrt_device base; 45 46 struct xrt_pose pose; 47 struct xrt_pose center; 48 49 uint64_t created_ns; 50 float diameter_m; 51 52 enum u_logging_level log_level; 53 enum simulated_movement movement; 54}; 55 56 57/* 58 * 59 * Functions 60 * 61 */ 62 63static inline struct simulated_hmd * 64simulated_hmd(struct xrt_device *xdev) 65{ 66 return (struct simulated_hmd *)xdev; 67} 68 69DEBUG_GET_ONCE_LOG_OPTION(simulated_log, "SIMULATED_LOG", U_LOGGING_WARN) 70DEBUG_GET_ONCE_NUM_OPTION(view_count, "SIMULATED_VIEW_COUNT", 2) 71 72#define HMD_TRACE(hmd, ...) U_LOG_XDEV_IFL_T(&hmd->base, hmd->log_level, __VA_ARGS__) 73#define HMD_DEBUG(hmd, ...) U_LOG_XDEV_IFL_D(&hmd->base, hmd->log_level, __VA_ARGS__) 74#define HMD_INFO(hmd, ...) U_LOG_XDEV_IFL_I(&hmd->base, hmd->log_level, __VA_ARGS__) 75#define HMD_ERROR(hmd, ...) U_LOG_XDEV_IFL_E(&hmd->base, hmd->log_level, __VA_ARGS__) 76 77static void 78simulated_hmd_destroy(struct xrt_device *xdev) 79{ 80 struct simulated_hmd *dh = simulated_hmd(xdev); 81 82 // Remove the variable tracking. 83 u_var_remove_root(dh); 84 85 u_device_free(&dh->base); 86} 87 88static xrt_result_t 89simulated_hmd_get_tracked_pose(struct xrt_device *xdev, 90 enum xrt_input_name name, 91 int64_t at_timestamp_ns, 92 struct xrt_space_relation *out_relation) 93{ 94 struct simulated_hmd *hmd = simulated_hmd(xdev); 95 96 if (name != XRT_INPUT_GENERIC_HEAD_POSE) { 97 U_LOG_XDEV_UNSUPPORTED_INPUT(&hmd->base, hmd->log_level, name); 98 return XRT_ERROR_INPUT_UNSUPPORTED; 99 } 100 101 const double time_s = time_ns_to_s(at_timestamp_ns - hmd->created_ns); 102 const double d = hmd->diameter_m; 103 const double d2 = d * 2; 104 const double t = 2.0; 105 const double t2 = t * 2; 106 const double t3 = t * 3; 107 const double t4 = t * 4; 108 const struct xrt_vec3 up = {0, 1, 0}; 109 110 switch (hmd->movement) { 111 default: 112 case SIMULATED_MOVEMENT_WOBBLE: { 113 struct xrt_pose tmp = XRT_POSE_IDENTITY; 114 115 // Wobble time. 116 tmp.position.x = sin((time_s / t2) * M_PI) * d2 - d; 117 tmp.position.y = sin((time_s / t) * M_PI) * d; 118 tmp.orientation.x = sin((time_s / t3) * M_PI) / 64.0f; 119 tmp.orientation.y = sin((time_s / t4) * M_PI) / 16.0f; 120 tmp.orientation.z = sin((time_s / t4) * M_PI) / 64.0f; 121 math_quat_normalize(&tmp.orientation); 122 123 // Transform with center to set it. 124 math_pose_transform(&hmd->center, &tmp, &hmd->pose); 125 } break; 126 case SIMULATED_MOVEMENT_ROTATE: { 127 struct xrt_pose tmp = XRT_POSE_IDENTITY; 128 129 // Rotate around the up vector. 130 math_quat_from_angle_vector(time_s / 4, &up, &hmd->pose.orientation); 131 132 // Transform with center to set it. 133 math_pose_transform(&hmd->center, &tmp, &hmd->pose); 134 } break; 135 case SIMULATED_MOVEMENT_STATIONARY: 136 // Reset pose. 137 hmd->pose = hmd->center; 138 break; 139 } 140 141 out_relation->pose = hmd->pose; 142 out_relation->relation_flags = (enum xrt_space_relation_flags)(XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | 143 XRT_SPACE_RELATION_POSITION_VALID_BIT | 144 XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT); 145 146 return XRT_SUCCESS; 147} 148 149static xrt_result_t 150simulated_ref_space_usage(struct xrt_device *xdev, 151 enum xrt_reference_space_type type, 152 enum xrt_input_name name, 153 bool used) 154{ 155 struct simulated_hmd *hmd = simulated_hmd(xdev); 156 157 struct u_pp_sink_stack_only sink; 158 u_pp_delegate_t dg = u_pp_sink_stack_only_init(&sink); 159 160 u_pp(dg, "Ref space "); 161 u_pp_xrt_reference_space_type(dg, type); 162 u_pp(dg, " is %sused", used ? "" : "not "); 163 164 if (name != 0) { 165 u_pp(dg, ", driven by "); 166 u_pp_xrt_input_name(dg, name); 167 u_pp(dg, "."); 168 } else { 169 u_pp(dg, ", not controlled by us."); 170 } 171 172 HMD_INFO(hmd, "%s", sink.buffer); 173 174 return XRT_SUCCESS; 175} 176 177/* 178 * 179 * 'Exported' functions. 180 * 181 */ 182 183enum u_logging_level 184simulated_log_level(void) 185{ 186 return debug_get_log_option_simulated_log(); 187} 188 189struct xrt_device * 190simulated_hmd_create(enum simulated_movement movement, const struct xrt_pose *center) 191{ 192 enum u_device_alloc_flags flags = 193 (enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE); 194 struct simulated_hmd *hmd = U_DEVICE_ALLOCATE(struct simulated_hmd, flags, 1, 0); 195 hmd->base.update_inputs = u_device_noop_update_inputs; 196 hmd->base.get_tracked_pose = simulated_hmd_get_tracked_pose; 197 hmd->base.get_view_poses = u_device_get_view_poses; 198 hmd->base.get_visibility_mask = u_device_get_visibility_mask; 199 hmd->base.ref_space_usage = simulated_ref_space_usage; 200 hmd->base.destroy = simulated_hmd_destroy; 201 hmd->base.name = XRT_DEVICE_GENERIC_HMD; 202 hmd->base.device_type = XRT_DEVICE_TYPE_HMD; 203 hmd->base.supported.ref_space_usage = true; 204 hmd->pose.orientation.w = 1.0f; // All other values set to zero. 205 hmd->center = *center; 206 hmd->created_ns = os_monotonic_get_ns(); 207 hmd->diameter_m = 0.05f; 208 hmd->log_level = simulated_log_level(); 209 hmd->movement = movement; 210 211 hmd->base.hmd->view_count = debug_get_num_option_view_count(); 212 // Print name. 213 snprintf(hmd->base.str, XRT_DEVICE_NAME_LEN, "Simulated HMD"); 214 snprintf(hmd->base.serial, XRT_DEVICE_NAME_LEN, "Simulated HMD"); 215 216 // Setup input. 217 hmd->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; 218 219 // Setup info. 220 bool ret = true; 221 struct u_device_simple_info info; 222 info.display.w_pixels = 1280; 223 info.display.h_pixels = 720; 224 info.display.w_meters = 0.13f; 225 info.display.h_meters = 0.07f; 226 info.lens_horizontal_separation_meters = 0.13f / 2.0f; 227 info.lens_vertical_position_meters = 0.07f / 2.0f; 228 229 if (hmd->base.hmd->view_count == 1) { 230 info.fov[0] = 120.0f * (M_PI / 180.0f); 231 ret = u_device_setup_one_eye(&hmd->base, &info); 232 } else if (hmd->base.hmd->view_count == 2) { 233 info.fov[0] = 85.0f * (M_PI / 180.0f); 234 info.fov[1] = 85.0f * (M_PI / 180.0f); 235 ret = u_device_setup_split_side_by_side(&hmd->base, &info); 236 } else { 237 U_LOG_E("Invalid view count"); 238 ret = false; 239 } 240 if (!ret) { 241 HMD_ERROR(hmd, "Failed to setup basic device info"); 242 simulated_hmd_destroy(&hmd->base); 243 return NULL; 244 } 245 246 // Setup variable tracker. 247 u_var_add_root(hmd, "Simulated HMD", true); 248 u_var_add_pose(hmd, &hmd->pose, "pose"); 249 u_var_add_pose(hmd, &hmd->center, "center"); 250 u_var_add_f32(hmd, &hmd->diameter_m, "diameter_m"); 251 u_var_add_log_level(hmd, &hmd->log_level, "log_level"); 252 253 // Distortion information, fills in xdev->compute_distortion(). 254 u_distortion_mesh_set_none(&hmd->base); 255 256 return &hmd->base; 257}