The open source OpenXR runtime
1// Copyright 2020-2023, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief HMD remote driver.
6 * @author Jakob Bornecrantz <jakob@collabora.com>
7 * @ingroup drv_remote
8 */
9
10#include "r_internal.h"
11
12#include "os/os_time.h"
13
14#include "util/u_var.h"
15#include "util/u_misc.h"
16#include "util/u_debug.h"
17#include "util/u_device.h"
18#include "util/u_distortion_mesh.h"
19
20#include "math/m_api.h"
21#include "math/m_mathinclude.h"
22
23#include <stdio.h>
24
25
26/*
27 *
28 * Functions
29 *
30 */
31
32static inline struct r_hmd *
33r_hmd(struct xrt_device *xdev)
34{
35 return (struct r_hmd *)xdev;
36}
37
38static inline void
39copy_head_center_to_relation(struct r_hmd *rh, struct xrt_space_relation *out_relation)
40{
41 out_relation->pose = rh->r->latest.head.center;
42 out_relation->relation_flags = (enum xrt_space_relation_flags)(
43 XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_POSITION_VALID_BIT |
44 XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | XRT_SPACE_RELATION_POSITION_TRACKED_BIT);
45}
46
47static void
48r_hmd_destroy(struct xrt_device *xdev)
49{
50 struct r_hmd *rh = r_hmd(xdev);
51
52 // Remove the variable tracking.
53 u_var_remove_root(rh);
54
55 // Free this device with the helper.
56 u_device_free(&rh->base);
57}
58
59static xrt_result_t
60r_hmd_get_tracked_pose(struct xrt_device *xdev,
61 enum xrt_input_name name,
62 int64_t at_timestamp_ns,
63 struct xrt_space_relation *out_relation)
64{
65 struct r_hmd *rh = r_hmd(xdev);
66
67 switch (name) {
68 case XRT_INPUT_GENERIC_HEAD_POSE: copy_head_center_to_relation(rh, out_relation); break;
69 default:
70 U_LOG_XDEV_UNSUPPORTED_INPUT(&rh->base, u_log_get_global_level(), name);
71 return XRT_ERROR_INPUT_UNSUPPORTED;
72 }
73
74 return XRT_SUCCESS;
75}
76
77static xrt_result_t
78r_hmd_get_view_poses(struct xrt_device *xdev,
79 const struct xrt_vec3 *default_eye_relation,
80 int64_t at_timestamp_ns,
81 enum xrt_view_type view_type,
82 uint32_t view_count,
83 struct xrt_space_relation *out_head_relation,
84 struct xrt_fov *out_fovs,
85 struct xrt_pose *out_poses)
86{
87 struct r_hmd *rh = r_hmd(xdev);
88
89 if (!rh->r->latest.head.per_view_data_valid) {
90 return u_device_get_view_poses( //
91 xdev, //
92 default_eye_relation, //
93 at_timestamp_ns, //
94 view_type, //
95 view_count, //
96 out_head_relation, //
97 out_fovs, //
98 out_poses); //
99 }
100
101 assert(view_count <= ARRAY_SIZE(rh->r->latest.head.views));
102
103 copy_head_center_to_relation(rh, out_head_relation);
104
105 for (uint32_t i = 0; i < view_count; i++) {
106 out_poses[i] = rh->r->latest.head.views[i].pose;
107 out_fovs[i] = rh->r->latest.head.views[i].fov;
108 }
109
110 return XRT_SUCCESS;
111}
112
113/*!
114 * @public @memberof r_hmd
115 */
116struct xrt_device *
117r_hmd_create(struct r_hub *r)
118{
119 // Allocate.
120 const enum u_device_alloc_flags flags = U_DEVICE_ALLOC_HMD;
121 const uint32_t input_count = 1;
122 const uint32_t output_count = 0;
123 struct r_hmd *rh = U_DEVICE_ALLOCATE( //
124 struct r_hmd, flags, input_count, output_count);
125
126 // Setup the basics.
127 u_device_populate_function_pointers(&rh->base, r_hmd_get_tracked_pose, r_hmd_destroy);
128 rh->base.get_view_poses = r_hmd_get_view_poses;
129 rh->base.tracking_origin = &r->origin;
130 rh->base.supported.orientation_tracking = true;
131 rh->base.supported.position_tracking = true;
132 rh->base.supported.hand_tracking = false;
133 rh->base.name = XRT_DEVICE_GENERIC_HMD;
134 rh->base.device_type = XRT_DEVICE_TYPE_HMD;
135 rh->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE;
136 rh->base.inputs[0].active = true;
137 rh->base.hmd->view_count = r->view_count;
138 rh->r = r;
139
140 // Print name.
141 snprintf(rh->base.str, sizeof(rh->base.str), "Remote HMD");
142 snprintf(rh->base.serial, sizeof(rh->base.serial), "Remote HMD");
143
144 // Setup info.
145 bool ret = true;
146 struct u_device_simple_info info;
147 info.display.w_pixels = 1920;
148 info.display.h_pixels = 1080;
149 info.display.w_meters = 0.13f;
150 info.display.h_meters = 0.07f;
151 info.lens_horizontal_separation_meters = 0.13f / 2.0f;
152 info.lens_vertical_position_meters = 0.07f / 2.0f;
153
154 if (rh->r->view_count == 1) {
155 info.fov[0] = 120.0f * (M_PI / 180.0f);
156 ret = u_device_setup_one_eye(&rh->base, &info);
157 } else if (rh->r->view_count == 2) {
158 info.fov[0] = 85.0f * (M_PI / 180.0f);
159 info.fov[1] = 85.0f * (M_PI / 180.0f);
160 ret = u_device_setup_split_side_by_side(&rh->base, &info);
161 } else {
162 U_LOG_E("Invalid view count");
163 ret = false;
164 }
165 if (!ret) {
166 U_LOG_E("Failed to setup basic device info");
167 r_hmd_destroy(&rh->base);
168 return NULL;
169 }
170
171 // Distortion information, fills in xdev->compute_distortion().
172 u_distortion_mesh_set_none(&rh->base);
173
174 // Setup variable tracker.
175 u_var_add_root(rh, rh->base.str, true);
176
177 return &rh->base;
178}