From 0ae20b23c5a2eb9abe18e53d576d14ed2b9742c8 Mon Sep 17 00:00:00 2001 From: Nova Date: Fri, 9 Dec 2022 09:01:46 -0500 Subject: [PATCH] feat: initial openxr stuff feat: openxr system refactor: rename oxr_runtime to openxr_runtime refactor: make openxr methods/signals snake case feat(openxr): session feat(openxr): action, action set feat(openxr/action): suggested bindings --- Cargo.toml | 1 + src/core/client.rs | 4 +++ src/main.rs | 6 ++++ src/nodes/mod.rs | 8 +++++ src/openxr/action.rs | 76 ++++++++++++++++++++++++++++++++++++++++ src/openxr/action_set.rs | 60 +++++++++++++++++++++++++++++++ src/openxr/instance.rs | 47 +++++++++++++++++++++++++ src/openxr/mod.rs | 34 ++++++++++++++++++ src/openxr/session.rs | 34 ++++++++++++++++++ src/openxr/system.rs | 76 ++++++++++++++++++++++++++++++++++++++++ 10 files changed, 346 insertions(+) create mode 100644 src/openxr/action.rs create mode 100644 src/openxr/action_set.rs create mode 100644 src/openxr/instance.rs create mode 100644 src/openxr/mod.rs create mode 100644 src/openxr/session.rs create mode 100644 src/openxr/system.rs diff --git a/Cargo.toml b/Cargo.toml index 3397e1f..4dcc5d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ path = "src/main.rs" [features] default = ["wayland", "xwayland"] +openxr_runtime = [] wayland = ["dep:smithay", "dep:xkbcommon"] xwayland = ["smithay/xwayland"] profile_tokio = ["dep:console-subscriber", "tokio/tracing"] diff --git a/src/core/client.rs b/src/core/client.rs index 986fa9c..c4d5238 100644 --- a/src/core/client.rs +++ b/src/core/client.rs @@ -1,4 +1,6 @@ use super::scenegraph::Scenegraph; +#[cfg(feature = "oxr_runtime")] +use crate::openxr; use crate::{ core::{registry::OwnedRegistry, task}, nodes::{ @@ -108,6 +110,8 @@ impl Client { items::create_interface(&client)?; input::create_interface(&client)?; startup::create_interface(&client)?; + #[cfg(feature = "openxr_runtime")] + openxr::create_interface(&client); let pid_printable = pid .map(|pid| pid.to_string()) diff --git a/src/main.rs b/src/main.rs index 852f4c2..e6374e1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,8 @@ mod core; mod nodes; mod objects; +#[cfg(feature = "openxr_runtime")] +mod openxr; #[cfg(feature = "wayland")] mod wayland; @@ -31,6 +33,8 @@ use tracing::metadata::LevelFilter; use tracing::{debug_span, error, info}; use tracing_subscriber::{fmt, prelude::*, EnvFilter}; +pub static SK_INFO: OnceCell = OnceCell::new(); + #[derive(Parser)] #[clap(author, version, about, long_about = None)] struct CliArgs { @@ -114,6 +118,8 @@ fn main() { let _ = SK_MULTITHREAD.set(sk.multithreaded()); info!("Init StereoKit"); + SK_INFO.set(stereokit.system_info()).unwrap(); + sk.material_set_shader( sk.material_find("default/material_pbr").unwrap(), sk.shader_find("default/shader_pbr_clip").unwrap(), diff --git a/src/nodes/mod.rs b/src/nodes/mod.rs index 3bd719f..799b3a5 100644 --- a/src/nodes/mod.rs +++ b/src/nodes/mod.rs @@ -29,6 +29,8 @@ use tracing::{debug_span, instrument}; use crate::core::client::Client; use crate::core::registry::Registry; +#[cfg(feature = "openxr_runtime")] +use crate::openxr; use self::alias::Alias; use self::audio::Sound; @@ -101,6 +103,10 @@ pub struct Node { // Startup pub startup_settings: OnceCell>, + + // OpenXR + #[cfg(feature = "openxr_runtime")] + pub openxr_object: OnceCell, } impl Node { @@ -144,6 +150,8 @@ impl Node { item_acceptor: OnceCell::new(), item_ui: OnceCell::new(), sound: OnceCell::new(), + #[cfg(feature = "openxr_runtime")] + openxr_object: OnceCell::new(), startup_settings: OnceCell::new(), }; node.add_local_signal("set_enabled", Node::set_enabled_flex); diff --git a/src/openxr/action.rs b/src/openxr/action.rs new file mode 100644 index 0000000..bd88954 --- /dev/null +++ b/src/openxr/action.rs @@ -0,0 +1,76 @@ +use super::Object; +use crate::{core::client::Client, nodes::Node}; +use color_eyre::eyre::{bail, Result}; +use parking_lot::Mutex; +use rustc_hash::FxHashMap; +use serde::Deserialize; +use stardust_xr::schemas::flex::deserialize; +use std::sync::Arc; + +#[derive(Debug)] +pub struct Action { + // _info: InstanceInfo, + _localized_name: String, + suggested_bindings: Mutex>, +} +impl Action { + pub fn create_action_flex( + node: &Node, + _calling_client: Arc, + data: &[u8], + ) -> Result<()> { + let Object::ActionSet(action_set) = node.get_aspect("OpenXR interface", "Instance", |n| &n.openxr_object)? else { + bail!("Object not an instance") + }; + + #[derive(Debug, Deserialize)] + struct CreateActionInfo { + name: String, + localized_name: String, + } + let info: CreateActionInfo = dbg!(deserialize(data)?); + + let node = Node::create( + &node.get_client().unwrap(), + node.get_path(), + &info.name, + true, + ) + .add_to_scenegraph(); + node.add_local_signal("suggest_binding", Self::suggest_binding_flex); + + let action = Arc::new(Action { + _localized_name: info.localized_name, + suggested_bindings: Mutex::new(FxHashMap::default()), + }); + action_set + .actions + .lock() + .insert(info.name, Arc::downgrade(&action)); + node.openxr_object.set(Object::Action(action)).unwrap(); + + Ok(()) + } + pub fn suggest_binding_flex( + node: &Node, + _calling_client: Arc, + data: &[u8], + ) -> Result<()> { + let Object::Action(action) = node.get_aspect("OpenXR interface", "Action", |n| &n.openxr_object)? else { + bail!("Object not an action") + }; + + #[derive(Debug, Deserialize)] + struct SuggestBindingArgs { + interaction_profile: String, + binding: String, + } + let args: SuggestBindingArgs = dbg!(deserialize(data)?); + action + .suggested_bindings + .lock() + .insert(args.interaction_profile, args.binding); + + Ok(()) + } +} diff --git a/src/openxr/action_set.rs b/src/openxr/action_set.rs new file mode 100644 index 0000000..cfed47a --- /dev/null +++ b/src/openxr/action_set.rs @@ -0,0 +1,60 @@ +use super::{action::Action, Object}; +use crate::{core::client::Client, nodes::Node}; +use color_eyre::eyre::{bail, Result}; +use parking_lot::Mutex; +use rustc_hash::FxHashMap; +use serde::Deserialize; +use stardust_xr::schemas::flex::deserialize; +use std::sync::{Arc, Weak}; + +#[derive(Debug)] +pub struct ActionSet { + // _info: InstanceInfo, + _localized_name: String, + _priority: u32, + pub actions: Mutex>>, +} +impl ActionSet { + pub fn create_action_set_flex( + node: &Node, + _calling_client: Arc, + data: &[u8], + ) -> Result<()> { + let Object::Instance(instance) = node.get_aspect("OpenXR interface", "Instance", |n| &n.openxr_object)? else { + bail!("Object not an instance") + }; + let Some(instance) = instance.get() else { bail!("Instance not initialized") }; + + #[derive(Deserialize)] + struct CreateActionSetInfo { + name: String, + localized_name: String, + priority: u32, + } + let info: CreateActionSetInfo = deserialize(data)?; + + let node = Node::create( + &node.get_client().unwrap(), + "/openxr/action_set", + &info.name, + true, + ) + .add_to_scenegraph(); + node.add_local_signal("create_action", Action::create_action_flex); + + let action_set = Arc::new(ActionSet { + _localized_name: info.localized_name, + _priority: info.priority, + actions: Mutex::new(FxHashMap::default()), + }); + instance + .action_sets + .lock() + .insert(info.name, Arc::downgrade(&action_set)); + node.openxr_object + .set(Object::ActionSet(action_set)) + .unwrap(); + + Ok(()) + } +} diff --git a/src/openxr/instance.rs b/src/openxr/instance.rs new file mode 100644 index 0000000..25ec95c --- /dev/null +++ b/src/openxr/instance.rs @@ -0,0 +1,47 @@ +use super::{action_set::ActionSet, Object}; +use crate::{core::client::Client, nodes::Node}; +use color_eyre::eyre::{bail, eyre, Result}; +use parking_lot::Mutex; +use rustc_hash::FxHashMap; +use serde::Deserialize; +use stardust_xr::schemas::flex::deserialize; +use std::sync::{Arc, Weak}; + +#[derive(Debug, Deserialize)] +struct InstanceInfo { + _app_info: ApplicationInfo, + _extension_names: Vec, +} +#[derive(Debug, Deserialize)] +struct ApplicationInfo { + _app_name: String, + _app_version: u32, + _engine_name: String, + _engine_version: u32, + _api_version: u64, +} + +#[derive(Debug)] +pub struct Instance { + _info: InstanceInfo, + pub action_sets: Mutex>>, +} +impl Instance { + pub fn setup_instance_flex( + node: &Node, + _calling_client: Arc, + data: &[u8], + ) -> Result<()> { + let Object::Instance(instance) = node.get_aspect("OpenXR interface", "Instance", |n| &n.openxr_object)? else { + bail!("Object not an instance") + }; + let instance_info = Instance { + _info: deserialize(data)?, + action_sets: Mutex::new(FxHashMap::default()), + }; + dbg!(&instance_info); + instance + .set(Arc::new(instance_info)) + .map_err(|_| eyre!("Instance already set up")) + } +} diff --git a/src/openxr/mod.rs b/src/openxr/mod.rs new file mode 100644 index 0000000..e7696d1 --- /dev/null +++ b/src/openxr/mod.rs @@ -0,0 +1,34 @@ +mod action; +mod action_set; +mod instance; +mod session; +mod system; + +use self::{ + action::Action, action_set::ActionSet, instance::Instance, session::Session, system::System, +}; +use crate::{core::client::Client, nodes::Node}; +use once_cell::sync::OnceCell; +use std::sync::Arc; + +#[derive(Debug)] +pub enum Object { + Instance(OnceCell>), + System(System), + Session(Session), + ActionSet(Arc), + Action(Arc), +} + +pub fn create_interface(client: &Arc) { + let node = Node::create(client, "", "openxr", false); + node.add_local_signal("setup_instance", Instance::setup_instance_flex); + node.add_local_method("get_system", System::get_system_flex); + node.add_local_signal("create_action_set", ActionSet::create_action_set_flex); + + node.openxr_object + .set(Object::Instance(OnceCell::new())) + .unwrap(); + + node.add_to_scenegraph(); +} diff --git a/src/openxr/session.rs b/src/openxr/session.rs new file mode 100644 index 0000000..6132219 --- /dev/null +++ b/src/openxr/session.rs @@ -0,0 +1,34 @@ +use std::sync::Arc; + +use color_eyre::eyre::{bail, Result}; +use stardust_xr::schemas::flex::deserialize; + +use super::Object; +use crate::{core::client::Client, nodes::Node}; + +#[derive(Debug)] +pub struct Session { + // _info: InstanceInfo, +} +impl Session { + pub fn create_session_flex( + node: &Node, + _calling_client: Arc, + data: &[u8], + ) -> Result<()> { + let Object::System(_system) = node.get_aspect("OpenXR interface", "Instance", |n| &n.openxr_object)? else { + bail!("Object not a system") + }; + let node = Node::create( + &node.get_client().unwrap(), + node.get_path(), + deserialize(data)?, + true, + ) + .add_to_scenegraph(); + let session = Session {}; + node.openxr_object.set(Object::Session(session)).unwrap(); + + Ok(()) + } +} diff --git a/src/openxr/system.rs b/src/openxr/system.rs new file mode 100644 index 0000000..9861ca7 --- /dev/null +++ b/src/openxr/system.rs @@ -0,0 +1,76 @@ +use super::{session::Session, Object}; +use crate::{core::client::Client, nodes::Node, SK_INFO}; +use color_eyre::eyre::{bail, eyre, Result}; +use serde::Serialize; +use stardust_xr::schemas::flex::{deserialize, serialize}; +use std::sync::Arc; + +#[derive(Debug)] +pub enum System { + Handheld, + HeadMounted, +} +impl System { + pub fn from_raw(raw: u32) -> Option { + match raw { + 1 => Some(System::Handheld), + 2 => Some(System::HeadMounted), + _ => None, + } + } + + pub fn get_system_flex( + node: &Node, + _calling_client: Arc, + data: &[u8], + ) -> Result> { + // let Object::Instance(instance) = node.get_aspect("OpenXR interface", "Instance", |n| &n.openxr_object)? else { + // bail!("Object not an instance") + // }; + let system_type: u32 = deserialize(data)?; + let system = System::from_raw(system_type).ok_or_else(|| eyre!("No system exists!"))?; + let node = Node::create( + &node.get_client().unwrap(), + node.get_path(), + &format!("system{}", system_type), + true, + ) + .add_to_scenegraph(); + node.add_local_method("views", System::views_flex); + node.add_local_signal("create_session", Session::create_session_flex); + node.openxr_object.set(Object::System(system)).unwrap(); + + Ok(serialize(system_type)?) + } + + fn views_flex(_node: &Node, _calling_client: Arc, data: &[u8]) -> Result> { + let view_configuration_type: u64 = deserialize(data)?; + let view_count: u32 = match view_configuration_type { + 1 => 1, + 2 => 2, + 1000037000 => 4, + 1000054000 => 1, + _ => bail!("Invalid view config type"), + }; + + #[derive(Debug, Serialize)] + struct View { + recommended_image_rect_width: u32, + max_image_rect_width: u32, + recommended_image_rect_height: u32, + max_image_rect_height: u32, + } + let sk_info = SK_INFO.get().unwrap(); + + Ok(serialize( + (0..view_count) + .map(|_| View { + recommended_image_rect_width: sk_info.display_width, + max_image_rect_width: sk_info.display_width, + recommended_image_rect_height: sk_info.display_height, + max_image_rect_height: sk_info.display_height, + }) + .collect::>(), + )?) + } +}