diff --git a/Cargo.toml b/Cargo.toml index fe1779a..6df7354 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,8 +24,8 @@ path = "src/main.rs" default = [] wayland = ["dep:smithay", "dep:wayland-scanner", "dep:wayland-backend"] profile_tokio = ["dep:console-subscriber", "tokio/tracing"] -profile_app = ["dep:tracing-tracy", "bevy/trace_tracy"] -change_tracking = ["bevy/track_location"] +profile_app = ["dep:tracing-tracy", "bevy/trace_tracy", "bevy/trace"] +bevy_debugging = ["bevy/bevy_remote", "bevy/track_location"] [package.metadata.appimage] auto_link = true @@ -64,7 +64,7 @@ color-eyre = { version = "0.6.3", default-features = false } clap = { version = "4.5.13", features = ["derive"] } console-subscriber = { version = "0.4.0", optional = true } thiserror = "2.0.9" -tracing = "0.1.40" +tracing = { version = "0.1.40", features = ["release_max_level_warn"] } tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } tracing-tracy = { version = "0.11.1", optional = true } @@ -79,7 +79,7 @@ mint = "0.5.9" tokio = { version = "1.39.2", features = ["rt-multi-thread", "signal", "time"] } # bevy -bevy = { version = "0.16", features = ["wayland", "bevy_remote", "mp3", "wav"] } +bevy = { version = "0.16", features = ["wayland", "mp3", "wav"] } bevy_mod_xr = "0.3" bevy_mod_openxr = "0.3" # bevy_sk.git = "https://github.com/MalekiRe/bevy_sk" diff --git a/src/main.rs b/src/main.rs index 2e8fa7c..d7065d8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,8 +21,6 @@ use bevy::gizmos::GizmoPlugin; use bevy::gltf::GltfPlugin; use bevy::input::InputPlugin; use bevy::pbr::PbrPlugin; -use bevy::remote::RemotePlugin; -use bevy::remote::http::RemoteHttpPlugin; use bevy::render::{RenderDebugFlags, RenderPlugin}; use bevy::scene::ScenePlugin; use bevy::text::FontLoader; @@ -378,7 +376,10 @@ fn bevy_loop( app.add_schedule(pre_frame_wait); app.insert_resource(ClearColor(Color::BLACK.with_alpha(0.0))); app.insert_resource(ObjectRegistryRes(object_registry)); - app.add_plugins((RemotePlugin::default(), RemoteHttpPlugin::default())); + #[cfg(feature = "bevy_debugging")] + { + app.add_plugins((RemotePlugin::default(), RemoteHttpPlugin::default())); + } // the Stardust server plugins // infra plugins app.add_plugins(EntityHandlePlugin); diff --git a/src/nodes/drawable/lines.rs b/src/nodes/drawable/lines.rs index f8cc4a5..d70db93 100644 --- a/src/nodes/drawable/lines.rs +++ b/src/nodes/drawable/lines.rs @@ -27,7 +27,7 @@ pub struct LinesNodePlugin; impl Plugin for LinesNodePlugin { fn build(&self, app: &mut App) { - app.add_systems(Update, (build_line_mesh, update_visibillity).chain()); + app.add_systems(Update, (build_line_mesh/* , update_visibillity */).chain()); } } diff --git a/src/nodes/drawable/model.rs b/src/nodes/drawable/model.rs index 9f0a51d..5cfc082 100644 --- a/src/nodes/drawable/model.rs +++ b/src/nodes/drawable/model.rs @@ -31,7 +31,7 @@ impl Plugin for ModelNodePlugin { app.add_systems(Update, load_models); app.add_systems( PostUpdate, - (gen_model_parts, apply_materials, update_visibillity).chain(), + (gen_model_parts, apply_materials/* , update_visibillity */).chain(), ); } } diff --git a/src/nodes/drawable/text.rs b/src/nodes/drawable/text.rs index 17d2587..1fd6906 100644 --- a/src/nodes/drawable/text.rs +++ b/src/nodes/drawable/text.rs @@ -1,4 +1,5 @@ use crate::{ + BevyMaterial, core::{ bevy_channel::{BevyChannel, BevyChannelReader}, client::Client, @@ -9,10 +10,12 @@ use crate::{ resource::get_resource_file, }, nodes::{ - drawable::XAlign, spatial::{Spatial, SpatialNode}, Node - }, BevyMaterial, + Node, + drawable::XAlign, + spatial::{Spatial, SpatialNode}, + }, }; -use bevy::{platform::collections::HashMap, prelude::*}; +use bevy::{platform::collections::HashMap, prelude::*, render::mesh::MeshAabb}; use bevy_mesh_text_3d::{ Align, Attrs, MeshTextPlugin, Settings as FontSettings, generate_meshes, text_glyphs::TextGlyphs, @@ -40,25 +43,7 @@ impl Plugin for TextNodePlugin { SPAWN_TEXT.init(app); app.init_resource::(); - app.add_systems(Update, (spawn_text, update_visibillity).chain()); - } -} - -fn update_visibillity(mut cmds: Commands) { - for text in TEXT_REGISTRY.get_valid_contents().into_iter() { - let Some(entity) = text.entity.lock().as_deref().copied() else { - continue; - }; - match text.spatial.node().map(|n| n.enabled()).unwrap_or(false) { - true => { - cmds.entity(entity) - .insert_recursive::(Visibility::Visible); - } - false => { - cmds.entity(entity) - .insert_recursive::(Visibility::Hidden); - } - } + app.add_systems(Update, spawn_text); } } @@ -134,15 +119,25 @@ fn spawn_text( if let Some(db) = old_db { mem::swap(font_settings.font_system.db_mut(), db); } - let Ok(meshes) = char_meshes.inspect_err(|err| error!("unable to create text meshes: {err}")) + let Ok(char_meshes) = + char_meshes.inspect_err(|err| error!("unable to create text meshes: {err}")) else { continue; }; - let dist = meshes - .iter() - .fold(f32::MAX, |dist, v| dist.min(v.transform.translation.x)); + let dist = char_meshes.iter().fold(f32::MAX, |dist, v| { + dist.min( + v.transform.translation.x + - meshes + .get(&v.mesh) + .unwrap() + .compute_aabb() + .unwrap_or_default() + .half_extents + .x, + ) + }); // TODO: text align - let letters = meshes + let letters = char_meshes .into_iter() .map(|v| { cmds.spawn(( diff --git a/src/nodes/input/mod.rs b/src/nodes/input/mod.rs index 5ff119e..e1fe0f8 100644 --- a/src/nodes/input/mod.rs +++ b/src/nodes/input/mod.rs @@ -6,6 +6,8 @@ mod method; mod pointer; mod tip; +use bevy::tasks::ComputeTaskPool; +use bevy::tasks::ParallelSlice; pub use handler::*; pub use method::*; use tracing::debug_span; @@ -120,55 +122,60 @@ pub fn process_input() { }; node.enabled() }); - for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() { - let _span = debug_span!("handle input handler").entered(); - for method_alias in handler.method_aliases.get_aliases() { - method_alias.set_enabled(false); - } + INPUT_HANDLER_REGISTRY + .get_valid_contents() + .into_iter() + .par_splat_map(ComputeTaskPool::get(), None, |_, handlers| { + for handler in handlers { + let _span = debug_span!("handle input handler").entered(); + for method_alias in handler.method_aliases.get_aliases() { + method_alias.set_enabled(false); + } - let Some(handler_node) = handler.spatial.node() else { - continue; - }; - if !handler_node.enabled() { - continue; - } - if let Some(handler_field_node) = handler.field.spatial.node() { - if !handler_field_node.enabled() { - continue; + let Some(handler_node) = handler.spatial.node() else { + continue; + }; + if !handler_node.enabled() { + continue; + } + if let Some(handler_field_node) = handler.field.spatial.node() { + if !handler_field_node.enabled() { + continue; + } + }; + + let ser_span = debug_span!("serializing input").entered(); + let (methods, datas) = methods + .clone() + // filter out methods without the handler in their handler order + .filter(|a| { + a.handler_order + .lock() + .iter() + .any(|h| h.ptr_eq(&Arc::downgrade(&handler))) + }) + // filter out methods without the proper alias + .filter_map(|m| { + Some(( + handler + .method_aliases + .get_from_original_node(m.spatial.node.clone())?, + m, + )) + }) + // make sure the input method alias is enabled + .inspect(|(a, _)| { + a.set_enabled(true); + }) + // serialize the data + .map(|(a, m)| (a.clone(), m.serialize(a.get_id(), &handler))) + .unzip::<_, _, Vec<_>, Vec<_>>(); + drop(ser_span); + + let _span = debug_span!("client input").entered(); + let _ = input_handler_client::input(&handler_node, &methods, &datas); } - }; - - let ser_span = debug_span!("serializing input").entered(); - let (methods, datas) = methods - .clone() - // filter out methods without the handler in their handler order - .filter(|a| { - a.handler_order - .lock() - .iter() - .any(|h| h.ptr_eq(&Arc::downgrade(&handler))) - }) - // filter out methods without the proper alias - .filter_map(|m| { - Some(( - handler - .method_aliases - .get_from_original_node(m.spatial.node.clone())?, - m, - )) - }) - // make sure the input method alias is enabled - .inspect(|(a, _)| { - a.set_enabled(true); - }) - // serialize the data - .map(|(a, m)| (a.clone(), m.serialize(a.get_id(), &handler))) - .unzip::<_, _, Vec<_>, Vec<_>>(); - drop(ser_span); - - let _span = debug_span!("client input").entered(); - let _ = input_handler_client::input(&handler_node, &methods, &datas); - } + }); for method in methods { method.cull_capture_attempts(); } diff --git a/src/nodes/spatial/mod.rs b/src/nodes/spatial/mod.rs index 6eb08b4..99e2425 100644 --- a/src/nodes/spatial/mod.rs +++ b/src/nodes/spatial/mod.rs @@ -18,6 +18,7 @@ use mint::Vector3; use parking_lot::Mutex; use rustc_hash::FxHashMap; use std::fmt::Debug; +use std::sync::atomic::Ordering; use std::sync::{Arc, OnceLock, Weak}; use std::{f32, ptr}; @@ -32,17 +33,42 @@ impl Plugin for SpatialNodePlugin { } fn update_spatial_nodes( - mut query: Query<(&mut BevyTransform, &SpatialNode, Option<&ChildOf>)>, + mut query: Query<( + &mut BevyTransform, + &SpatialNode, + Option<&ChildOf>, + &mut Visibility, + )>, parent_query: Query<&GlobalTransform>, ) { query .par_iter_mut() - .for_each(|(mut transform, spatial_node, child_of)| { + .for_each(|(mut transform, spatial_node, child_of, mut vis)| { + let _span = debug_span!("updating spatial node").entered(); let Some(spatial) = spatial_node.0.upgrade() else { - // should we despawn the entity? return; }; - let mat4 = spatial.global_transform(); + if spatial + .node() + .is_some_and(|v| !v.enabled.load(Ordering::Relaxed)) + { + if !matches!(*vis, Visibility::Hidden) { + *vis = Visibility::Hidden; + } + return; + } + let mat4 = + debug_span!("getting global transform").in_scope(|| spatial.global_transform()); + let (scale, _, _) = mat4.to_scale_rotation_translation(); + match (*vis, scale == Vec3::ZERO) { + (Visibility::Inherited | Visibility::Visible, true) => { + *vis = Visibility::Hidden; + } + (Visibility::Hidden, false) => { + *vis = Visibility::Inherited; + } + _ => {} + } match child_of { Some(child_of) => { let Ok(parent) = parent_query.get(child_of.0) else { @@ -60,7 +86,7 @@ fn update_spatial_nodes( } #[derive(Clone, Component, Debug)] -#[require(BevyTransform)] +#[require(BevyTransform, Visibility)] pub struct SpatialNode(pub Weak); stardust_xr_server_codegen::codegen_spatial_protocol!(); diff --git a/src/objects/input/sk_controller.rs b/src/objects/input/sk_controller.rs index cd53201..0ed9104 100644 --- a/src/objects/input/sk_controller.rs +++ b/src/objects/input/sk_controller.rs @@ -39,6 +39,7 @@ use std::{ str::FromStr, sync::Arc, }; +use tracing::instrument; use zbus::Connection; pub struct ControllerPlugin; const CURSOR_MODEL_PATH: &str = "/tmp/stardust_server/models/cursor.glb"; @@ -152,9 +153,11 @@ fn update( controllers.right.set_enabled(false); return; }; - session - .sync_actions(&[ActiveActionSet::new(&actions.set)]) - .unwrap(); + debug_span!("sync actions").in_scope(|| { + session + .sync_actions(&[ActiveActionSet::new(&actions.set)]) + .unwrap(); + }); let time = state.predicted_display_time; // stupid bevy gltf loading issue (rotated 180 degrees on the y axis) controllers @@ -299,6 +302,7 @@ impl SkController { space: None, }) } + #[instrument(level = "debug", skip(self))] pub fn set_enabled(&self, enabled: bool) { if let Some(node) = self.input.spatial.node() { node.set_enabled(enabled); @@ -321,6 +325,7 @@ impl SkController { let Some(space) = self.space.as_ref() else { return; }; + let _span = debug_span!("locate space").entered(); let Ok(location) = session .locate_space(space, &ref_space, time) .inspect_err(|err| error!("error while locating controller space: {err}")) @@ -333,6 +338,7 @@ impl SkController { | SpaceLocationFlags::ORIENTATION_VALID | SpaceLocationFlags::ORIENTATION_TRACKED, ); + drop(_span); self.set_enabled(enabled); if enabled { let world_transform = Mat4::from(Affine3A::from(location.pose.to_xr_pose())); @@ -377,6 +383,7 @@ impl SkController { .map(|v| v.current_state) .unwrap_or_default() } + let _span = debug_span!("apply datamap").entered(); self.datamap = ControllerDatamap { select: get(session, path, &actions.trigger), middle: get(session, path, &actions.stick_click) as u32 as f32, @@ -385,6 +392,7 @@ impl SkController { scroll: get(session, path, &actions.stick).to_vec2(), }; *self.input.datamap.lock() = Datamap::from_typed(&self.datamap).unwrap(); + drop(_span); let distance_calculator = |space: &Arc, _data: &InputDataType, field: &Field| { Some(field.distance(space, [0.0; 3].into()).abs())