refactor: improve performance a lot

Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
Schmarni
2024-12-27 05:42:21 +01:00
parent 19367927a8
commit 2efdbec2ca
15 changed files with 328 additions and 72 deletions

View File

@@ -9,6 +9,11 @@ license = "GPLv2"
repository = "https://github.com/StardustXR/stardust-xr-server/" repository = "https://github.com/StardustXR/stardust-xr-server/"
homepage = "https://stardustxr.org" homepage = "https://stardustxr.org"
[patch.crates-io]
tracing-tracy = { git = "https://github.com/nagisa/rust_tracy_client", tag = "tracy-client-v0.17.6" }
tracy-client = { git = "https://github.com/nagisa/rust_tracy_client", tag = "tracy-client-v0.17.6" }
tracy-client-sys = { git = "https://github.com/nagisa/rust_tracy_client", tag = "tracy-client-v0.17.6" }
[workspace] [workspace]
members = ["codegen"] members = ["codegen"]
@@ -46,7 +51,12 @@ auto_link_exclude_list = [
] ]
[dependencies] [dependencies]
bevy = { version = "0.15", features = ["wayland", "mp3", "wav"] } bevy = { version = "0.15", features = [
"wayland",
"mp3",
"wav",
"trace_tracy",
] }
bevy_mod_xr = { git = "https://github.com/Schmarni-Dev/bevy_openxr", branch = "0.15rc" } bevy_mod_xr = { git = "https://github.com/Schmarni-Dev/bevy_openxr", branch = "0.15rc" }
bevy_mod_openxr = { git = "https://github.com/Schmarni-Dev/bevy_openxr", branch = "0.15rc" } bevy_mod_openxr = { git = "https://github.com/Schmarni-Dev/bevy_openxr", branch = "0.15rc" }
bevy_xr_utils = { git = "https://github.com/Schmarni-Dev/bevy_openxr", branch = "0.15rc" } bevy_xr_utils = { git = "https://github.com/Schmarni-Dev/bevy_openxr", branch = "0.15rc" }

View File

@@ -49,6 +49,93 @@ pub fn codegen_item_panel_protocol(_input: proc_macro::TokenStream) -> proc_macr
codegen_protocol(ITEM_PANEL_PROTOCOL) codegen_protocol(ITEM_PANEL_PROTOCOL)
} }
#[proc_macro]
pub fn codegen_id_to_name_functions(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let mut aspect_map: Vec<(u64, String)> = Vec::new();
let mut method_map: Vec<(u64, String)> = Vec::new();
let mut signal_map: Vec<(u64, String)> = Vec::new();
let protocols = [
ROOT_PROTOCOL,
NODE_PROTOCOL,
SPATIAL_PROTOCOL,
FIELD_PROTOCOL,
AUDIO_PROTOCOL,
DRAWABLE_PROTOCOL,
INPUT_PROTOCOL,
ITEM_PROTOCOL,
ITEM_CAMERA_PROTOCOL,
ITEM_PANEL_PROTOCOL,
];
for aspect in protocols
.into_iter()
.filter_map(|p| Protocol::parse(p).ok())
.flat_map(|v| v.aspects)
{
aspect_map.push((aspect.id, aspect.name));
for m in aspect.members.into_iter() {
match m._type {
MemberType::Signal => &mut signal_map,
MemberType::Method => &mut method_map,
}
.push((m.opcode, m.name));
}
}
let aspect_id_to_name = aspect_map
.iter()
.map(|(id, name)| {
quote! {
#id => #name,
}
})
.reduce(fold_tokens);
let aspect_id_to_name_fn = quote! {
pub const fn aspect_id_to_name(id: u64) -> &'static str {
match id {
#aspect_id_to_name
_ => "Unknown"
}
}
};
let method_id_to_name = method_map
.iter()
.map(|(id, name)| {
quote! {
#id => #name,
}
})
.reduce(fold_tokens);
let method_id_to_name_fn = quote! {
pub const fn method_id_to_name(id: u64) -> &'static str {
match id {
#method_id_to_name
_ => "Unknown"
}
}
};
let signal_id_to_name = signal_map
.iter()
.map(|(id, name)| {
quote! {
#id => #name,
}
})
.reduce(fold_tokens);
let signal_id_to_name_fn = quote! {
pub const fn signal_id_to_name(id: u64) -> &'static str {
match id {
#signal_id_to_name
_ => "Unknown"
}
}
};
quote! {
#aspect_id_to_name_fn
#method_id_to_name_fn
#signal_id_to_name_fn
}.into()
}
fn codegen_protocol(protocol: &'static str) -> proc_macro::TokenStream { fn codegen_protocol(protocol: &'static str) -> proc_macro::TokenStream {
let protocol = Protocol::parse(protocol).unwrap(); let protocol = Protocol::parse(protocol).unwrap();
let interface = protocol let interface = protocol

View File

@@ -71,9 +71,10 @@ fn yeet_entities(
query: Query<Entity, With<TemporaryEntity>>, query: Query<Entity, With<TemporaryEntity>>,
reader: Res<DestroyEntityReader>, reader: Res<DestroyEntityReader>,
) { ) {
query query.iter().for_each(|e| {
.iter() info!("yeeting component entities");
.for_each(|e| cmds.entity(e).despawn_recursive()); cmds.entity(e).despawn_recursive();
});
reader reader
.0 .0
.try_iter() .try_iter()

View File

@@ -7,3 +7,4 @@ pub mod registry;
pub mod resource; pub mod resource;
pub mod scenegraph; pub mod scenegraph;
pub mod task; pub mod task;
pub mod queued_mutex;

119
src/core/queued_mutex.rs Normal file
View File

@@ -0,0 +1,119 @@
use std::{
ops::{Deref, DerefMut},
sync::atomic::Ordering,
};
use parking_lot::{
lock_api::{MutexGuard, RwLockReadGuard},
Mutex, RawMutex, RawRwLock, RwLock,
};
use portable_atomic::AtomicU8;
pub struct QueuedMutex<T: Clone> {
mutable: Mutex<Option<T>>,
readers: AtomicU8,
inner: RwLock<T>,
}
impl<T: Clone + Default> Default for QueuedMutex<T> {
fn default() -> Self {
Self::new(T::default())
}
}
impl<T: Clone> QueuedMutex<T> {
pub const fn new(value: T) -> QueuedMutex<T> {
Self {
mutable: Mutex::new(None),
readers: AtomicU8::new(0),
inner: RwLock::new(value),
}
}
pub fn lock(&self) -> QueuedMutexLockGuard<'_, T> {
let mut guard = self.mutable.lock();
if guard.is_none() {
guard.replace(self.inner.read().clone());
}
QueuedMutexLockGuard { mutex: self, guard }
}
pub fn read_now(&self) -> QueuedMutexReadGuard<'_, T> {
let guard = self.inner.read();
self.readers.add(1, Ordering::Relaxed);
QueuedMutexReadGuard {
mutex: self,
guard: Some(guard),
}
}
}
pub struct QueuedMutexLockGuard<'a, T: Clone> {
mutex: &'a QueuedMutex<T>,
guard: MutexGuard<'a, RawMutex, Option<T>>,
}
impl<T: Clone> Deref for QueuedMutexLockGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self.guard.as_ref() {
Some(v) => v,
None => unreachable!(),
}
}
}
impl<T: Clone> DerefMut for QueuedMutexLockGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
match self.guard.as_mut() {
Some(v) => v,
None => unreachable!(),
}
}
}
impl<T: Clone> Drop for QueuedMutexLockGuard<'_, T> {
fn drop(&mut self) {
if self.mutex.readers.load(Ordering::Relaxed) != 0 {
return;
}
let mut write_lock = self.mutex.inner.write();
*write_lock = match self.guard.take() {
Some(v) => v,
None => unreachable!(),
}
}
}
pub struct QueuedMutexReadGuard<'a, T: Clone> {
mutex: &'a QueuedMutex<T>,
guard: Option<RwLockReadGuard<'a, RawRwLock, T>>,
}
impl<T: Clone> Deref for QueuedMutexReadGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self.guard.as_ref() {
Some(v) => v,
None => unreachable!(),
}
}
}
impl<T: Clone> Drop for QueuedMutexReadGuard<'_, T> {
fn drop(&mut self) {
drop(self.guard.take());
if self
.mutex
.readers
.fetch_sub(1, Ordering::Relaxed)
.wrapping_sub(1)
!= 0
{
return;
}
let mut write_lock = self.mutex.inner.write();
if let Some(v) = self.mutex.mutable.lock().take() {
*write_lock = v
}
}
}

View File

@@ -16,6 +16,8 @@ use std::sync::{Arc, Weak};
use tokio::sync::oneshot; use tokio::sync::oneshot;
use tracing::{debug, debug_span}; use tracing::{debug, debug_span};
stardust_xr_server_codegen::codegen_id_to_name_functions!();
#[derive(Default)] #[derive(Default)]
pub struct Scenegraph { pub struct Scenegraph {
pub(super) client: OnceCell<Weak<Client>>, pub(super) client: OnceCell<Weak<Client>>,
@@ -96,7 +98,15 @@ impl scenegraph::Scenegraph for Scenegraph {
let Some(client) = self.get_client() else { let Some(client) = self.get_client() else {
return Err(ScenegraphError::NodeNotFound); return Err(ScenegraphError::NodeNotFound);
}; };
debug_span!("Handle signal", aspect_id, node_id, method).in_scope(|| { debug_span!(
"Handle signal",
aspect_id,
aspect_name = aspect_id_to_name(aspect_id),
node_id,
method,
signal_name = signal_id_to_name(method)
)
.in_scope(|| {
self.get_node(node_id) self.get_node(node_id)
.ok_or(ScenegraphError::NodeNotFound)? .ok_or(ScenegraphError::NodeNotFound)?
.send_local_signal( .send_local_signal(
@@ -123,7 +133,14 @@ impl scenegraph::Scenegraph for Scenegraph {
let _ = response.send(Err(ScenegraphError::NodeNotFound)); let _ = response.send(Err(ScenegraphError::NodeNotFound));
return; return;
}; };
debug!(aspect_id, node_id, method, "Handle method"); debug!(
aspect_id,
aspect_name = aspect_id_to_name(aspect_id),
node_id,
method,
method_name = method_id_to_name(method),
"Handle method"
);
let Some(node) = self.get_node(node_id) else { let Some(node) = self.get_node(node_id) else {
let _ = response.send(Err(ScenegraphError::NodeNotFound)); let _ = response.send(Err(ScenegraphError::NodeNotFound));
return; return;

View File

@@ -42,6 +42,7 @@ use bevy_mod_xr::session::{XrFirst, XrPreDestroySession, XrSessionCreated, XrSes
use bevy_mod_xr::spaces::XrPrimaryReferenceSpace; use bevy_mod_xr::spaces::XrPrimaryReferenceSpace;
use bevy_plugin::{DbusConnection, InputUpdate, StardustBevyPlugin, StardustFirst}; use bevy_plugin::{DbusConnection, InputUpdate, StardustBevyPlugin, StardustFirst};
use clap::Parser; use clap::Parser;
use tracing::level_filters::LevelFilter;
use core::client::Client; use core::client::Client;
use core::task; use core::task;
use directories::ProjectDirs; use directories::ProjectDirs;
@@ -198,7 +199,7 @@ async fn setup() {
let cli_args = cli_args.clone(); let cli_args = cli_args.clone();
let dbus_connection = dbus_connection.clone(); let dbus_connection = dbus_connection.clone();
move || { move || {
stereokit_loop( bevy_loop(
sk_ready_notifier, sk_ready_notifier,
project_dirs, project_dirs,
cli_args, cli_args,
@@ -228,7 +229,7 @@ async fn setup() {
info!("Cleanly shut down Stardust"); info!("Cleanly shut down Stardust");
} }
fn stereokit_loop( fn bevy_loop(
sk_ready_notifier: Arc<Notify>, sk_ready_notifier: Arc<Notify>,
project_dirs: Option<ProjectDirs>, project_dirs: Option<ProjectDirs>,
args: CliArgs, args: CliArgs,
@@ -331,6 +332,7 @@ fn stereokit_loop(
cams.iter().for_each(|e| { cams.iter().for_each(|e| {
cmds.entity(e).remove::<Skybox>(); cmds.entity(e).remove::<Skybox>();
}); });
let _span = debug_span!("spawn");
cmds.insert_resource(ClearColor(Color::NONE)); cmds.insert_resource(ClearColor(Color::NONE));
} }
*last_hidden = env_hidden; *last_hidden = env_hidden;
@@ -392,7 +394,7 @@ fn stereokit_loop(
bevy_app.insert_resource(objects); bevy_app.insert_resource(objects);
let bevy_step = |world: &mut World| { fn bevy_step(world: &mut World) {
let _span = debug_span!("Bevy step"); let _span = debug_span!("Bevy step");
let _span = _span.enter(); let _span = _span.enter();
// camera::update(token); // camera::update(token);
@@ -428,6 +430,7 @@ fn stereokit_loop(
.run_system_cached(should_run_frame_loop) .run_system_cached(should_run_frame_loop)
.unwrap_or(true) .unwrap_or(true)
{ {
let _span = debug_span!("eeping").entered();
let mut waiter = world.remove_resource::<OxrFrameWaiter>().unwrap(); let mut waiter = world.remove_resource::<OxrFrameWaiter>().unwrap();
let state = waiter.wait().unwrap(); let state = waiter.wait().unwrap();
world.insert_resource(OxrFrameState(state)); world.insert_resource(OxrFrameState(state));

View File

@@ -163,18 +163,8 @@ impl Drop for Sound {
} }
} }
<<<<<<< HEAD
=======
<<<<<<< HEAD
create_interface!(AudioInterface);
>>>>>>> 0ec4c0f (refactor: get models fully working)
struct AudioInterface; struct AudioInterface;
impl InterfaceAspect for AudioInterface { impl InterfaceAspect for AudioInterface {
=======
pub fn update() {}
impl InterfaceAspect for Interface {
>>>>>>> 2f5c92d (refactor: get models fully working)
#[doc = "Create a sound node. WAV and MP3 are supported."] #[doc = "Create a sound node. WAV and MP3 are supported."]
fn create_sound( fn create_sound(
_node: Arc<Node>, _node: Arc<Node>,

View File

@@ -19,6 +19,7 @@ use glam::{Vec3, Vec3A};
use parking_lot::Mutex; use parking_lot::Mutex;
use prisma::Lerp; use prisma::Lerp;
use std::{collections::VecDeque, sync::Arc}; use std::{collections::VecDeque, sync::Arc};
use tracing::{debug_span, info};
static LINES_REGISTRY: Registry<Lines> = Registry::new(); static LINES_REGISTRY: Registry<Lines> = Registry::new();
@@ -27,6 +28,7 @@ pub struct Lines {
data: Mutex<Vec<Line>>, data: Mutex<Vec<Line>>,
} }
impl Lines { impl Lines {
#[tracing::instrument]
pub fn add_to(node: &Arc<Node>, lines: Vec<Line>) -> Result<Arc<Lines>> { pub fn add_to(node: &Arc<Node>, lines: Vec<Line>) -> Result<Arc<Lines>> {
*node *node
.get_aspect::<Spatial>() .get_aspect::<Spatial>()
@@ -34,15 +36,15 @@ impl Lines {
.bounding_box_calc .bounding_box_calc
.lock() = { .lock() = {
if let Ok(lines) = node.get_aspect::<Lines>() { if let Ok(lines) = node.get_aspect::<Lines>() {
Aabb3d::from_point_cloud( Aabb3d::from_point_cloud(Isometry3d::IDENTITY, {
Isometry3d::IDENTITY, let _span = debug_span!("add_to data lock").entered();
lines lines
.data .data
.lock() .lock()
.iter() .iter()
.flat_map(|line| line.points.iter()) .flat_map(|line| line.points.iter())
.map(|point| Vec3A::from(point.point)), .map(|point| Vec3A::from(point.point))
) })
} else { } else {
Aabb3d::new(Vec3A::ZERO, Vec3A::ZERO) Aabb3d::new(Vec3A::ZERO, Vec3A::ZERO)
} }
@@ -59,7 +61,9 @@ impl Lines {
fn draw(&self, mesh: &mut Mesh, view: &GlobalTransform) -> Transform { fn draw(&self, mesh: &mut Mesh, view: &GlobalTransform) -> Transform {
let transform_mat = self.space.global_transform(); let transform_mat = self.space.global_transform();
let _span = debug_span!("draw data lock").entered();
let data = self.data.lock().clone(); let data = self.data.lock().clone();
drop(_span);
let global_to_view = view.compute_matrix().inverse(); let global_to_view = view.compute_matrix().inverse();
let local_to_view = transform_mat.inverse() * global_to_view; let local_to_view = transform_mat.inverse() * global_to_view;
let view_to_local = local_to_view.inverse(); let view_to_local = local_to_view.inverse();
@@ -139,12 +143,11 @@ struct BevyLinePoint {
color: Srgba, color: Srgba,
thickness: f32, thickness: f32,
} }
impl Aspect for Lines {
const NAME: &'static str = "Lines";
}
impl LinesAspect for Lines { impl LinesAspect for Lines {
#[tracing::instrument]
fn set_lines(node: Arc<Node>, _calling_client: Arc<Client>, lines: Vec<Line>) -> Result<()> { fn set_lines(node: Arc<Node>, _calling_client: Arc<Client>, lines: Vec<Line>) -> Result<()> {
let lines_aspect = node.get_aspect::<Lines>()?; let lines_aspect = node.get_aspect::<Lines>()?;
let _span = debug_span!("set_lines data lock").entered();
*lines_aspect.data.lock() = lines; *lines_aspect.data.lock() = lines;
Ok(()) Ok(())
} }
@@ -167,9 +170,23 @@ pub fn draw_all(
..Default::default() ..Default::default()
}; };
let mat_handle = materials.add(material); let mat_handle = materials.add(material);
for lines in LINES_REGISTRY.get_valid_contents() { let _span = debug_span!("line registry get valid contents").entered();
let vec = LINES_REGISTRY.get_valid_contents();
drop(_span);
info!("len {}", vec.len());
for lines in vec {
let _span = debug_span!("outer if span").entered();
if let Some(node) = lines.space.node() { if let Some(node) = lines.space.node() {
if node.enabled() && !lines.data.lock().is_empty() { let _span = debug_span!("lines_data lock").entered();
let w = lines.data.lock().is_empty();
drop(_span);
let _span = debug_span!("node enabled check").entered();
let e = node.enabled();
drop(_span);
let _span = debug_span!("if span").entered();
if e && !w {
let _span = debug_span!("create line mesh").entered();
info!("spawning line");
// Does this rebuild the mesh every frame? yes, is this problematic? probably, // Does this rebuild the mesh every frame? yes, is this problematic? probably,
// would a shader work better? yes, do i care? not right now // would a shader work better? yes, do i care? not right now
let mut mesh = Mesh::new( let mut mesh = Mesh::new(

View File

@@ -336,18 +336,6 @@ fn create_model_parts_for_loaded_models(
*space.bounding_box_calc.lock() = Aabb3d::new(aabb.center, aabb.half_extents); *space.bounding_box_calc.lock() = Aabb3d::new(aabb.center, aabb.half_extents);
<<<<<<< HEAD
let model_part = Arc::new(ModelPart {
entity: MainWorldEntity(entity),
path: part_path,
space,
model: Arc::downgrade(model),
pending_material_parameters: Mutex::new(FxHashMap::default()),
pending_material_replacement: Mutex::new(None),
aliases: AliasList::default(),
});
node.add_aspect_raw(model_part.clone());
=======
let model_part = Arc::new(ModelPart { let model_part = Arc::new(ModelPart {
entity: OnceCell::from(entity), entity: OnceCell::from(entity),
path: part_path, path: part_path,
@@ -361,7 +349,6 @@ fn create_model_parts_for_loaded_models(
info!("fresh {}", &model_part.path); info!("fresh {}", &model_part.path);
model_part model_part
}); });
>>>>>>> 0ec4c0f (refactor: get models fully working)
parts.push(model_part.clone()); parts.push(model_part.clone());
} }
cmds.entity(entity).remove::<UnprocessedModel>(); cmds.entity(entity).remove::<UnprocessedModel>();
@@ -440,13 +427,6 @@ impl ModelAspect for Model {
part_path: String, part_path: String,
) -> Result<()> { ) -> Result<()> {
let model = node.get_aspect::<Model>()?; let model = node.get_aspect::<Model>()?;
<<<<<<< HEAD
let parts = model.parts.lock();
let Some(part) = parts.iter().find(|p| p.path == part_path) else {
let paths = parts.iter().map(|p| &p.path).collect::<Vec<_>>();
bail!("Couldn't find model part at path {part_path}, all available paths: {paths:?}",);
};
=======
let mut parts = model.parts.lock(); let mut parts = model.parts.lock();
let part = let part =
parts parts
@@ -476,7 +456,6 @@ impl ModelAspect for Model {
parts.push(model_part.clone()); parts.push(model_part.clone());
model_part model_part
}); });
>>>>>>> 0ec4c0f (refactor: get models fully working)
Alias::create_with_id( Alias::create_with_id(
&part.space.node().unwrap(), &part.space.node().unwrap(),
&calling_client, &calling_client,

View File

@@ -29,6 +29,7 @@ use glam::{vec3, Mat4, Vec2, Vec3};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use std::{ffi::OsStr, path::PathBuf, sync::Arc}; use std::{ffi::OsStr, path::PathBuf, sync::Arc};
use tracing::{info, info_span};
use super::{TextAspect, TextStyle}; use super::{TextAspect, TextStyle};
@@ -68,15 +69,14 @@ fn update_text(mut surface_query: Query<(&mut Transform)>) {
else { else {
continue; continue;
}; };
let data = text.data.lock(); // let data = text.data.lock();
*transform = Transform::from_matrix( *transform = Transform::from_matrix(
text.space.global_transform() text.space.global_transform(), // * Mat4::from_scale(vec3(
* Mat4::from_scale(vec3( // data.character_height,
data.character_height, // data.character_height,
data.character_height, // data.character_height,
data.character_height, // )),
)),
); );
} }
} }
@@ -90,7 +90,10 @@ fn spawn_text(
asset_server: Res<AssetServer>, asset_server: Res<AssetServer>,
) { ) {
for text in reader.try_iter() { for text in reader.try_iter() {
let _span = info_span!("spawning text").entered();
let _span2 = info_span!("text data lock").entered();
let data = text.data.lock(); let data = text.data.lock();
drop(_span2);
let size = Extent3d { let size = Extent3d {
width: (512.0 * data.bounds.as_ref().map(|v| v.bounds.x).unwrap_or(1.0)).floor() as u32, width: (512.0 * data.bounds.as_ref().map(|v| v.bounds.x).unwrap_or(1.0)).floor() as u32,
height: (512.0 * data.bounds.as_ref().map(|v| v.bounds.y).unwrap_or(1.0)).floor() height: (512.0 * data.bounds.as_ref().map(|v| v.bounds.y).unwrap_or(1.0)).floor()
@@ -168,6 +171,8 @@ fn spawn_text(
MeshMaterial3d(mats.add(DefaultMaterial { MeshMaterial3d(mats.add(DefaultMaterial {
base_color_texture: Some(image_handle), base_color_texture: Some(image_handle),
unlit: true, unlit: true,
// would Cutout be enough here?
alpha_mode: bevy::prelude::AlphaMode::Blend,
..default() ..default()
})), })),
)) ))

View File

@@ -8,6 +8,7 @@ mod tip;
pub use handler::*; pub use handler::*;
pub use method::*; pub use method::*;
use tracing::debug_span;
use super::fields::Field; use super::fields::Field;
use super::spatial::Spatial; use super::spatial::Spatial;
@@ -140,6 +141,7 @@ pub fn process_input() {
.clone() .clone()
// filter out methods without the handler in their handler order // filter out methods without the handler in their handler order
.filter(|a| { .filter(|a| {
let _span = debug_span!("handlder_order lock").entered();
a.handler_order a.handler_order
.lock() .lock()
.iter() .iter()

View File

@@ -10,6 +10,7 @@ pub mod spatial;
use self::alias::Alias; use self::alias::Alias;
use crate::core::client::Client; use crate::core::client::Client;
use crate::core::error::{Result, ServerError}; use crate::core::error::{Result, ServerError};
use crate::core::queued_mutex::QueuedMutex;
use crate::core::registry::Registry; use crate::core::registry::Registry;
use crate::core::scenegraph::MethodResponseSender; use crate::core::scenegraph::MethodResponseSender;
use parking_lot::Mutex; use parking_lot::Mutex;
@@ -25,6 +26,7 @@ use std::fmt::Debug;
use std::os::fd::OwnedFd; use std::os::fd::OwnedFd;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::vec::Vec; use std::vec::Vec;
use tracing::{debug_span, info};
#[derive(Default)] #[derive(Default)]
pub struct Message { pub struct Message {
@@ -125,17 +127,24 @@ impl Node {
)) ))
} }
pub fn enabled(&self) -> bool { pub fn enabled(&self) -> bool {
self.enabled.load(Ordering::Relaxed) let bool = {
&& if let Ok(spatial) = self.get_aspect::<Spatial>() { let _span = debug_span!("load atomic bool").entered();
spatial self.enabled.load(Ordering::Relaxed)
.global_transform() };
.to_scale_rotation_translation() bool && if let Ok(spatial) = {
.0 let _span = debug_span!("get spatial aspect").entered();
.length_squared() self.get_aspect::<Spatial>()
> 0.0 } {
} else { let _span = debug_span!("check if scale is zero").entered();
true spatial
} .global_transform()
.to_scale_rotation_translation()
.0
.length_squared()
> 0.0
} else {
true
}
} }
pub fn set_enabled(&self, enabled: bool) { pub fn set_enabled(&self, enabled: bool) {
self.enabled.store(enabled, Ordering::Relaxed) self.enabled.store(enabled, Ordering::Relaxed)
@@ -324,7 +333,7 @@ pub trait Aspect: Any + Send + Sync + 'static {
} }
#[derive(Default)] #[derive(Default)]
struct Aspects(Mutex<FxHashMap<u64, Arc<dyn Aspect>>>); struct Aspects(QueuedMutex<FxHashMap<u64, Arc<dyn Aspect>>>);
impl Aspects { impl Aspects {
fn add<A: AspectIdentifier>(&self, t: A) -> Arc<A> { fn add<A: AspectIdentifier>(&self, t: A) -> Arc<A> {
let aspect = Arc::new(t); let aspect = Arc::new(t);

View File

@@ -38,7 +38,7 @@ use openxr::{ActionSet, Posef};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use stardust_xr::values::Datamap; use stardust_xr::values::Datamap;
use std::{ops::Deref, sync::Arc}; use std::{ops::Deref, sync::Arc};
use tracing::error; use tracing::{debug_span, error};
use zbus::Connection; use zbus::Connection;
#[derive(Default, Debug, Deserialize, Serialize)] #[derive(Default, Debug, Deserialize, Serialize)]
@@ -236,11 +236,15 @@ fn spawn_controllers(
HandSide::Left => "left", HandSide::Left => "left",
HandSide::Right => "right", HandSide::Right => "right",
}; };
let _span = debug_span!("create SpatialRef").entered();
let (spatial, object_handle) = SpatialRef::create( let (spatial, object_handle) = SpatialRef::create(
&connection, &connection,
&("/org/stardustxr/Controller/".to_string() + side), &("/org/stardustxr/Controller/".to_string() + side),
); );
drop(_span);
let tip = InputDataType::Tip(Tip::default()); let tip = InputDataType::Tip(Tip::default());
let _span = debug_span!("create input method").entered();
let Ok(input) = (|| -> color_eyre::Result<Arc<InputMethod>> { let Ok(input) = (|| -> color_eyre::Result<Arc<InputMethod>> {
Ok(InputMethod::add_to( Ok(InputMethod::add_to(
&spatial.node().unwrap(), &spatial.node().unwrap(),
@@ -250,6 +254,8 @@ fn spawn_controllers(
})() else { })() else {
continue; continue;
}; };
drop(_span);
let _span = debug_span!("create actions").entered();
let actions = { let actions = {
let set = session let set = session
.instance() .instance()
@@ -275,6 +281,8 @@ fn spawn_controllers(
.unwrap(), .unwrap(),
} }
}; };
drop(_span);
let _span = debug_span!("spawn").entered();
cmds.spawn(( cmds.spawn((
SceneRoot(handle.clone()), SceneRoot(handle.clone()),
SkController { SkController {

View File

@@ -12,7 +12,10 @@ use crate::objects::{ObjectHandle, SpatialRef};
use crate::DefaultMaterial; use crate::DefaultMaterial;
use bevy::app::{Plugin, PostUpdate}; use bevy::app::{Plugin, PostUpdate};
use bevy::asset::{AssetServer, Assets, Handle}; use bevy::asset::{AssetServer, Assets, Handle};
use bevy::prelude::{Commands, Component, Entity, Query, Res, ResMut}; use bevy::prelude::{
Commands, Component, Entity, Gizmos, IntoSystemConfigs as _, Query, Res, ResMut,
};
use bevy::utils::default;
use bevy_mod_openxr::helper_traits::{ToQuat, ToVec3}; use bevy_mod_openxr::helper_traits::{ToQuat, ToVec3};
use bevy_mod_openxr::resources::OxrFrameState; use bevy_mod_openxr::resources::OxrFrameState;
use bevy_mod_openxr::session::OxrSession; use bevy_mod_openxr::session::OxrSession;
@@ -41,6 +44,13 @@ impl Plugin for StardustHandPlugin {
fn build(&self, app: &mut bevy::prelude::App) { fn build(&self, app: &mut bevy::prelude::App) {
app.add_systems(XrSessionCreated, create_hands); app.add_systems(XrSessionCreated, create_hands);
app.add_systems(PostUpdate, update_hands); app.add_systems(PostUpdate, update_hands);
app.add_systems(PostUpdate, draw_hand_gizmos.after(update_hands));
}
}
fn draw_hand_gizmos(mut gizmos: Gizmos, query: Query<&SkHand>) {
for hand in query.iter() {
gizmos.axes(hand.palm_spatial.global_transform(), 0.05);
} }
} }
@@ -87,8 +97,6 @@ fn update_hands(
update_joint(&mut finger.intermediate, joints[finger_index + 2]); update_joint(&mut finger.intermediate, joints[finger_index + 2]);
update_joint(&mut finger.proximal, joints[finger_index + 1]); update_joint(&mut finger.proximal, joints[finger_index + 1]);
update_joint(&mut finger.metacarpal, joints[finger_index]); update_joint(&mut finger.metacarpal, joints[finger_index]);
// Why?
finger.tip.radius = 0.0;
} }
update_joint(&mut hand_input.palm, joints[HandBone::Palm as usize]); update_joint(&mut hand_input.palm, joints[HandBone::Palm as usize]);
hand.palm_spatial hand.palm_spatial