Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion alvr/server_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ tokio = { version = "1", features = [
tower-http = { version = "0.6", features = ["cors", "set-header"] }
serde = "1"
serde_json = "1"
sysinfo = "0.38"
sysinfo = { version = "0.38", default-features = false, features = ["system"] }
2 changes: 1 addition & 1 deletion alvr/server_openvr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ alvr_server_io.workspace = true
alvr_session.workspace = true

serde_json = "1"
sysinfo = "0.38"
sysinfo = { version = "0.38", default-features = false, features = ["system"] }

[build-dependencies]
alvr_filesystem = { path = "../filesystem" }
Expand Down
21 changes: 1 addition & 20 deletions alvr/server_openvr/cpp/alvr_server/alvr_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class DriverProvider : public vr::IServerTrackedDeviceProvider {
std::map<uint64_t, TrackedDevice*> tracked_devices;

virtual vr::EVRInitError Init(vr::IVRDriverContext* pContext) override {
InitializeRuntime(); // sets up rust logging/runtime, keep first
Debug("DriverProvider::Init");

VR_INIT_SERVER_DRIVER_CONTEXT(pContext);
Expand Down Expand Up @@ -202,26 +203,6 @@ const char* g_driverRootDir;
Settings g_settings;
const Settings* Settings_Instance() { return &g_settings; }

void (*LogError)(const char* stringPtr);
void (*LogWarn)(const char* stringPtr);
void (*LogInfo)(const char* stringPtr);
void (*LogDebug)(const char* stringPtr);
void (*LogEncoder)(const char* stringPtr);
void (*LogPeriodically)(const char* tag, const char* stringPtr);
void (*DriverReadyIdle)(bool setDefaultChaprone);
void (*SetVideoConfigNals)(const unsigned char* configBuffer, int len, int codec);
void (*VideoSend)(unsigned long long targetTimestampNs, unsigned char* buf, int len, bool isIdr);
void (*HapticsSend)(unsigned long long path, float duration_s, float frequency, float amplitude);
void (*ShutdownRuntime)();
unsigned long long (*PathStringToHash)(const char* path);
void (*ReportPresent)(unsigned long long timestamp_ns, unsigned long long offset_ns);
void (*ReportComposed)(unsigned long long timestamp_ns, unsigned long long offset_ns);
FfiDynamicEncoderParams (*GetDynamicEncoderParams)();
unsigned long long (*GetSerialNumber)(unsigned long long deviceID, char* outString);
void (*SetOpenvrProps)(void* instancePtr, unsigned long long deviceID);
void (*RegisterButtons)(void* instancePtr, unsigned long long deviceID);
void (*WaitForVSync)();

void CppInit(bool earlyHmdInitialization, Settings settings) {
g_driver_provider.early_hmd_initialization = earlyHmdInitialization;

Expand Down
45 changes: 22 additions & 23 deletions alvr/server_openvr/cpp/alvr_server/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,32 +191,31 @@ extern "C" unsigned int RGBTOYUV420_SHADER_COMP_SPV_LEN;
extern "C" const char* g_sessionPath;
extern "C" const char* g_driverRootDir;

extern "C" void (*LogError)(const char* stringPtr);
extern "C" void (*LogWarn)(const char* stringPtr);
extern "C" void (*LogInfo)(const char* stringPtr);
extern "C" void (*LogDebug)(const char* stringPtr);
extern "C" void (*LogEncoder)(const char* stringPtr);
extern "C" void (*LogPeriodically)(const char* tag, const char* stringPtr);
extern "C" void (*DriverReadyIdle)(bool setDefaultChaprone);
extern "C" void (*SetVideoConfigNals)(const unsigned char* configBuffer, int len, int codec);
extern "C" void (*VideoSend)(
unsigned long long targetTimestampNs, unsigned char* buf, int len, bool isIdr
);
extern "C" void (*HapticsSend)(
unsigned long long path, float duration_s, float frequency, float amplitude
);
extern "C" void (*ShutdownRuntime)();
extern "C" unsigned long long (*PathStringToHash)(const char* path);
extern "C" void (*ReportPresent)(unsigned long long timestamp_ns, unsigned long long offset_ns);
extern "C" void (*ReportComposed)(unsigned long long timestamp_ns, unsigned long long offset_ns);
extern "C" FfiDynamicEncoderParams (*GetDynamicEncoderParams)();
extern "C" unsigned long long (*GetSerialNumber)(unsigned long long deviceID, char* outString);
extern "C" void (*SetOpenvrProps)(void* instancePtr, unsigned long long deviceID);
extern "C" void (*RegisterButtons)(void* instancePtr, unsigned long long deviceID);
extern "C" void (*WaitForVSync)();
extern "C" void LogError(const char* stringPtr);
extern "C" void LogWarn(const char* stringPtr);
extern "C" void LogInfo(const char* stringPtr);
extern "C" void LogDebug(const char* stringPtr);
extern "C" void LogEncoder(const char* stringPtr);
extern "C" void LogPeriodically(const char* tag, const char* stringPtr);
extern "C" void DriverReadyIdle(bool setDefaultChaprone);
extern "C" void SetVideoConfigNals(const unsigned char* configBuffer, int len, int codec);
extern "C" void
VideoSend(unsigned long long targetTimestampNs, unsigned char* buf, int len, bool isIdr);
extern "C" void
HapticsSend(unsigned long long path, float duration_s, float frequency, float amplitude);
extern "C" void ShutdownRuntime();
extern "C" unsigned long long PathStringToHash(const char* path);
extern "C" void ReportPresent(unsigned long long timestamp_ns, unsigned long long offset_ns);
extern "C" void ReportComposed(unsigned long long timestamp_ns, unsigned long long offset_ns);
extern "C" FfiDynamicEncoderParams GetDynamicEncoderParams();
extern "C" unsigned long long GetSerialNumber(unsigned long long deviceID, char* outString);
extern "C" void SetOpenvrProps(void* instancePtr, unsigned long long deviceID);
extern "C" void RegisterButtons(void* instancePtr, unsigned long long deviceID);
extern "C" void WaitForVSync();

extern "C" void CppInit(bool earlyHmdInitialization, Settings settings);
extern "C" void* CppOpenvrEntryPoint(const char* pInterfaceName, int* pReturnCode);
extern "C" void InitializeRuntime();
extern "C" bool InitializeStreaming(Settings settings);
extern "C" void DeinitializeStreaming();
extern "C" void SendVSync();
Expand Down
128 changes: 97 additions & 31 deletions alvr/server_openvr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ use std::{
static SERVER_CORE_CONTEXT: RwLock<Option<ServerCoreContext>> = RwLock::new(None);
static LOCAL_VIEW_PARAMS: RwLock<[ViewParams; 2]> = RwLock::new([ViewParams::DUMMY; 2]);
static HEAD_POSE_QUEUE: Mutex<VecDeque<(Duration, Pose)>> = Mutex::new(VecDeque::new());
static EVENT_LOOP_HANDLE: Mutex<Option<thread::JoinHandle<()>>> = Mutex::new(None);
static IDLE_INIT_HANDLE: Mutex<Option<thread::JoinHandle<()>>> = Mutex::new(None);
static FACTORY_INIT_DATA: Mutex<Option<FactoryInitData>> = Mutex::new(None);

struct FactoryInitData {
filesystem_layout: afs::Layout,
early_hmd_initialization: bool,
}

fn make_settings(negotiated: Option<&ServerNegotiatedStreamingConfig>) -> Settings {
let settings = alvr_server_core::settings();
Expand Down Expand Up @@ -239,7 +247,7 @@ fn make_settings(negotiated: Option<&ServerNegotiatedStreamingConfig>) -> Settin
}

fn spawn_event_loop(events_receiver: mpsc::Receiver<ServerCoreEvent>) {
thread::spawn(move || {
let handle = thread::spawn(move || {
if let Some(context) = &*SERVER_CORE_CONTEXT.read() {
context.start_connection();
}
Expand Down Expand Up @@ -500,10 +508,12 @@ fn spawn_event_loop(events_receiver: mpsc::Receiver<ServerCoreEvent>) {

unsafe { ShutdownOpenvrClient() };
});
*EVENT_LOOP_HANDLE.lock() = Some(handle);
}

#[unsafe(export_name = "DriverReadyIdle")]
extern "C" fn driver_ready_idle(set_default_chap: bool) {
thread::spawn(move || {
let handle = thread::spawn(move || {
unsafe { InitOpenvrClient() };

if set_default_chap {
Expand All @@ -513,10 +523,12 @@ extern "C" fn driver_ready_idle(set_default_chap: bool) {
}
}
});
*IDLE_INIT_HANDLE.lock() = Some(handle);
}

/// # Safety
/// `instance_ptr` is a valid pointer to a `TrackedDevice` instance
#[unsafe(export_name = "RegisterButtons")]
pub unsafe extern "C" fn register_buttons(instance_ptr: *mut c_void, device_id: u64) {
let mapped_device_id = if device_id == *HAND_TRACKER_LEFT_ID {
*HAND_LEFT_ID
Expand All @@ -537,6 +549,7 @@ pub unsafe extern "C" fn register_buttons(instance_ptr: *mut c_void, device_id:
}
}

#[unsafe(export_name = "HapticsSend")]
extern "C" fn send_haptics(device_id: u64, duration_s: f32, frequency: f32, amplitude: f32) {
if let Ok(duration) = Duration::try_from_secs_f32(duration_s)
&& let Some(context) = &*SERVER_CORE_CONTEXT.read()
Expand All @@ -550,6 +563,7 @@ extern "C" fn send_haptics(device_id: u64, duration_s: f32, frequency: f32, ampl
}
}

#[unsafe(export_name = "SetVideoConfigNals")]
extern "C" fn set_video_config_nals(buffer_ptr: *const u8, len: i32, codec: i32) {
let codec = if codec == 0 {
CodecType::H264
Expand All @@ -568,6 +582,7 @@ extern "C" fn set_video_config_nals(buffer_ptr: *const u8, len: i32, codec: i32)
}
}

#[unsafe(export_name = "VideoSend")]
extern "C" fn send_video(timestamp_ns: u64, buffer_ptr: *mut u8, len: i32, is_idr: bool) {
if let Some(context) = &*SERVER_CORE_CONTEXT.read() {
let timestamp = Duration::from_nanos(timestamp_ns);
Expand Down Expand Up @@ -599,6 +614,7 @@ extern "C" fn send_video(timestamp_ns: u64, buffer_ptr: *mut u8, len: i32, is_id
}
}

#[unsafe(export_name = "GetDynamicEncoderParams")]
extern "C" fn get_dynamic_encoder_params() -> FfiDynamicEncoderParams {
if let Some(context) = &*SERVER_CORE_CONTEXT.read()
&& let Some(params) = context.get_dynamic_encoder_params()
Expand All @@ -613,6 +629,7 @@ extern "C" fn get_dynamic_encoder_params() -> FfiDynamicEncoderParams {
}
}

#[unsafe(export_name = "ReportComposed")]
extern "C" fn report_composed(timestamp_ns: u64, offset_ns: u64) {
if let Some(context) = &*SERVER_CORE_CONTEXT.read() {
context.report_composed(
Expand All @@ -622,6 +639,7 @@ extern "C" fn report_composed(timestamp_ns: u64, offset_ns: u64) {
}
}

#[unsafe(export_name = "ReportPresent")]
extern "C" fn report_present(timestamp_ns: u64, offset_ns: u64) {
if let Some(context) = &*SERVER_CORE_CONTEXT.read() {
context.report_present(
Expand All @@ -631,6 +649,7 @@ extern "C" fn report_present(timestamp_ns: u64, offset_ns: u64) {
}
}

#[unsafe(export_name = "WaitForVSync")]
extern "C" fn wait_for_vsync() {
// Default 120Hz-ish wait if StatisticsManager isn't up.
// We use 120Hz-ish so that SteamVR doesn't accidentally get
Expand Down Expand Up @@ -659,8 +678,17 @@ extern "C" fn wait_for_vsync() {
}
}

#[unsafe(export_name = "ShutdownRuntime")]
pub extern "C" fn shutdown_driver() {
SERVER_CORE_CONTEXT.write().take();

// join driver threads so the dll isn't unloaded while they're still running
if let Some(handle) = EVENT_LOOP_HANDLE.lock().take() {
handle.join().ok();
}
if let Some(handle) = IDLE_INIT_HANDLE.lock().take() {
handle.join().ok();
}
}

/// This is the SteamVR/OpenVR entry point
Expand All @@ -684,8 +712,73 @@ pub unsafe extern "C" fn HmdDriverFactory(
.processes_by_name(OsStr::new(&afs::dashboard_fname()))
.collect::<Vec<_>>();

// When there is already a ALVR dashboard running, initialize the HMD device early to
// avoid buggy SteamVR behavior
// defer heavy init to InitializeRuntime() so a factory probe
// (e.g. steam.exe enumerating drivers) doesn't spawn threads
*FACTORY_INIT_DATA.lock() = Some(FactoryInitData {
filesystem_layout,
early_hmd_initialization: !dashboard_processes.is_empty(),
});

unsafe { CppOpenvrEntryPoint(interface_name, return_code) }
}

#[unsafe(export_name = "LogError")]
unsafe extern "C" fn log_error(string_ptr: *const c_char) {
unsafe { alvr_server_core::alvr_error(string_ptr) };
}

#[unsafe(export_name = "LogWarn")]
unsafe extern "C" fn log_warn(string_ptr: *const c_char) {
unsafe { alvr_server_core::alvr_warn(string_ptr) };
}

#[unsafe(export_name = "LogInfo")]
unsafe extern "C" fn log_info(string_ptr: *const c_char) {
unsafe { alvr_server_core::alvr_info(string_ptr) };
}

#[unsafe(export_name = "LogDebug")]
unsafe extern "C" fn log_debug(string_ptr: *const c_char) {
unsafe { alvr_server_core::alvr_dbg_server_impl(string_ptr) };
}

#[unsafe(export_name = "LogEncoder")]
unsafe extern "C" fn log_encoder(string_ptr: *const c_char) {
unsafe { alvr_server_core::alvr_dbg_encoder(string_ptr) };
}

#[unsafe(export_name = "LogPeriodically")]
unsafe extern "C" fn log_periodically(tag_ptr: *const c_char, string_ptr: *const c_char) {
unsafe { alvr_server_core::alvr_log_periodically(tag_ptr, string_ptr) };
}

#[unsafe(export_name = "PathStringToHash")]
unsafe extern "C" fn path_string_to_hash(path: *const c_char) -> u64 {
unsafe { alvr_server_core::alvr_path_to_id(path) }
}

#[unsafe(export_name = "GetSerialNumber")]
extern "C" fn get_serial_number(device_id: u64, out_str: *mut c_char) -> u64 {
props::get_serial_number(device_id, out_str)
}

#[unsafe(export_name = "SetOpenvrProps")]
extern "C" fn set_openvr_props(instance_ptr: *mut c_void, device_id: u64) {
props::set_device_openvr_props(instance_ptr, device_id)
}

// called from DriverProvider::Init()
#[unsafe(export_name = "InitializeRuntime")]
pub extern "C" fn initialize_runtime() {
static ONCE: Once = Once::new();
ONCE.call_once(move || {
ONCE.call_once(|| {
let Some(init_data) = FACTORY_INIT_DATA.lock().take() else {
return;
};
let filesystem_layout = init_data.filesystem_layout;

alvr_server_core::initialize_environment(filesystem_layout.clone());

let log_to_disk = alvr_server_core::settings().extra.logging.log_to_disk;
Expand All @@ -712,32 +805,7 @@ pub unsafe extern "C" fn HmdDriverFactory(
graphics::initialize_shaders();

unsafe {
LogError = Some(alvr_server_core::alvr_error);
LogWarn = Some(alvr_server_core::alvr_warn);
LogInfo = Some(alvr_server_core::alvr_info);
LogDebug = Some(alvr_server_core::alvr_dbg_server_impl);
LogEncoder = Some(alvr_server_core::alvr_dbg_encoder);
LogPeriodically = Some(alvr_server_core::alvr_log_periodically);
PathStringToHash = Some(alvr_server_core::alvr_path_to_id);
GetSerialNumber = Some(props::get_serial_number);
SetOpenvrProps = Some(props::set_device_openvr_props);
RegisterButtons = Some(register_buttons);
DriverReadyIdle = Some(driver_ready_idle);
HapticsSend = Some(send_haptics);
SetVideoConfigNals = Some(set_video_config_nals);
VideoSend = Some(send_video);
GetDynamicEncoderParams = Some(get_dynamic_encoder_params);
ReportComposed = Some(report_composed);
ReportPresent = Some(report_present);
WaitForVSync = Some(wait_for_vsync);
ShutdownRuntime = Some(shutdown_driver);

// When there is already a ALVR dashboard running, initialize the HMD device early to
// avoid buggy SteamVR behavior
// NB: we already bail out before if the dashboards don't belong to this streamer
let early_hmd_initialization = !dashboard_processes.is_empty();

CppInit(early_hmd_initialization, make_settings(None));
CppInit(init_data.early_hmd_initialization, make_settings(None));
}

let (context, events_receiver) = ServerCoreContext::new();
Expand All @@ -746,6 +814,4 @@ pub unsafe extern "C" fn HmdDriverFactory(

spawn_event_loop(events_receiver);
});

unsafe { CppOpenvrEntryPoint(interface_name, return_code) }
}
Loading