···1-// Copyright 2020-2021, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
···12 * @ingroup drv_sample
13 */
140015#include "xrt/xrt_device.h"
16017#include "math/m_api.h"
18#include "math/m_mathinclude.h" // IWYU pragma: keep
1920-#include "util/u_var.h"
21-#include "util/u_time.h"
22#include "util/u_debug.h"
23#include "util/u_device.h"
024#include "util/u_logging.h"
25-#include "util/u_distortion_mesh.h"
0026#include "util/u_visibility_mask.h"
27#include "xrt/xrt_results.h"
28···47 struct xrt_pose pose;
4849 enum u_logging_level log_level;
00050};
5152···5960DEBUG_GET_ONCE_LOG_OPTION(sample_log, "SAMPLE_LOG", U_LOGGING_WARN)
6162-#define SH_TRACE(p, ...) U_LOG_XDEV_IFL_T(&sh->base, sh->log_level, __VA_ARGS__)
63-#define SH_DEBUG(p, ...) U_LOG_XDEV_IFL_D(&sh->base, sh->log_level, __VA_ARGS__)
64-#define SH_ERROR(p, ...) U_LOG_XDEV_IFL_E(&sh->base, sh->log_level, __VA_ARGS__)
06566static void
67sample_hmd_destroy(struct xrt_device *xdev)
68{
69- struct sample_hmd *sh = sample_hmd(xdev);
7071 // Remove the variable tracking.
72- u_var_remove_root(sh);
7374- u_device_free(&sh->base);
00075}
7677static void
78sample_hmd_update_inputs(struct xrt_device *xdev)
79{
80 /*
81- * Empty for the sampler driver, if you need to you should
82 * put code to update the attached inputs fields. If not you can use
83 * the u_device_noop_update_inputs helper to make it a no-op.
84 */
···90 uint64_t at_timestamp_ns,
91 struct xrt_space_relation *out_relation)
92{
93- struct sample_hmd *sh = sample_hmd(xdev);
9495 if (name != XRT_INPUT_GENERIC_HEAD_POSE) {
96- SH_ERROR(sh, "unknown input name");
97 return;
98 }
99100- // Estimate pose at timestamp at_timestamp_ns!
101- math_quat_normalize(&sh->pose.orientation);
102- out_relation->pose = sh->pose;
103- out_relation->relation_flags = (enum xrt_space_relation_flags)(XRT_SPACE_RELATION_ORIENTATION_VALID_BIT |
104- XRT_SPACE_RELATION_POSITION_VALID_BIT |
105- XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT);
0000000000106}
107108static void
···128 out_poses); //
129}
130131-bool
132-sample_hmd_compute_distortion(
133- struct xrt_device *xdev, uint32_t view, float u, float v, struct xrt_uv_triplet *out_result)
134-{
135- return u_compute_distortion_none(u, u, out_result);
136-}
137-138xrt_result_t
139sample_hmd_get_visibility_mask(struct xrt_device *xdev,
140 enum xrt_visibility_mask_type type,
···153 enum u_device_alloc_flags flags =
154 (enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE);
155156- struct sample_hmd *sh = U_DEVICE_ALLOCATE(struct sample_hmd, flags, 1, 0);
157158 // This list should be ordered, most preferred first.
159 size_t idx = 0;
160- sh->base.hmd->blend_modes[idx++] = XRT_BLEND_MODE_OPAQUE;
161- sh->base.hmd->blend_mode_count = idx;
000000000162163- sh->base.update_inputs = sample_hmd_update_inputs;
164- sh->base.get_tracked_pose = sample_hmd_get_tracked_pose;
165- sh->base.get_view_poses = sample_hmd_get_view_poses;
166- sh->base.compute_distortion = sample_hmd_compute_distortion;
167- sh->base.get_visibility_mask = sample_hmd_get_visibility_mask;
168- sh->base.destroy = sample_hmd_destroy;
169170- sh->pose = (struct xrt_pose)XRT_POSE_IDENTITY;
171- sh->log_level = debug_get_log_option_sample_log();
172173 // Print name.
174- snprintf(sh->base.str, XRT_DEVICE_NAME_LEN, "Sample HMD");
175- snprintf(sh->base.serial, XRT_DEVICE_NAME_LEN, "Sample HMD S/N");
00176177 // Setup input.
178- sh->base.name = XRT_DEVICE_GENERIC_HMD;
179- sh->base.device_type = XRT_DEVICE_TYPE_HMD;
180- sh->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE;
181- sh->base.orientation_tracking_supported = true;
182- sh->base.position_tracking_supported = false;
183184 // Set up display details
185 // refresh rate
186- sh->base.hmd->screens[0].nominal_frame_interval_ns = time_s_to_ns(1.0f / 90.0f);
187188 const double hFOV = 90 * (M_PI / 180.0);
189 const double vFOV = 96.73 * (M_PI / 180.0);
···192 const double vCOP = 0.5;
193 if (
194 /* right eye */
195- !math_compute_fovs(1, hCOP, hFOV, 1, vCOP, vFOV, &sh->base.hmd->distortion.fov[1]) ||
196 /*
197 * left eye - same as right eye, except the horizontal center of projection is moved in the opposite
198 * direction now
199 */
200- !math_compute_fovs(1, 1.0 - hCOP, hFOV, 1, vCOP, vFOV, &sh->base.hmd->distortion.fov[0])) {
201 // If those failed, it means our math was impossible.
202- SH_ERROR(sh, "Failed to setup basic device info");
203- sample_hmd_destroy(&sh->base);
204 return NULL;
205 }
206 const int panel_w = 1080;
207 const int panel_h = 1200;
208209 // Single "screen" (always the case)
210- sh->base.hmd->screens[0].w_pixels = panel_w * 2;
211- sh->base.hmd->screens[0].h_pixels = panel_h;
212213 // Left, Right
214 for (uint8_t eye = 0; eye < 2; ++eye) {
215- sh->base.hmd->views[eye].display.w_pixels = panel_w;
216- sh->base.hmd->views[eye].display.h_pixels = panel_h;
217- sh->base.hmd->views[eye].viewport.y_pixels = 0;
218- sh->base.hmd->views[eye].viewport.w_pixels = panel_w;
219- sh->base.hmd->views[eye].viewport.h_pixels = panel_h;
220 // if rotation is not identity, the dimensions can get more complex.
221- sh->base.hmd->views[eye].rot = u_device_rotation_ident;
222 }
223 // left eye starts at x=0, right eye starts at x=panel_width
224- sh->base.hmd->views[0].viewport.x_pixels = 0;
225- sh->base.hmd->views[1].viewport.x_pixels = panel_w;
226227 // Distortion information, fills in xdev->compute_distortion().
228- u_distortion_mesh_set_none(&sh->base);
0000000229230 // Setup variable tracker: Optional but useful for debugging
231- u_var_add_root(sh, "Sample HMD", true);
232- u_var_add_pose(sh, &sh->pose, "pose");
233- u_var_add_log_level(sh, &sh->log_level, "log_level");
234235236- return &sh->base;
237}
···1+// Copyright 2020-2024, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
···12 * @ingroup drv_sample
13 */
1415+#include "os/os_time.h"
16+#include "xrt/xrt_defines.h"
17#include "xrt/xrt_device.h"
1819+#include "math/m_relation_history.h"
20#include "math/m_api.h"
21#include "math/m_mathinclude.h" // IWYU pragma: keep
220023#include "util/u_debug.h"
24#include "util/u_device.h"
25+#include "util/u_distortion_mesh.h"
26#include "util/u_logging.h"
27+#include "util/u_misc.h"
28+#include "util/u_time.h"
29+#include "util/u_var.h"
30#include "util/u_visibility_mask.h"
31#include "xrt/xrt_results.h"
32···51 struct xrt_pose pose;
5253 enum u_logging_level log_level;
54+55+ // has built-in mutex so thread safe
56+ struct m_relation_history *relation_hist;
57};
5859···6667DEBUG_GET_ONCE_LOG_OPTION(sample_log, "SAMPLE_LOG", U_LOGGING_WARN)
6869+#define HMD_TRACE(hmd, ...) U_LOG_XDEV_IFL_T(&hmd->base, hmd->log_level, __VA_ARGS__)
70+#define HMD_DEBUG(hmd, ...) U_LOG_XDEV_IFL_D(&hmd->base, hmd->log_level, __VA_ARGS__)
71+#define HMD_INFO(hmd, ...) U_LOG_XDEV_IFL_I(&hmd->base, hmd->log_level, __VA_ARGS__)
72+#define HMD_ERROR(hmd, ...) U_LOG_XDEV_IFL_E(&hmd->base, hmd->log_level, __VA_ARGS__)
7374static void
75sample_hmd_destroy(struct xrt_device *xdev)
76{
77+ struct sample_hmd *hmd = sample_hmd(xdev);
7879 // Remove the variable tracking.
80+ u_var_remove_root(hmd);
8182+83+ m_relation_history_destroy(&hmd->relation_hist);
84+85+ u_device_free(&hmd->base);
86}
8788static void
89sample_hmd_update_inputs(struct xrt_device *xdev)
90{
91 /*
92+ * Empty for the sample driver, if you need to you should
93 * put code to update the attached inputs fields. If not you can use
94 * the u_device_noop_update_inputs helper to make it a no-op.
95 */
···101 uint64_t at_timestamp_ns,
102 struct xrt_space_relation *out_relation)
103{
104+ struct sample_hmd *hmd = sample_hmd(xdev);
105106 if (name != XRT_INPUT_GENERIC_HEAD_POSE) {
107+ HMD_ERROR(hmd, "unknown input name");
108 return;
109 }
110111+ struct xrt_space_relation relation = XRT_SPACE_RELATION_ZERO;
112+113+ enum m_relation_history_result history_result =
114+ m_relation_history_get(hmd->relation_hist, at_timestamp_ns, &relation);
115+ if (history_result == M_RELATION_HISTORY_RESULT_INVALID) {
116+ // If you get in here, it means you did not push any poses into the relation history.
117+ // You may want to handle this differently.
118+ HMD_ERROR(hmd, "Internal error: no poses pushed?");
119+ }
120+121+ if ((relation.relation_flags & XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) != 0) {
122+ // If we provide an orientation, make sure that it is normalized.
123+ math_quat_normalize(&relation.pose.orientation);
124+ }
125+126+ *out_relation = relation;
127}
128129static void
···149 out_poses); //
150}
1510000000152xrt_result_t
153sample_hmd_get_visibility_mask(struct xrt_device *xdev,
154 enum xrt_visibility_mask_type type,
···167 enum u_device_alloc_flags flags =
168 (enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE);
169170+ struct sample_hmd *hmd = U_DEVICE_ALLOCATE(struct sample_hmd, flags, 1, 0);
171172 // This list should be ordered, most preferred first.
173 size_t idx = 0;
174+ hmd->base.hmd->blend_modes[idx++] = XRT_BLEND_MODE_OPAQUE;
175+ hmd->base.hmd->blend_mode_count = idx;
176+177+ hmd->base.update_inputs = sample_hmd_update_inputs;
178+ hmd->base.get_tracked_pose = sample_hmd_get_tracked_pose;
179+ hmd->base.get_view_poses = sample_hmd_get_view_poses;
180+ hmd->base.get_visibility_mask = sample_hmd_get_visibility_mask;
181+ hmd->base.destroy = sample_hmd_destroy;
182+183+ // Distortion information, fills in xdev->compute_distortion().
184+ u_distortion_mesh_set_none(&hmd->base);
185186+ // populate this with something more complex if required
187+ // hmd->base.compute_distortion = sample_hmd_compute_distortion;
0000188189+ hmd->pose = (struct xrt_pose)XRT_POSE_IDENTITY;
190+ hmd->log_level = debug_get_log_option_sample_log();
191192 // Print name.
193+ snprintf(hmd->base.str, XRT_DEVICE_NAME_LEN, "Sample HMD");
194+ snprintf(hmd->base.serial, XRT_DEVICE_NAME_LEN, "Sample HMD S/N");
195+196+ m_relation_history_create(&hmd->relation_hist);
197198 // Setup input.
199+ hmd->base.name = XRT_DEVICE_GENERIC_HMD;
200+ hmd->base.device_type = XRT_DEVICE_TYPE_HMD;
201+ hmd->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE;
202+ hmd->base.orientation_tracking_supported = true;
203+ hmd->base.position_tracking_supported = true;
204205 // Set up display details
206 // refresh rate
207+ hmd->base.hmd->screens[0].nominal_frame_interval_ns = time_s_to_ns(1.0f / 90.0f);
208209 const double hFOV = 90 * (M_PI / 180.0);
210 const double vFOV = 96.73 * (M_PI / 180.0);
···213 const double vCOP = 0.5;
214 if (
215 /* right eye */
216+ !math_compute_fovs(1, hCOP, hFOV, 1, vCOP, vFOV, &hmd->base.hmd->distortion.fov[1]) ||
217 /*
218 * left eye - same as right eye, except the horizontal center of projection is moved in the opposite
219 * direction now
220 */
221+ !math_compute_fovs(1, 1.0 - hCOP, hFOV, 1, vCOP, vFOV, &hmd->base.hmd->distortion.fov[0])) {
222 // If those failed, it means our math was impossible.
223+ HMD_ERROR(hmd, "Failed to setup basic device info");
224+ sample_hmd_destroy(&hmd->base);
225 return NULL;
226 }
227 const int panel_w = 1080;
228 const int panel_h = 1200;
229230 // Single "screen" (always the case)
231+ hmd->base.hmd->screens[0].w_pixels = panel_w * 2;
232+ hmd->base.hmd->screens[0].h_pixels = panel_h;
233234 // Left, Right
235 for (uint8_t eye = 0; eye < 2; ++eye) {
236+ hmd->base.hmd->views[eye].display.w_pixels = panel_w;
237+ hmd->base.hmd->views[eye].display.h_pixels = panel_h;
238+ hmd->base.hmd->views[eye].viewport.y_pixels = 0;
239+ hmd->base.hmd->views[eye].viewport.w_pixels = panel_w;
240+ hmd->base.hmd->views[eye].viewport.h_pixels = panel_h;
241 // if rotation is not identity, the dimensions can get more complex.
242+ hmd->base.hmd->views[eye].rot = u_device_rotation_ident;
243 }
244 // left eye starts at x=0, right eye starts at x=panel_width
245+ hmd->base.hmd->views[0].viewport.x_pixels = 0;
246+ hmd->base.hmd->views[1].viewport.x_pixels = panel_w;
247248 // Distortion information, fills in xdev->compute_distortion().
249+ u_distortion_mesh_set_none(&hmd->base);
250+251+ // Just put an initial identity value in the tracker
252+ struct xrt_space_relation identity = XRT_SPACE_RELATION_ZERO;
253+ identity.relation_flags = (enum xrt_space_relation_flags)(XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT |
254+ XRT_SPACE_RELATION_ORIENTATION_VALID_BIT);
255+ uint64_t now = os_monotonic_get_ns();
256+ m_relation_history_push(hmd->relation_hist, &identity, now);
257258 // Setup variable tracker: Optional but useful for debugging
259+ u_var_add_root(hmd, "Sample HMD", true);
260+ u_var_add_log_level(hmd, &hmd->log_level, "log_level");
0261262263+ return &hmd->base;
264}
+11-7
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 Rylie Pavlik <rylie.pavlik@collabora.com>
8 * @ingroup drv_sample
···15#endif
1617/*!
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
00022 * and thus exposes an "auto-prober" to explicitly discover the device.
23 *
24 * See @ref writing-driver for additional information.
···30 * you can skip the @ref xrt_auto_prober implementation, and instead implement a
31 * "found" function that matches the signature expected by xrt_prober_entry::found.
32 * See for example @ref hdk_found.
033 */
3435/*!
36- * Create a auto prober for a sample device.
37 *
38 * @ingroup drv_sample
39 */
···41sample_create_auto_prober(void);
4243/*!
44- * Create a sample hmd.
45 *
46 * This is only exposed so that the prober (in one source file)
47- * can call the construction function (in another.)
48 * @ingroup drv_sample
49 */
50struct xrt_device *
···1+// Copyright 2020-2024, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5+ * @brief Interface to Sample HMD driver.
6 * @author Jakob Bornecrantz <jakob@collabora.com>
7 * @author Rylie Pavlik <rylie.pavlik@collabora.com>
8 * @ingroup drv_sample
···15#endif
1617/*!
18+ * @defgroup drv_sample Sample HMD driver
19 * @ingroup drv
20 *
21+ * @brief Driver for a Sample HMD.
22+ *
23+ * Does no actual work.
24+ * Assumed to not be detectable by USB VID/PID,
25 * and thus exposes an "auto-prober" to explicitly discover the device.
26 *
27 * See @ref writing-driver for additional information.
···33 * you can skip the @ref xrt_auto_prober implementation, and instead implement a
34 * "found" function that matches the signature expected by xrt_prober_entry::found.
35 * See for example @ref hdk_found.
36+ * Alternately, you might create a builder or an instance implementation directly.
37 */
3839/*!
40+ * Create a auto prober for a Sample HMD.
41 *
42 * @ingroup drv_sample
43 */
···45sample_create_auto_prober(void);
4647/*!
48+ * Create a Sample HMD.
49 *
50 * This is only exposed so that the prober (in one source file)
51+ * can call the construction function (in another)
52 * @ingroup drv_sample
53 */
54struct xrt_device *