diff --git a/CMakeLists.txt b/CMakeLists.txt index 4df0cbbb6..f97b4724c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -156,6 +156,9 @@ endif() # Most users won't touch these. mark_as_advanced(XRT_FEATURE_COMPOSITOR_MAIN XRT_FEATURE_OPENXR) +# ILLIXR +set(ILLIXR_PATH "" CACHE PATH "Path to ILLIXR headers") + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") set(XRT_HAVE_LIBUDEV ON) set(XRT_HAVE_INTERNAL_HID ON) @@ -178,6 +181,7 @@ cmake_dependent_option(XRT_BUILD_DRIVER_OHMD "Enable OpenHMD driver" ON "OPENHMD cmake_dependent_option(XRT_BUILD_DRIVER_HANDTRACKING "Enable Camera Hand Tracking driver" ON "XRT_HAVE_V4L2" OFF) cmake_dependent_option(XRT_BUILD_DRIVER_DAYDREAM "Enable the Google Daydream View controller driver (BLE, via D-Bus)" ON "XRT_HAVE_DBUS" OFF) cmake_dependent_option(XRT_BUILD_DRIVER_ARDUINO "Enable Arduino input device with BLE via via D-Bus" ON "XRT_HAVE_DBUS" OFF) +cmake_dependent_option(XRT_BUILD_DRIVER_ILLIXR "Enable ILLIXR driver" ON "ILLIXR_PATH" OFF) option(XRT_BUILD_DRIVER_DUMMY "Enable dummy driver" ON) cmake_dependent_option(XRT_BUILD_DRIVER_REMOTE "Enable remote debugging driver" ON "XRT_HAVE_LINUX OR ANDROID" OFF) @@ -195,7 +199,7 @@ cmake_dependent_option(XRT_BUILD_DRIVER_ANDROID "Enable Android sensors driver" # You can set this from a superproject to add a driver # All drivers must be listed in here to be included in the generated header! -list(APPEND AVAILABLE_DRIVERS "ANDROID" ARDUINO DUMMY HDK HYDRA NS OHMD PSMV PSVR RS V4L2 VIVE DAYDREAM REMOTE SURVIVE HANDTRACKING) +list(APPEND AVAILABLE_DRIVERS "ANDROID" ARDUINO DUMMY HDK HYDRA NS OHMD PSMV PSVR RS V4L2 VIVE DAYDREAM REMOTE SURVIVE HANDTRACKING ILLIXR) # Package name needs to be known by the native code itself. @@ -315,6 +319,7 @@ message(STATUS "# DRIVER_DAYDREAM: ${XRT_BUILD_DRIVER_DAYDREAM}") message(STATUS "# DRIVER_DUMMY: ${XRT_BUILD_DRIVER_DUMMY}") message(STATUS "# DRIVER_HDK: ${XRT_BUILD_DRIVER_HDK}") message(STATUS "# DRIVER_HYDRA: ${XRT_BUILD_DRIVER_HYDRA}") +message(STATUS "# DRIVER_ILLIXR: ${XRT_BUILD_DRIVER_ILLIXR}") message(STATUS "# DRIVER_NS: ${XRT_BUILD_DRIVER_NS}") message(STATUS "# DRIVER_OHMD: ${XRT_BUILD_DRIVER_OHMD}") message(STATUS "# DRIVER_HANDTRACKING: ${XRT_BUILD_DRIVER_HANDTRACKING}") diff --git a/src/xrt/drivers/CMakeLists.txt b/src/xrt/drivers/CMakeLists.txt index e6e7246b0..65617a9b8 100644 --- a/src/xrt/drivers/CMakeLists.txt +++ b/src/xrt/drivers/CMakeLists.txt @@ -231,6 +231,22 @@ if(XRT_BUILD_DRIVER_ANDROID) list(APPEND ENABLED_DRIVERS android) endif() +if (XRT_BUILD_DRIVER_ILLIXR) + set(ILLIXR_SOURCE_FILES + illixr/illixr_device.cpp + illixr/illixr_interface.h + illixr/illixr_prober.c + illixr/illixr_component.cpp + illixr/illixr_component.h + ) + + add_library(drv_illixr STATIC ${ILLIXR_SOURCE_FILES}) + target_link_libraries(drv_illixr PUBLIC ${CMAKE_DL_LIBS} xrt-interfaces aux_util aux_os) + target_include_directories(drv_illixr PUBLIC ${ILLIXR_PATH}) + target_compile_options(drv_illixr PUBLIC $<$:-std=c++17>) + list(APPEND ENABLED_HEADSET_DRIVERS illixr) +endif() + if(ENABLED_HEADSET_DRIVERS) set(ENABLED_DRIVERS ${ENABLED_HEADSET_DRIVERS} ${ENABLED_DRIVERS}) list(SORT ENABLED_DRIVERS) @@ -238,4 +254,4 @@ if(ENABLED_HEADSET_DRIVERS) message(STATUS "Enabled drivers: ${ENABLED_DRIVERS}") else() message(FATAL_ERROR "You must enable at least one headset driver to build Monado.") -endif() +endif() \ No newline at end of file diff --git a/src/xrt/drivers/illixr/illixr_component.cpp b/src/xrt/drivers/illixr/illixr_component.cpp new file mode 100644 index 000000000..9e4af3be2 --- /dev/null +++ b/src/xrt/drivers/illixr/illixr_component.cpp @@ -0,0 +1,84 @@ +// Copyright 2020-2021, The Board of Trustees of the University of Illinois. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief ILLIXR plugin + * @author RSIM Group + * @ingroup drv_illixr + */ + + +#include "xrt/xrt_device.h" + +#include +#include "common/plugin.hpp" +#include "common/phonebook.hpp" +#include "common/switchboard.hpp" +#include "common/data_format.hpp" +#include "common/pose_prediction.hpp" + +using namespace ILLIXR; + +/// Dummy plugin class for an instance during phonebook registration +class illixr_plugin : public plugin +{ +public: + illixr_plugin(std::string name_, phonebook *pb_) + : plugin{name_, pb_}, sb{pb->lookup_impl()}, + sb_pose{pb->lookup_impl()}, + sb_eyebuffer{sb->publish("eyebuffer")}, + sb_vsync_estimate{ + sb->subscribe_latest("vsync_estimate")} + {} + + const std::shared_ptr sb; + const std::shared_ptr sb_pose; + const std::unique_ptr> sb_eyebuffer; + const std::unique_ptr> sb_vsync_estimate; + fast_pose_type prev_pose; /* stores a copy of pose each time + illixr_read_pose() is called */ + std::chrono::time_point + sample_time; /* when prev_pose was stored */ +}; + +static illixr_plugin *illixr_plugin_obj = nullptr; + +extern "C" plugin * +illixr_monado_create_plugin(phonebook *pb) +{ + illixr_plugin_obj = new illixr_plugin{"illixr_plugin", pb}; + illixr_plugin_obj->start(); + return illixr_plugin_obj; +} + +extern "C" struct xrt_pose +illixr_read_pose() +{ + assert(illixr_plugin_obj && + "illixr_plugin_obj must be initialized first."); + + if (!illixr_plugin_obj->sb_pose->fast_pose_reliable()) { + std::cerr << "Pose not reliable yet; returning best guess" + << std::endl; + } + struct xrt_pose ret; + const fast_pose_type fast_pose = + illixr_plugin_obj->sb_pose->get_fast_pose(); + const pose_type pose = fast_pose.pose; + + // record when the pose was read for use in write_frame + illixr_plugin_obj->sample_time = std::chrono::system_clock::now(); + + ret.orientation.x = pose.orientation.x(); + ret.orientation.y = pose.orientation.y(); + ret.orientation.z = pose.orientation.z(); + ret.orientation.w = pose.orientation.w(); + ret.position.x = pose.position.x(); + ret.position.y = pose.position.y(); + ret.position.z = pose.position.z(); + + // store pose in static variable for use in write_frame + illixr_plugin_obj->prev_pose = fast_pose; // copy member variables + + return ret; +} \ No newline at end of file diff --git a/src/xrt/drivers/illixr/illixr_component.h b/src/xrt/drivers/illixr/illixr_component.h new file mode 100644 index 000000000..eab3ef8db --- /dev/null +++ b/src/xrt/drivers/illixr/illixr_component.h @@ -0,0 +1,23 @@ +// Copyright 2020-2021, The Board of Trustees of the University of Illinois. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief ILLIXR plugin + * @author RSIM Group + * @ingroup drv_illixr + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void * +illixr_monado_create_plugin(void *pb); +struct xrt_pose +illixr_read_pose(); + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/drivers/illixr/illixr_device.cpp b/src/xrt/drivers/illixr/illixr_device.cpp new file mode 100644 index 000000000..5b0c478c9 --- /dev/null +++ b/src/xrt/drivers/illixr/illixr_device.cpp @@ -0,0 +1,231 @@ +// Copyright 2020-2021, The Board of Trustees of the University of Illinois. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief ILLIXR HMD + * @author RSIM Group + * @ingroup drv_illixr + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "math/m_api.h" +#include "xrt/xrt_device.h" +#include "util/u_var.h" +#include "util/u_misc.h" +#include "util/u_debug.h" +#include "util/u_device.h" +#include "util/u_time.h" +#include "util/u_distortion_mesh.h" + +#include "illixr_component.h" +#include "common/dynamic_lib.hpp" +#include "common/runtime.hpp" + +/* + * + * Structs and defines. + * + */ + +struct illixr_hmd +{ + struct xrt_device base; + + struct xrt_pose pose; + + bool print_spew; + bool print_debug; + + const char *path; + const char *comp; + ILLIXR::dynamic_lib *runtime_lib; + ILLIXR::runtime *runtime; +}; + + +/* + * + * Functions + * + */ + +static inline struct illixr_hmd * +illixr_hmd(struct xrt_device *xdev) +{ + return (struct illixr_hmd *)xdev; +} + +DEBUG_GET_ONCE_BOOL_OPTION(illixr_spew, "ILLIXR_PRINT_SPEW", false) +DEBUG_GET_ONCE_BOOL_OPTION(illixr_debug, "ILLIXR_PRINT_DEBUG", false) + +#define DH_SPEW(dh, ...) \ + do { \ + if (dh->print_spew) { \ + fprintf(stderr, "%s - ", __func__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } \ + } while (false) + +#define DH_DEBUG(dh, ...) \ + do { \ + if (dh->print_debug) { \ + fprintf(stderr, "%s - ", __func__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } \ + } while (false) + +#define DH_ERROR(dh, ...) \ + do { \ + fprintf(stderr, "%s - ", __func__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } while (false) + +static void +illixr_hmd_destroy(struct xrt_device *xdev) +{ + struct illixr_hmd *dh = illixr_hmd(xdev); + dh->runtime->stop(); + delete dh->runtime; + delete dh->runtime_lib; + + // Remove the variable tracking. + u_var_remove_root(dh); + + u_device_free(&dh->base); +} + +static void +illixr_hmd_update_inputs(struct xrt_device *xdev) +{ + // Empty +} + +static void +illixr_hmd_get_tracked_pose(struct xrt_device *xdev, + enum xrt_input_name name, + uint64_t at_timestamp_ns, + struct xrt_space_relation *out_relation) +{ + if (name != XRT_INPUT_GENERIC_HEAD_POSE) { + DH_ERROR(illixr_hmd(xdev), "unknown input name"); + return; + } + + out_relation->pose = illixr_read_pose(); + out_relation->relation_flags = (enum xrt_space_relation_flags)( + XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | + XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | + XRT_SPACE_RELATION_POSITION_VALID_BIT | + XRT_SPACE_RELATION_POSITION_TRACKED_BIT); +} + +static void +illixr_hmd_get_view_pose(struct xrt_device *xdev, + struct xrt_vec3 *eye_relation, + uint32_t view_index, + struct xrt_pose *out_pose) +{ + struct xrt_pose pose = illixr_read_pose(); + + *out_pose = pose; +} + +std::vector +split(const std::string &s, char delimiter) +{ + std::vector tokens; + std::string token; + std::istringstream tokenStream{s}; + while (std::getline(tokenStream, token, delimiter)) { + tokens.push_back(token); + } + return tokens; +} + +static int +illixr_rt_launch(struct illixr_hmd *dh, const char *path, const char *comp) +{ + dh->runtime_lib = new ILLIXR::dynamic_lib{ + ILLIXR::dynamic_lib::create(std::string{path})}; + dh->runtime = + dh->runtime_lib->get("runtime_factory")(); + dh->runtime->load_so(split(std::string{comp}, ':')); + dh->runtime->load_plugin_factory( + (ILLIXR::plugin_factory)illixr_monado_create_plugin); + + return 0; +} + +extern "C" struct xrt_device * +illixr_hmd_create(const char *path_in, const char *comp_in) +{ + struct illixr_hmd *dh; + enum u_device_alloc_flags flags = (enum u_device_alloc_flags)( + U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE); + dh = U_DEVICE_ALLOCATE(struct illixr_hmd, flags, 1, 0); + dh->base.update_inputs = illixr_hmd_update_inputs; + dh->base.get_tracked_pose = illixr_hmd_get_tracked_pose; + dh->base.get_view_pose = illixr_hmd_get_view_pose; + dh->base.destroy = illixr_hmd_destroy; + dh->base.name = XRT_DEVICE_GENERIC_HMD; + dh->base.device_type = XRT_DEVICE_TYPE_HMD; + dh->base.hmd->blend_mode = XRT_BLEND_MODE_OPAQUE; + dh->pose.orientation.w = 1.0f; // All other values set to zero. + dh->print_spew = debug_get_bool_option_illixr_spew(); + dh->print_debug = debug_get_bool_option_illixr_debug(); + dh->path = path_in; + dh->comp = comp_in; + + // Print name. + snprintf(dh->base.str, XRT_DEVICE_NAME_LEN, "ILLIXR"); + + // Setup input. + dh->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; + + // Setup info. + struct u_device_simple_info info; + info.display.w_pixels = 2048; + info.display.h_pixels = 1024; + info.display.w_meters = 0.14f; + info.display.h_meters = 0.07f; + info.lens_horizontal_separation_meters = 0.13f / 2.0f; + info.lens_vertical_position_meters = 0.07f / 2.0f; + info.views[0].fov = 85.0f * (M_PI / 180.0f); + info.views[1].fov = 85.0f * (M_PI / 180.0f); + + if (!u_device_setup_split_side_by_side(&dh->base, &info)) { + DH_ERROR(dh, "Failed to setup basic device info"); + illixr_hmd_destroy(&dh->base); + return NULL; + } + + // Setup variable tracker. + u_var_add_root(dh, "ILLIXR", true); + u_var_add_pose(dh, &dh->pose, "pose"); + + if (dh->base.hmd->distortion.preferred == XRT_DISTORTION_MODEL_NONE) { + // Setup the distortion mesh. + u_distortion_mesh_set_none(&dh->base); + } + + // start ILLIXR runtime + if (illixr_rt_launch(dh, dh->path, dh->comp) != 0) { + DH_ERROR(dh, "Failed to load ILLIXR Runtime"); + illixr_hmd_destroy(&dh->base); + } + + return &dh->base; +} diff --git a/src/xrt/drivers/illixr/illixr_interface.h b/src/xrt/drivers/illixr/illixr_interface.h new file mode 100644 index 000000000..c4a2003a2 --- /dev/null +++ b/src/xrt/drivers/illixr/illixr_interface.h @@ -0,0 +1,48 @@ +// Copyright 2020-2021, The Board of Trustees of the University of Illinois. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief ILLIXR driver interface + * @author RSIM Group + * @ingroup drv_illixr + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @defgroup drv_illixr illixr driver. + * @ingroup drv + * + * @brief illixr driver. + */ + +/*! + * Create a auto prober for illixr devices. + * + * @ingroup drv_illixr + */ +struct xrt_auto_prober * +illixr_create_auto_prober(void); + +/*! + * Create a illixr hmd. + * + * @ingroup drv_illixr + */ +struct xrt_device * +illixr_hmd_create(const char *path, const char *comp); + +/*! + * @dir drivers/illixr + * + * @brief @ref drv_illixr files. + */ + + +#ifdef __cplusplus +} +#endif diff --git a/src/xrt/drivers/illixr/illixr_prober.c b/src/xrt/drivers/illixr/illixr_prober.c new file mode 100644 index 000000000..3ef2a00bf --- /dev/null +++ b/src/xrt/drivers/illixr/illixr_prober.c @@ -0,0 +1,67 @@ +// Copyright 2020-2021, The Board of Trustees of the University of Illinois. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief ILLIXR prober + * @author RSIM Group + * @ingroup drv_illixr + */ + +#include "xrt/xrt_prober.h" +#include "util/u_misc.h" +#include "util/u_debug.h" + +#include "illixr_interface.h" + + +struct illixr_prober +{ + struct xrt_auto_prober base; +}; + +static inline struct illixr_prober * +illixr_prober(struct xrt_auto_prober *p) +{ + return (struct illixr_prober *)p; +} + +static void +illixr_prober_destroy(struct xrt_auto_prober *p) +{ + struct illixr_prober *dp = illixr_prober(p); + + free(dp); +} + +static struct xrt_device * +illixr_prober_autoprobe(struct xrt_auto_prober *xap, + cJSON *attached_data, + bool no_hmds, + struct xrt_prober *xp) +{ + struct illixr_prober *dp = illixr_prober(xap); + (void)dp; + + if (no_hmds) { + return NULL; + } + + const char *illixr_path, *illixr_comp; + illixr_path = getenv("ILLIXR_PATH"); + illixr_comp = getenv("ILLIXR_COMP"); + if (!illixr_path || !illixr_comp) { + return NULL; + } + + return illixr_hmd_create(illixr_path, illixr_comp); +} + +struct xrt_auto_prober * +illixr_create_auto_prober() +{ + struct illixr_prober *dp = U_TYPED_CALLOC(struct illixr_prober); + dp->base.destroy = illixr_prober_destroy; + dp->base.lelo_dallas_autoprobe = illixr_prober_autoprobe; + + return &dp->base; +} diff --git a/src/xrt/state_trackers/prober/CMakeLists.txt b/src/xrt/state_trackers/prober/CMakeLists.txt index 920d6f1f4..33ce97a97 100644 --- a/src/xrt/state_trackers/prober/CMakeLists.txt +++ b/src/xrt/state_trackers/prober/CMakeLists.txt @@ -89,4 +89,4 @@ if(XRT_BUILD_DRIVER_REMOTE) target_link_libraries(st_prober PRIVATE drv_remote ) -endif() +endif() \ No newline at end of file diff --git a/src/xrt/targets/cli/cli_cmd_probe.c b/src/xrt/targets/cli/cli_cmd_probe.c index e498c3a3d..cc8ac652d 100644 --- a/src/xrt/targets/cli/cli_cmd_probe.c +++ b/src/xrt/targets/cli/cli_cmd_probe.c @@ -92,6 +92,10 @@ cli_cmd_probe(int argc, const char **argv) printf(" libsurvive,"); #endif +#ifdef XRT_BUILD_DRIVER_ILLIXR + printf(" ILLIXR,"); +#endif + printf("\n"); // Initialize the prober. diff --git a/src/xrt/targets/common/CMakeLists.txt b/src/xrt/targets/common/CMakeLists.txt index ccf6d9120..a44fa9027 100644 --- a/src/xrt/targets/common/CMakeLists.txt +++ b/src/xrt/targets/common/CMakeLists.txt @@ -88,6 +88,10 @@ if(XRT_BUILD_DRIVER_ANDROID) target_link_libraries(target_lists PRIVATE drv_android) endif() +if(XRT_BUILD_DRIVER_ILLIXR) + target_link_libraries(target_lists PRIVATE drv_illixr) +endif() + #### # Instance # diff --git a/src/xrt/targets/common/target_lists.c b/src/xrt/targets/common/target_lists.c index 88334e393..7a7a016d7 100644 --- a/src/xrt/targets/common/target_lists.c +++ b/src/xrt/targets/common/target_lists.c @@ -62,6 +62,10 @@ #include "android/android_prober.h" #endif +#ifdef XRT_BUILD_DRIVER_ILLIXR +#include "illixr/illixr_interface.h" +#endif + /*! * Each entry should be a vendor ID (VID), product ID (PID), a "found" function, * and a string literal name. @@ -150,6 +154,10 @@ xrt_auto_prober_creator target_auto_list[] = { android_create_auto_prober, #endif +#ifdef XRT_BUILD_DRIVER_ILLIXR + illixr_create_auto_prober, +#endif + #ifdef XRT_BUILD_DRIVER_DUMMY // Dummy headset driver last. dummy_create_auto_prober,