The open source OpenXR runtime
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

drivers: Add a sample driver intended for use as a template.

+351
+7
src/xrt/drivers/CMakeLists.txt
··· 296 296 list(APPEND ENABLED_DRIVERS euroc) 297 297 endif() 298 298 299 + # We always build the sample driver, to make sure it stays valid, but it never gets linked 300 + add_library(drv_sample STATIC 301 + sample/sample_hmd.c 302 + sample/sample_interface.h 303 + sample/sample_prober.c) 304 + target_link_libraries(drv_sample PRIVATE xrt-interfaces aux_util) 305 + 299 306 if(ENABLED_HEADSET_DRIVERS) 300 307 set(ENABLED_DRIVERS ${ENABLED_HEADSET_DRIVERS} ${ENABLED_DRIVERS}) 301 308 list(SORT ENABLED_DRIVERS)
+192
src/xrt/drivers/sample/sample_hmd.c
··· 1 + // Copyright 2020-2021, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Sample HMD device, use as a starting point to make your own device driver. 6 + * 7 + * 8 + * Based largely on dummy_hmd.c 9 + * 10 + * @author Jakob Bornecrantz <jakob@collabora.com> 11 + * @author Ryan Pavlik <ryan.pavlik@collabora.com> 12 + * @ingroup drv_sample 13 + */ 14 + 15 + #include "xrt/xrt_device.h" 16 + 17 + #include "os/os_time.h" 18 + 19 + #include "math/m_api.h" 20 + #include "math/m_mathinclude.h" 21 + 22 + #include "util/u_var.h" 23 + #include "util/u_misc.h" 24 + #include "util/u_time.h" 25 + #include "util/u_debug.h" 26 + #include "util/u_device.h" 27 + #include "util/u_logging.h" 28 + #include "util/u_distortion_mesh.h" 29 + 30 + #include <stdio.h> 31 + 32 + 33 + /* 34 + * 35 + * Structs and defines. 36 + * 37 + */ 38 + 39 + /*! 40 + * A sample HMD device. 41 + * 42 + * @implements xrt_device 43 + */ 44 + struct sample_hmd 45 + { 46 + struct xrt_device base; 47 + 48 + struct xrt_pose pose; 49 + 50 + enum u_logging_level log_level; 51 + }; 52 + 53 + 54 + /// Casting helper function 55 + static inline struct sample_hmd * 56 + sample_hmd(struct xrt_device *xdev) 57 + { 58 + return (struct sample_hmd *)xdev; 59 + } 60 + 61 + DEBUG_GET_ONCE_LOG_OPTION(sample_log, "SAMPLE_LOG", U_LOGGING_WARN) 62 + 63 + #define SH_TRACE(p, ...) U_LOG_XDEV_IFL_T(&sh->base, sh->log_level, __VA_ARGS__) 64 + #define SH_DEBUG(p, ...) U_LOG_XDEV_IFL_D(&sh->base, sh->log_level, __VA_ARGS__) 65 + #define SH_ERROR(p, ...) U_LOG_XDEV_IFL_E(&sh->base, sh->log_level, __VA_ARGS__) 66 + 67 + static void 68 + sample_hmd_destroy(struct xrt_device *xdev) 69 + { 70 + struct sample_hmd *sh = sample_hmd(xdev); 71 + 72 + // Remove the variable tracking. 73 + u_var_remove_root(sh); 74 + 75 + u_device_free(&sh->base); 76 + } 77 + 78 + static void 79 + sample_hmd_update_inputs(struct xrt_device *xdev) 80 + { 81 + // Empty, you should put code to update the attached input fields (if any) 82 + } 83 + 84 + static void 85 + sample_hmd_get_tracked_pose(struct xrt_device *xdev, 86 + enum xrt_input_name name, 87 + uint64_t at_timestamp_ns, 88 + struct xrt_space_relation *out_relation) 89 + { 90 + struct sample_hmd *sh = sample_hmd(xdev); 91 + 92 + if (name != XRT_INPUT_GENERIC_HEAD_POSE) { 93 + SH_ERROR(sh, "unknown input name"); 94 + return; 95 + } 96 + 97 + // Estimate pose at timestamp at_timestamp_ns! 98 + math_quat_normalize(&sh->pose.orientation); 99 + out_relation->pose = sh->pose; 100 + out_relation->relation_flags = (enum xrt_space_relation_flags)(XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | 101 + XRT_SPACE_RELATION_POSITION_VALID_BIT | 102 + XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT); 103 + } 104 + 105 + static void 106 + sample_hmd_get_view_pose(struct xrt_device *xdev, 107 + const struct xrt_vec3 *eye_relation, 108 + uint32_t view_index, 109 + struct xrt_pose *out_pose) 110 + { 111 + (void)xdev; 112 + // This helper function assumes a symmetric IPD 113 + u_device_get_view_pose(eye_relation, view_index, out_pose); 114 + } 115 + 116 + struct xrt_device * 117 + sample_hmd_create(void) 118 + { 119 + // This indicates you won't be using Monado's built-in tracking algorithms. 120 + enum u_device_alloc_flags flags = 121 + (enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE); 122 + 123 + struct sample_hmd *sh = U_DEVICE_ALLOCATE(struct sample_hmd, flags, 1, 0); 124 + sh->base.update_inputs = sample_hmd_update_inputs; 125 + sh->base.get_tracked_pose = sample_hmd_get_tracked_pose; 126 + sh->base.get_view_pose = sample_hmd_get_view_pose; 127 + sh->base.destroy = sample_hmd_destroy; 128 + sh->base.name = XRT_DEVICE_GENERIC_HMD; 129 + sh->base.device_type = XRT_DEVICE_TYPE_HMD; 130 + sh->pose.orientation.w = 1.0f; // All other values set to zero by U_DEVICE_ALLOCATE (which calls U_CALLOC) 131 + sh->log_level = debug_get_log_option_sample_log(); 132 + 133 + // Print name. 134 + snprintf(sh->base.str, XRT_DEVICE_NAME_LEN, "Sample HMD"); 135 + snprintf(sh->base.serial, XRT_DEVICE_NAME_LEN, "Sample HMD S/N"); 136 + 137 + // Setup input. 138 + sh->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; 139 + 140 + // Set up display details 141 + // refresh rate 142 + sh->base.hmd->screens[0].nominal_frame_interval_ns = time_s_to_ns(1.0f / 90.0f); 143 + 144 + const double hFOV = 90 * (M_PI / 180.0); 145 + const double vFOV = 96.73 * (M_PI / 180.0); 146 + // center of projection 147 + const double hCOP = 0.529; 148 + const double vCOP = 0.5; 149 + if ( 150 + /* right eye */ 151 + !math_compute_fovs(1, hCOP, hFOV, 1, vCOP, vFOV, &sh->base.hmd->views[1].fov) || 152 + /* 153 + * left eye - same as right eye, except the horizontal center of projection is moved in the opposite 154 + * direction now 155 + */ 156 + !math_compute_fovs(1, 1.0 - hCOP, hFOV, 1, vCOP, vFOV, &sh->base.hmd->views[0].fov)) { 157 + // If those failed, it means our math was impossible. 158 + SH_ERROR(sh, "Failed to setup basic device info"); 159 + sample_hmd_destroy(&sh->base); 160 + return NULL; 161 + } 162 + const int panel_w = 1080; 163 + const int panel_h = 1200; 164 + 165 + // Single "screen" (always the case) 166 + sh->base.hmd->screens[0].w_pixels = panel_w * 2; 167 + sh->base.hmd->screens[0].h_pixels = panel_h; 168 + 169 + // Left, Right 170 + for (uint8_t eye = 0; eye < 2; ++eye) { 171 + sh->base.hmd->views[eye].display.w_pixels = panel_w; 172 + sh->base.hmd->views[eye].display.h_pixels = panel_h; 173 + sh->base.hmd->views[eye].viewport.y_pixels = 0; 174 + sh->base.hmd->views[eye].viewport.w_pixels = panel_w; 175 + sh->base.hmd->views[eye].viewport.h_pixels = panel_h; 176 + // if rotation is not identity, the dimensions can get more complex. 177 + sh->base.hmd->views[eye].rot = u_device_rotation_ident; 178 + } 179 + // left eye starts at x=0, right eye starts at x=panel_width 180 + sh->base.hmd->views[0].viewport.x_pixels = 0; 181 + sh->base.hmd->views[1].viewport.x_pixels = panel_w; 182 + 183 + // Setup variable tracker: Optional but useful for debugging 184 + u_var_add_root(sh, "Sample HMD", true); 185 + u_var_add_pose(sh, &sh->pose, "pose"); 186 + u_var_add_log_level(sh, &sh->log_level, "log_level"); 187 + 188 + // Distortion information, fills in xdev->compute_distortion(). 189 + u_distortion_mesh_set_none(&sh->base); 190 + 191 + return &sh->base; 192 + }
+81
src/xrt/drivers/sample/sample_interface.h
··· 1 + // Copyright 2020-2021, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Interface to sample driver. 6 + * @author Jakob Bornecrantz <jakob@collabora.com> 7 + * @author Ryan Pavlik <ryan.pavlik@collabora.com> 8 + * @ingroup drv_sample 9 + */ 10 + 11 + #pragma once 12 + 13 + #ifdef __cplusplus 14 + extern "C" { 15 + #endif 16 + 17 + /*! 18 + * @defgroup drv_sample Sample driver 19 + * @ingroup drv 20 + * 21 + * @brief Simple do-nothing sample driver, that cannot be detected by USB VID/PID 22 + * and thus exposes an "auto-prober" to explicitly discover the device. 23 + * 24 + * This device has an implementation of @ref xrt_auto_prober to perform hardware 25 + * detection, as well as an implementation of @ref xrt_device for the actual device. 26 + * 27 + * If your device is or has USB HID that **can** be detected based on USB VID/PID, 28 + * you can skip the @ref xrt_auto_prober implementation, and instead implement a 29 + * "found" function that matches the signature expected by xrt_prober_entry::found. 30 + * See for example @ref hdk_found. 31 + * 32 + * After you copy and rename these files, you can customize them with the following, 33 + * assuming your new device type is called `struct my_device` or `md` for short, and 34 + * your auto-prober is called `struct my_device_auto_prober` or `mdap` for short: 35 + * 36 + * ```sh 37 + * # First pattern is for renaming device types, 38 + * # second is for renaming device variables, 39 + * # third is for renaming device macros. 40 + * # Fourth and fifth are for renaming auto prober types and variables, respectively. 41 + * # The last two are for renaming the environment variable and function name 42 + * # for the environment variable logging config. 43 + * sed -r -e 's/sample_hmd/my_device/g' \ 44 + * -e 's/\bsh\b/md/g' \ 45 + * -e 's/sample_auto_prober/my_device_auto_prober/g' \ 46 + * -e 's/\bsap\b/mdap/g' \ 47 + * -e 's/\bSH_/MD_/g' \ 48 + * -e 's/sample/my_device/g' \ 49 + * -e 's/SAMPLE/MY_DEVICE/g' \ 50 + * -i *.c *.h 51 + * ``` 52 + */ 53 + 54 + /*! 55 + * Create a auto prober for a sample device. 56 + * 57 + * @ingroup drv_sample 58 + */ 59 + struct xrt_auto_prober * 60 + sample_create_auto_prober(void); 61 + 62 + /*! 63 + * Create a sample hmd. 64 + * 65 + * This is only exposed so that the prober (in one source file) 66 + * can call the construction function (in another.) 67 + * @ingroup drv_sample 68 + */ 69 + struct xrt_device * 70 + sample_hmd_create(void); 71 + 72 + /*! 73 + * @dir drivers/sample 74 + * 75 + * @brief @ref drv_sample files. 76 + */ 77 + 78 + 79 + #ifdef __cplusplus 80 + } 81 + #endif
+71
src/xrt/drivers/sample/sample_prober.c
··· 1 + // Copyright 2020-2021, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Sample prober code. 6 + * @author Jakob Bornecrantz <jakob@collabora.com> 7 + * @ingroup drv_sample 8 + */ 9 + 10 + #include "xrt/xrt_prober.h" 11 + 12 + #include "util/u_misc.h" 13 + #include "util/u_debug.h" 14 + 15 + #include "sample_interface.h" 16 + 17 + 18 + /*! 19 + * @implements xrt_auto_prober 20 + */ 21 + struct sample_auto_prober 22 + { 23 + struct xrt_auto_prober base; 24 + }; 25 + 26 + //! @private @memberof sample_auto_prober 27 + static inline struct sample_auto_prober * 28 + sample_auto_prober(struct xrt_auto_prober *p) 29 + { 30 + return (struct sample_auto_prober *)p; 31 + } 32 + 33 + //! @private @memberof sample_auto_prober 34 + static void 35 + sample_auto_prober_destroy(struct xrt_auto_prober *p) 36 + { 37 + struct sample_auto_prober *sap = sample_auto_prober(p); 38 + 39 + free(sap); 40 + } 41 + 42 + //! @public @memberof sample_auto_prober 43 + static int 44 + sample_auto_prober_autoprobe(struct xrt_auto_prober *xap, 45 + cJSON *attached_data, 46 + bool no_hmds, 47 + struct xrt_prober *xp, 48 + struct xrt_device **out_xdevs) 49 + { 50 + struct sample_auto_prober *sap = sample_auto_prober(xap); 51 + (void)sap; 52 + 53 + // Do not create a sample HMD if we are not looking for HMDs. 54 + if (no_hmds) { 55 + return 0; 56 + } 57 + 58 + out_xdevs[0] = sample_hmd_create(); 59 + return 1; 60 + } 61 + 62 + struct xrt_auto_prober * 63 + sample_create_auto_prober() 64 + { 65 + struct sample_auto_prober *sap = U_TYPED_CALLOC(struct sample_auto_prober); 66 + sap->base.name = "Sample"; 67 + sap->base.destroy = sample_auto_prober_destroy; 68 + sap->base.lelo_dallas_autoprobe = sample_auto_prober_autoprobe; 69 + 70 + return &sap->base; 71 + }