The open source OpenXR runtime
0
fork

Configure Feed

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

d/steamvr_lh: Support loading SlimeVR OpenVR driver alongside lighthouse

Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2251>

rcelyte 3139079a 9422aca6

+104 -49
+1
doc/changes/drivers/mr.2251.md
··· 1 + steamvr_lh: Support loading SlimeVR OpenVR driver alongside lighthouse
+17
src/xrt/drivers/steamvr_lh/device.cpp
··· 810 810 } 811 811 break; 812 812 } 813 + case vr::Prop_ModelNumber_String: { 814 + using namespace std::literals::string_view_literals; 815 + vr::PropertyWrite_t fixedProp = prop; 816 + const std::string_view name = {static_cast<char *>(prop.pvBuffer), prop.unBufferSize}; 817 + if (name == "SlimeVR Virtual Tracker\0"sv) { 818 + static const InputClass input_class = { 819 + XRT_DEVICE_VIVE_TRACKER, {XRT_INPUT_GENERIC_TRACKER_POSE}, {}, {}}; 820 + this->name = input_class.name; 821 + set_input_class(&input_class); 822 + this->manufacturer = name.substr(0, name.find_first_of(' ')); 823 + fixedProp.pvBuffer = (char *)fixedProp.pvBuffer + this->manufacturer.size() + 824 + (this->manufacturer.size() != name.size()); 825 + fixedProp.unBufferSize = name.end() - (char *)fixedProp.pvBuffer; 826 + } 827 + Device::handle_property_write(fixedProp); 828 + break; 829 + } 813 830 case vr::Prop_ControllerRoleHint_Int32: { 814 831 vr::ETrackedControllerRole role = *static_cast<vr::ETrackedControllerRole *>(prop.pvBuffer); 815 832 switch (role) {
+6 -4
src/xrt/drivers/steamvr_lh/interfaces/context.hpp
··· 102 102 103 103 bool 104 104 setup_controller(const char *serial, vr::ITrackedDeviceServerDriver *driver); 105 - vr::IServerTrackedDeviceProvider *provider; 105 + std::vector<vr::IServerTrackedDeviceProvider *> providers; 106 106 107 107 inline vr::VRInputComponentHandle_t 108 108 new_handle() ··· 112 112 return h; 113 113 } 114 114 115 - protected: 115 + public: 116 116 Context(const std::string &steam_install, const std::string &steamvr_install, u_logging_level level); 117 117 118 - public: 119 118 // These are owned by monado, context is destroyed when these are destroyed 120 119 class HmdDevice *hmd{nullptr}; 121 120 class ControllerDevice *controller[16]{nullptr}; ··· 126 125 [[nodiscard]] static std::shared_ptr<Context> 127 126 create(const std::string &steam_install, 128 127 const std::string &steamvr_install, 129 - vr::IServerTrackedDeviceProvider *p); 128 + std::vector<vr::IServerTrackedDeviceProvider *> providers); 129 + 130 + void 131 + run_frame(); 130 132 131 133 void 132 134 maybe_run_frame(uint64_t new_frame);
+80 -45
src/xrt/drivers/steamvr_lh/steamvr_lh.cpp
··· 15 15 #include <string_view> 16 16 #include <filesystem> 17 17 #include <istream> 18 + #include <thread> 18 19 19 20 #include "openvr_driver.h" 20 21 #include "vdf_parser.hpp" ··· 29 30 #include "util/u_system_helpers.h" 30 31 #include "vive/vive_bindings.h" 31 32 33 + #include "math/m_api.h" 34 + 32 35 namespace { 33 36 34 37 DEBUG_GET_ONCE_LOG_OPTION(lh_log, "LIGHTHOUSE_LOG", U_LOGGING_INFO) 38 + DEBUG_GET_ONCE_BOOL_OPTION(lh_load_slimevr, "LH_LOAD_SLIMEVR", false) 35 39 36 40 static const size_t MAX_CONTROLLERS = 16; 37 41 ··· 46 50 47 51 //! Pointer to driver context 48 52 std::shared_ptr<Context> ctx; 49 - 50 - // Controller as index and value as xdev 51 - int32_t controller_to_xdev_map[MAX_CONTROLLERS]; 52 53 53 54 //! Index to the left controller. 54 55 int32_t left_index; ··· 106 107 std::shared_ptr<Context> 107 108 Context::create(const std::string &steam_install, 108 109 const std::string &steamvr_install, 109 - vr::IServerTrackedDeviceProvider *p) 110 + std::vector<vr::IServerTrackedDeviceProvider *> providers) 110 111 { 111 112 // xrt_tracking_origin initialization 112 - Context *c = new Context(steam_install, steamvr_install, debug_get_log_option_lh_log()); 113 - c->provider = p; 113 + std::shared_ptr<Context> c = 114 + std::make_shared<Context>(steam_install, steamvr_install, debug_get_log_option_lh_log()); 115 + c->providers = std::move(providers); 114 116 std::strncpy(c->name, "SteamVR Lighthouse Tracking", XRT_TRACKING_NAME_LEN); 115 117 c->type = XRT_TRACKING_TYPE_LIGHTHOUSE; 116 118 c->offset = XRT_POSE_IDENTITY; 117 - return std::shared_ptr<Context>(c); 119 + for (vr::IServerTrackedDeviceProvider *const &driver : c->providers) { 120 + vr::EVRInitError err = driver->Init(c.get()); 121 + if (err != vr::VRInitError_None) { 122 + U_LOG_IFL_E(c->log_level, "OpenVR driver initialization failed: error %u", err); 123 + return nullptr; 124 + } 125 + } 126 + return c; 118 127 } 119 128 120 129 Context::Context(const std::string &steam_install, const std::string &steamvr_install, u_logging_level level) ··· 123 132 124 133 Context::~Context() 125 134 { 126 - provider->Cleanup(); 135 + for (vr::IServerTrackedDeviceProvider *const &provider : providers) 136 + provider->Cleanup(); 127 137 } 128 138 129 139 /***** IVRDriverContext methods *****/ ··· 270 280 } 271 281 272 282 void 283 + Context::run_frame() 284 + { 285 + for (vr::IServerTrackedDeviceProvider *const &provider : providers) 286 + provider->RunFrame(); 287 + } 288 + 289 + void 273 290 Context::maybe_run_frame(uint64_t new_frame) 274 291 { 275 292 if (new_frame > current_frame) { 276 293 ++current_frame; 277 - provider->RunFrame(); 294 + run_frame(); 278 295 } 279 296 } 280 297 // NOLINTBEGIN(bugprone-easily-swappable-parameters) ··· 314 331 { 315 332 assert(sizeof(newPose) == unPoseStructSize); 316 333 317 - // Check for valid device index, allowing for the HMD plus up to 16 controllers 318 - if (unWhichDevice > 16) 334 + // Check for valid device index, allowing for the HMD plus up to MAX_CONTROLLERS controllers 335 + if (unWhichDevice > MAX_CONTROLLERS) 319 336 return; 320 337 321 338 Device *dev = nullptr; ··· 387 404 Context::GetRawTrackedDevicePoses(float fPredictedSecondsFromNow, 388 405 vr::TrackedDevicePose_t *pTrackedDevicePoseArray, 389 406 uint32_t unTrackedDevicePoseArrayCount) 390 - {} 407 + { 408 + // This is the bare minimum required for SlimeVR's HMD feedback to work 409 + if (unTrackedDevicePoseArrayCount != 10 || this->hmd == nullptr) 410 + return; 411 + const uint64_t time = 412 + std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()) 413 + .count(); 414 + xrt_space_relation head = {}; 415 + xrt_device_get_tracked_pose(this->hmd, XRT_INPUT_GENERIC_HEAD_POSE, time, &head); 416 + xrt_matrix_3x3 rot = {}; 417 + math_matrix_3x3_from_quat(&head.pose.orientation, &rot); 418 + pTrackedDevicePoseArray[0].mDeviceToAbsoluteTracking = {{ 419 + {rot.v[0], rot.v[3], rot.v[6], head.pose.position.x}, 420 + {rot.v[1], rot.v[4], rot.v[7], head.pose.position.y}, 421 + {rot.v[2], rot.v[5], rot.v[8], head.pose.position.z}, 422 + }}; 423 + } 391 424 392 425 void 393 426 Context::RequestRestart(const char *pchLocalizedReason, ··· 672 705 if (nDevice == 0 && this->hmd) { 673 706 return container; 674 707 } 675 - if (nDevice >= 1 && nDevice <= 16 && this->controller[nDevice - 1]) { 708 + if (nDevice >= 1 && nDevice <= MAX_CONTROLLERS && this->controller[nDevice - 1]) { 676 709 return container; 677 710 } 678 711 ··· 727 760 728 761 U_LOG_IFL_I(level, "Found SteamVR install: %s", steamvr.c_str()); 729 762 730 - // TODO: support windows? 731 - auto driver_so = steamvr + "/drivers/lighthouse/bin/linux64/driver_lighthouse.so"; 763 + std::vector<vr::IServerTrackedDeviceProvider *> drivers = {}; 764 + const auto loadDriver = [&](std::string soPath, bool require) { 765 + // TODO: support windows? 766 + void *driver_lib = dlopen((steamvr + soPath).c_str(), RTLD_LAZY); 767 + if (!driver_lib) { 768 + U_LOG_IFL_E(level, "Couldn't open driver lib: %s", dlerror()); 769 + return !require; 770 + } 732 771 733 - void *lighthouse_lib = dlopen(driver_so.c_str(), RTLD_LAZY); 734 - if (!lighthouse_lib) { 735 - U_LOG_IFL_E(level, "Couldn't open lighthouse lib: %s", dlerror()); 736 - return xrt_result::XRT_ERROR_DEVICE_CREATION_FAILED; 737 - } 772 + void *sym = dlsym(driver_lib, "HmdDriverFactory"); 773 + if (!sym) { 774 + U_LOG_IFL_E(level, "Couldn't find HmdDriverFactory in driver lib: %s", dlerror()); 775 + return false; 776 + } 777 + using HmdDriverFactory_t = void *(*)(const char *, int *); 778 + auto factory = reinterpret_cast<HmdDriverFactory_t>(sym); 738 779 739 - void *sym = dlsym(lighthouse_lib, "HmdDriverFactory"); 740 - if (!sym) { 741 - U_LOG_IFL_E(level, "Couldn't find HmdDriverFactory in lighthouse lib: %s", dlerror()); 780 + vr::EVRInitError err = vr::VRInitError_None; 781 + drivers.push_back(static_cast<vr::IServerTrackedDeviceProvider *>( 782 + factory(vr::IServerTrackedDeviceProvider_Version, (int *)&err))); 783 + if (err != vr::VRInitError_None) { 784 + U_LOG_IFL_E(level, "Couldn't get tracked device driver: error %u", err); 785 + return false; 786 + } 787 + return true; 788 + }; 789 + if (!loadDriver("/drivers/lighthouse/bin/linux64/driver_lighthouse.so", true)) 742 790 return xrt_result::XRT_ERROR_DEVICE_CREATION_FAILED; 743 - } 744 - using HmdDriverFactory_t = void *(*)(const char *, int *); 745 - auto factory = reinterpret_cast<HmdDriverFactory_t>(sym); 746 - 747 - vr::EVRInitError err = vr::VRInitError_None; 748 - auto *driver = static_cast<vr::IServerTrackedDeviceProvider *>( 749 - factory(vr::IServerTrackedDeviceProvider_Version, (int *)&err)); 750 - if (err != vr::VRInitError_None) { 751 - U_LOG_IFL_E(level, "Couldn't get tracked device driver: error %u", err); 791 + if (debug_get_bool_option_lh_load_slimevr() && 792 + !loadDriver("/drivers/slimevr/bin/linux64/driver_slimevr.so", false)) 752 793 return xrt_result::XRT_ERROR_DEVICE_CREATION_FAILED; 753 - } 754 - 755 - svrs->ctx = Context::create(STEAM_INSTALL_DIR, steamvr, driver); 756 - 757 - err = driver->Init(svrs->ctx.get()); 758 - if (err != vr::VRInitError_None) { 759 - U_LOG_IFL_E(level, "Lighthouse driver initialization failed: error %u", err); 794 + svrs->ctx = Context::create(STEAM_INSTALL_DIR, steamvr, std::move(drivers)); 795 + if (svrs->ctx == nullptr) 760 796 return xrt_result::XRT_ERROR_DEVICE_CREATION_FAILED; 761 - } 762 797 763 798 U_LOG_IFL_I(level, "Lighthouse initialization complete, giving time to setup connected devices..."); 764 799 // RunFrame needs to be called to detect controllers 765 800 using namespace std::chrono_literals; 766 801 auto start_time = std::chrono::steady_clock::now(); 767 802 while (true) { 768 - driver->RunFrame(); 803 + svrs->ctx->run_frame(); 769 804 auto cur_time = std::chrono::steady_clock::now(); 770 805 if (cur_time - start_time >= 3s) { 771 806 break; 772 807 } 808 + std::this_thread::sleep_for(20ms); 773 809 } 774 810 U_LOG_IFL_I(level, "Device search time complete."); 775 811 ··· 803 839 xsysd->static_roles.head = head; 804 840 } 805 841 806 - // Include the controllers (up to 16) 807 - for (int i = 0; i < 16; i++) { 842 + // Include the controllers 843 + for (int i = 0; i < MAX_CONTROLLERS; i++) { 808 844 if (svrs->ctx->controller[i]) { 809 - xsysd->xdevs[xsysd->xdev_count] = svrs->ctx->controller[i]; 810 - svrs->controller_to_xdev_map[i] = xsysd->xdev_count++; 845 + xsysd->xdevs[xsysd->xdev_count++] = svrs->ctx->controller[i]; 811 846 } 812 847 } 813 848