The open source OpenXR runtime
1// Copyright 2020-2021, The Board of Trustees of the University of Illinois.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief ILLIXR HMD
6 * @author RSIM Group <illixr@cs.illinois.edu>
7 * @ingroup drv_illixr
8 */
9
10#include <math.h>
11#include <stdio.h>
12#include <unistd.h>
13#include <stdlib.h>
14#include <string.h>
15#include <assert.h>
16#include <dlfcn.h>
17#include <alloca.h>
18#include <string>
19#include <sstream>
20
21#include "math/m_api.h"
22#include "xrt/xrt_device.h"
23#include "util/u_var.h"
24#include "util/u_misc.h"
25#include "util/u_debug.h"
26#include "util/u_device.h"
27#include "util/u_time.h"
28#include "util/u_distortion_mesh.h"
29
30#include "illixr_component.h"
31#include "common/dynamic_lib.hpp"
32#include "common/runtime.hpp"
33
34/*
35 *
36 * Structs and defines.
37 *
38 */
39
40struct illixr_hmd
41{
42 struct xrt_device base;
43
44 struct xrt_pose pose;
45
46 bool print_spew;
47 bool print_debug;
48
49 const char *path;
50 const char *comp;
51 ILLIXR::dynamic_lib *runtime_lib;
52 ILLIXR::runtime *runtime;
53};
54
55
56/*
57 *
58 * Functions
59 *
60 */
61
62static inline struct illixr_hmd *
63illixr_hmd(struct xrt_device *xdev)
64{
65 return (struct illixr_hmd *)xdev;
66}
67
68DEBUG_GET_ONCE_BOOL_OPTION(illixr_spew, "ILLIXR_PRINT_SPEW", false)
69DEBUG_GET_ONCE_BOOL_OPTION(illixr_debug, "ILLIXR_PRINT_DEBUG", false)
70
71#define DH_SPEW(dh, ...) \
72 do { \
73 if (dh->print_spew) { \
74 fprintf(stderr, "%s - ", __func__); \
75 fprintf(stderr, __VA_ARGS__); \
76 fprintf(stderr, "\n"); \
77 } \
78 } while (false)
79
80#define DH_DEBUG(dh, ...) \
81 do { \
82 if (dh->print_debug) { \
83 fprintf(stderr, "%s - ", __func__); \
84 fprintf(stderr, __VA_ARGS__); \
85 fprintf(stderr, "\n"); \
86 } \
87 } while (false)
88
89#define DH_ERROR(dh, ...) \
90 do { \
91 fprintf(stderr, "%s - ", __func__); \
92 fprintf(stderr, __VA_ARGS__); \
93 fprintf(stderr, "\n"); \
94 } while (false)
95
96static void
97illixr_hmd_destroy(struct xrt_device *xdev)
98{
99 struct illixr_hmd *dh = illixr_hmd(xdev);
100 dh->runtime->stop();
101 delete dh->runtime;
102 delete dh->runtime_lib;
103
104 // Remove the variable tracking.
105 u_var_remove_root(dh);
106
107 u_device_free(&dh->base);
108}
109
110static void
111illixr_hmd_get_tracked_pose(struct xrt_device *xdev,
112 enum xrt_input_name name,
113 uint64_t at_timestamp_ns,
114 struct xrt_space_relation *out_relation)
115{
116 if (name != XRT_INPUT_GENERIC_HEAD_POSE) {
117 DH_ERROR(illixr_hmd(xdev), "unknown input name");
118 return;
119 }
120
121 out_relation->pose = illixr_read_pose();
122 out_relation->relation_flags = (enum xrt_space_relation_flags)(
123 XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT |
124 XRT_SPACE_RELATION_POSITION_VALID_BIT | XRT_SPACE_RELATION_POSITION_TRACKED_BIT);
125}
126
127std::vector<std::string>
128split(const std::string &s, char delimiter)
129{
130 std::vector<std::string> tokens;
131 std::string token;
132 std::istringstream tokenStream{s};
133 while (std::getline(tokenStream, token, delimiter)) {
134 tokens.push_back(token);
135 }
136 return tokens;
137}
138
139static int
140illixr_rt_launch(struct illixr_hmd *dh, const char *path, const char *comp)
141{
142 dh->runtime_lib = new ILLIXR::dynamic_lib{ILLIXR::dynamic_lib::create(std::string{path})};
143 dh->runtime = dh->runtime_lib->get<ILLIXR::runtime *(*)()>("runtime_factory")();
144 dh->runtime->load_so(split(std::string{comp}, ':'));
145 dh->runtime->load_plugin_factory((ILLIXR::plugin_factory)illixr_monado_create_plugin);
146
147 return 0;
148}
149
150extern "C" struct xrt_device *
151illixr_hmd_create(const char *path_in, const char *comp_in)
152{
153 struct illixr_hmd *dh;
154 enum u_device_alloc_flags flags =
155 (enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE);
156 dh = U_DEVICE_ALLOCATE(struct illixr_hmd, flags, 1, 0);
157 dh->base.update_inputs = u_device_noop_update_inputs;
158 dh->base.get_tracked_pose = illixr_hmd_get_tracked_pose;
159 dh->base.get_view_poses = u_device_get_view_poses;
160 dh->base.destroy = illixr_hmd_destroy;
161 dh->base.name = XRT_DEVICE_GENERIC_HMD;
162 dh->base.device_type = XRT_DEVICE_TYPE_HMD;
163
164 size_t idx = 0;
165 dh->base.hmd->blend_modes[idx++] = XRT_BLEND_MODE_OPAQUE;
166 dh->base.hmd->blend_mode_count = idx;
167
168 dh->pose.orientation.w = 1.0f; // All other values set to zero.
169 dh->print_spew = debug_get_bool_option_illixr_spew();
170 dh->print_debug = debug_get_bool_option_illixr_debug();
171 dh->path = path_in;
172 dh->comp = comp_in;
173
174 // Print name.
175 snprintf(dh->base.str, XRT_DEVICE_NAME_LEN, "ILLIXR");
176 snprintf(dh->base.serial, XRT_DEVICE_NAME_LEN, "ILLIXR");
177
178 // Setup input.
179 dh->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE;
180
181 // Setup info.
182 struct u_device_simple_info info;
183 info.display.w_pixels = 2048;
184 info.display.h_pixels = 1024;
185 info.display.w_meters = 0.14f;
186 info.display.h_meters = 0.07f;
187 info.lens_horizontal_separation_meters = 0.13f / 2.0f;
188 info.lens_vertical_position_meters = 0.07f / 2.0f;
189 info.fov[0] = 85.0f * (M_PI / 180.0f);
190 info.fov[1] = 85.0f * (M_PI / 180.0f);
191
192 if (!u_device_setup_split_side_by_side(&dh->base, &info)) {
193 DH_ERROR(dh, "Failed to setup basic device info");
194 illixr_hmd_destroy(&dh->base);
195 return NULL;
196 }
197
198 // Setup variable tracker.
199 u_var_add_root(dh, "ILLIXR", true);
200 u_var_add_pose(dh, &dh->pose, "pose");
201
202 if (dh->base.hmd->distortion.preferred == XRT_DISTORTION_MODEL_NONE) {
203 // Setup the distortion mesh.
204 u_distortion_mesh_set_none(&dh->base);
205 }
206
207 // start ILLIXR runtime
208 if (illixr_rt_launch(dh, dh->path, dh->comp) != 0) {
209 DH_ERROR(dh, "Failed to load ILLIXR Runtime");
210 illixr_hmd_destroy(&dh->base);
211 }
212
213 return &dh->base;
214}