diff --git a/crates/re_data_store/src/store_read.rs b/crates/re_data_store/src/store_read.rs index 9de8a251aa51..4d915d75b99e 100644 --- a/crates/re_data_store/src/store_read.rs +++ b/crates/re_data_store/src/store_read.rs @@ -52,7 +52,7 @@ impl LatestAtQuery { /// interval. /// /// Motivation: all data is considered alive until the next logging to the same component path. -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct RangeQuery { pub timeline: Timeline, pub range: TimeRange, diff --git a/crates/re_query_cache/benches/latest_at.rs b/crates/re_query_cache/benches/latest_at.rs index 7eccfae8f821..a856988a3185 100644 --- a/crates/re_query_cache/benches/latest_at.rs +++ b/crates/re_query_cache/benches/latest_at.rs @@ -279,6 +279,7 @@ fn query_and_visit_points(store: &DataStore, paths: &[EntityPath]) -> Vec( + true, // cached? store, &query.clone().into(), path, @@ -309,6 +310,7 @@ fn query_and_visit_strings(store: &DataStore, paths: &[EntityPath]) -> Vec( + true, // cached? store, &query.clone().into(), path, diff --git a/crates/re_query_cache/src/cache.rs b/crates/re_query_cache/src/cache.rs index 6d09b51ce1c4..c36e3e285a75 100644 --- a/crates/re_query_cache/src/cache.rs +++ b/crates/re_query_cache/src/cache.rs @@ -9,7 +9,7 @@ use parking_lot::RwLock; use paste::paste; use seq_macro::seq; -use re_data_store::LatestAtQuery; +use re_data_store::{LatestAtQuery, RangeQuery}; use re_log_types::{EntityPath, RowId, StoreId, TimeInt, Timeline}; use re_query::ArchetypeView; use re_types_core::{components::InstanceKey, Archetype, ArchetypeName, Component, ComponentName}; @@ -21,17 +21,27 @@ use crate::{ErasedFlatVecDeque, FlatVecDeque}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum AnyQuery { LatestAt(LatestAtQuery), - // TODO(cmc): range queries support. + Range(RangeQuery), } impl From for AnyQuery { + #[inline] fn from(query: LatestAtQuery) -> Self { Self::LatestAt(query) } } +impl From for AnyQuery { + #[inline] + fn from(query: RangeQuery) -> Self { + Self::Range(query) + } +} + // --- +/// All primary caches (all stores, all entities, everything). +// // TODO(cmc): Centralize and harmonize all caches (query, jpeg, mesh). static CACHES: Lazy = Lazy::new(Caches::default); diff --git a/crates/re_query_cache/src/query.rs b/crates/re_query_cache/src/query.rs index 819ceae6157a..bf0387dd286d 100644 --- a/crates/re_query_cache/src/query.rs +++ b/crates/re_query_cache/src/query.rs @@ -1,7 +1,7 @@ use paste::paste; use seq_macro::seq; -use re_data_store::{DataStore, LatestAtQuery, TimeInt, Timeline}; +use re_data_store::{DataStore, LatestAtQuery, RangeQuery, TimeInt, TimeRange, Timeline}; use re_entity_db::{ExtraQueryHistory, VisibleHistory}; use re_log_types::{EntityPath, RowId}; use re_query::query_archetype; @@ -55,6 +55,7 @@ impl<'a, C> MaybeCachedComponentData<'a, C> { /// Alias for [`query_archetype_pov1_comp0`]. #[inline] pub fn query_archetype_pov1<'a, A, R1, F>( + cached: bool, store: &'a DataStore, query: &AnyQuery, entity_path: &'a EntityPath, @@ -71,7 +72,7 @@ where ), ), { - query_archetype_pov1_comp0::(store, query, entity_path, f) + query_archetype_pov1_comp0::(cached, store, query, entity_path, f) } macro_rules! impl_query_archetype { @@ -80,6 +81,7 @@ macro_rules! impl_query_archetype { #[doc = "(combined) for `" $N "` point-of-view components and `" $M "` optional components."] #[allow(non_snake_case)] pub fn []<'a, A, $($pov,)+ $($comp,)* F>( + cached: bool, store: &'a DataStore, query: &AnyQuery, entity_path: &'a EntityPath, @@ -101,11 +103,11 @@ macro_rules! impl_query_archetype { // NOTE: not `profile_function!` because we want them merged together. re_tracing::profile_scope!( "query_archetype", - format!("arch={} pov={} comp={}", A::name(), $N, $M) + format!("cached={cached} arch={} pov={} comp={}", A::name(), $N, $M) ); let mut latest_at_callback = |query: &LatestAtQuery, cache: &mut crate::LatestAtCache| { - re_tracing::profile_scope!("latest_at"); + re_tracing::profile_scope!("latest_at", format!("{query:?}")); let bucket = cache.entry(query.at).or_default(); // NOTE: Implicitly dropping the write guard here: the LatestAtCache is free once again! @@ -154,6 +156,47 @@ macro_rules! impl_query_archetype { }; match &query { + // TODO(cmc): cached range support + AnyQuery::Range(query) => { + re_tracing::profile_scope!("range", format!("{query:?}")); + + // NOTE: `+ 2` because we always grab the indicator component as well as the + // instance keys. + let arch_views = ::re_query::range_archetype::(store, query, entity_path); + + for (time, arch_view) in arch_views { + let data = ( + // TODO(cmc): `ArchetypeView` should indicate its pov time. + (time.unwrap_or(TimeInt::MIN), arch_view.primary_row_id()), + MaybeCachedComponentData::Raw(arch_view.iter_instance_keys().collect()), + $(MaybeCachedComponentData::Raw(arch_view.iter_required_component::<$pov>()?.collect()),)+ + $(MaybeCachedComponentData::Raw(arch_view.iter_optional_component::<$comp>()?.collect()),)* + ); + + f(data); + } + + Ok(()) + } + + AnyQuery::LatestAt(query) if !cached => { + re_tracing::profile_scope!("latest_at", format!("{query:?}")); + + let arch_view = ::re_query::query_archetype::(store, query, entity_path)?; + + let data = ( + // TODO(cmc): `ArchetypeView` should indicate its pov time. + (TimeInt::MIN, arch_view.primary_row_id()), + MaybeCachedComponentData::Raw(arch_view.iter_instance_keys().collect()), + $(MaybeCachedComponentData::Raw(arch_view.iter_required_component::<$pov>()?.collect()),)+ + $(MaybeCachedComponentData::Raw(arch_view.iter_optional_component::<$comp>()?.collect()),)* + ); + + f(data); + + Ok(()) + } + AnyQuery::LatestAt(query) => { Caches::with_latest_at::( store.id().clone(), @@ -187,6 +230,7 @@ seq!(NUM_COMP in 0..10 { /// Alias for [`query_archetype_with_history_pov1_comp0`]. #[inline] pub fn query_archetype_with_history_pov1<'a, A, R1, F>( + cached: bool, store: &'a DataStore, timeline: &'a Timeline, time: &'a TimeInt, @@ -205,7 +249,9 @@ where ), ), { - query_archetype_with_history_pov1_comp0::(store, timeline, time, history, ent_path, f) + query_archetype_with_history_pov1_comp0::( + cached, store, timeline, time, history, ent_path, f, + ) } /// Generates a function to cache a (potentially historical) query with N point-of-view components and M @@ -215,6 +261,7 @@ macro_rules! impl_query_archetype_with_history { #[doc = "Cached implementation of [`re_query::query_archetype_with_history`] for `" $N "` point-of-view"] #[doc = "components and `" $M "` optional components."] pub fn []<'a, A, $($pov,)+ $($comp,)* F>( + cached: bool, store: &'a DataStore, timeline: &'a Timeline, time: &'a TimeInt, @@ -238,7 +285,7 @@ macro_rules! impl_query_archetype_with_history { // NOTE: not `profile_function!` because we want them merged together. re_tracing::profile_scope!( "query_archetype_with_history", - format!("arch={} pov={} comp={}", A::name(), $N, $M) + format!("cached={cached} arch={} pov={} comp={}", A::name(), $N, $M) ); let visible_history = match timeline.typ() { @@ -249,13 +296,23 @@ macro_rules! impl_query_archetype_with_history { if !history.enabled || visible_history == VisibleHistory::OFF { let query = LatestAtQuery::new(*timeline, *time); $crate::[]::( + cached, store, &query.clone().into(), ent_path, f, ) } else { - unimplemented!("TODO(cmc): range support"); + let min_time = visible_history.from(*time); + let max_time = visible_history.to(*time); + let query = RangeQuery::new(*timeline, TimeRange::new(min_time, max_time)); + $crate::[]::( + cached, + store, + &query.clone().into(), + ent_path, + f, + ) } } } }; diff --git a/crates/re_query_cache/tests/latest_at.rs b/crates/re_query_cache/tests/latest_at.rs index bc0f259503ea..3fa32519f6c5 100644 --- a/crates/re_query_cache/tests/latest_at.rs +++ b/crates/re_query_cache/tests/latest_at.rs @@ -218,6 +218,7 @@ fn query_and_compare(store: &DataStore, query: &LatestAtQuery, ent_path: &Entity let mut got_colors = Vec::new(); query_archetype_pov1_comp1::( + true, // cached? store, &query.clone().into(), ent_path, diff --git a/crates/re_viewer/src/ui/rerun_menu.rs b/crates/re_viewer/src/ui/rerun_menu.rs index f166f52100b6..fb939226b8f5 100644 --- a/crates/re_viewer/src/ui/rerun_menu.rs +++ b/crates/re_viewer/src/ui/rerun_menu.rs @@ -291,6 +291,14 @@ fn experimental_feature_ui( - Add the 'Add space view/container' modal, accessible from the selection panel.", ); + re_ui + .checkbox( + ui, + &mut app_options.experimental_primary_caching_point_clouds, + "Primary caching: 2D & 3D point clouds", + ) + .on_hover_text("Toggle primary caching for the 2D & 3D point cloud space views."); + re_ui .checkbox( ui, diff --git a/crates/re_viewer_context/src/app_options.rs b/crates/re_viewer_context/src/app_options.rs index 24f13c3bffca..acc1b5d48644 100644 --- a/crates/re_viewer_context/src/app_options.rs +++ b/crates/re_viewer_context/src/app_options.rs @@ -25,6 +25,9 @@ pub struct AppOptions { /// Enable the experimental support for the container addition workflow. pub experimental_additive_workflow: bool, + /// Toggle primary caching for the 2D & 3D point cloud space views. + pub experimental_primary_caching_point_clouds: bool, + /// Displays an overlay for debugging picking. pub show_picking_debug_overlay: bool, @@ -54,6 +57,10 @@ impl Default for AppOptions { experimental_additive_workflow: cfg!(debug_assertions), + // TODO(cmc): default to true for debug/rerun-workspace once minimal features have been + // merged in. + experimental_primary_caching_point_clouds: false, + show_picking_debug_overlay: false, show_blueprint_in_timeline: false, diff --git a/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs b/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs index 3f131cad1929..c7a6a1f43ea3 100644 --- a/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs +++ b/examples/rust/custom_space_view/src/color_coordinates_visualizer_system.rs @@ -60,7 +60,7 @@ impl VisualizerSystem for InstanceColorSystem { ) -> Result, SpaceViewSystemExecutionError> { // For each entity in the space view that should be displayed with the `InstanceColorSystem`… for data_result in query.iter_visible_data_results(Self::identifier()) { - // ...gather all colors and their instance ids. + // …gather all colors and their instance ids. if let Ok(arch_view) = query_archetype::( ctx.entity_db.store(), &ctx.current_query(),