Skip to content

Add analytics for wgpu backend and whether the viewer runs in WSL #8612

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 9, 2025
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
3 changes: 1 addition & 2 deletions crates/top/rerun/src/commands/entrypoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,8 +845,7 @@ fn run_impl(
_build_info,
&call_source.app_env(),
startup_options,
cc.egui_ctx.clone(),
cc.storage,
cc,
);
for rx in rxs {
app.add_receiver(rx);
Expand Down
45 changes: 43 additions & 2 deletions crates/utils/re_analytics/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,43 @@ pub struct ViewerStarted {

/// The environment in which the viewer is running.
pub app_env: &'static str,

/// Sparse information about the runtime environment the viewer is running in.
pub runtime_info: ViewerRuntimeInformation,
}

/// Some sparse information about the runtime environment the viewer is running in.
pub struct ViewerRuntimeInformation {
/// Whether the viewer is started directly from within Windows Subsystem for Linux (WSL).
pub is_wsl: bool,

/// The wgpu graphics backend used by the viewer.
///
/// For possible values see [`wgpu::Backend`](https://docs.rs/wgpu/latest/wgpu/enum.Backend.html).
pub graphics_adapter_backend: String,

/// The device tier `re_renderer` identified for the graphics adapter.
///
/// For possible values see [`re_renderer::config::DeviceTier`](https://docs.rs/re_renderer/latest/re_renderer/config/enum.DeviceTier.html).
/// This is a very rough indication of the capabilities of the graphics adapter.
/// We do not want to send details graphics driver/capability information here since
/// it's too detailed (could be used for fingerprinting which we don't want) and not as useful
/// anyways since it's hard to learn about the typically identified capabilities.
pub re_renderer_device_tier: String,
}

impl Properties for ViewerRuntimeInformation {
fn serialize(self, event: &mut AnalyticsEvent) {
let Self {
is_wsl,
graphics_adapter_backend,
re_renderer_device_tier,
} = self;

event.insert("is_wsl", is_wsl);
event.insert("graphics_adapter_backend", graphics_adapter_backend);
event.insert("re_renderer_device_tier", re_renderer_device_tier);
}
}

/// Sent when a new recording is opened.
Expand Down Expand Up @@ -202,11 +239,15 @@ fn add_sanitized_url_properties(event: &mut AnalyticsEvent, url: Option<String>)

impl Properties for ViewerStarted {
fn serialize(self, event: &mut AnalyticsEvent) {
let Self { url, app_env } = self;
let Self {
url,
app_env,
runtime_info,
} = self;

event.insert("app_env", app_env);

add_sanitized_url_properties(event, url);
runtime_info.serialize(event);
}
}

Expand Down
30 changes: 20 additions & 10 deletions crates/viewer/re_renderer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@
/// See also `global_bindings.wgsl`
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DeviceTier {
/// Limited feature support as provided by WebGL and typically only by GLES2/OpenGL3(ish).
/// Limited feature support as provided by WebGL and some OpenGL drivers.
///
/// On desktop this happens typically with GLES 2 & OpenGL 3.x, as well as some OpenGL 4.x drivers
/// with lack of key rendering abilities.
///
/// Note that we do not distinguish between WebGL & native GL here,
/// instead, we go with the lowest common denominator.
/// In theory this path can also be hit on Vulkan & Metal drivers, but this is exceedingly rare.
Gles = 0,
Limited = 0,

/// Full support of WebGPU spec without additional feature requirements.
///
Expand All @@ -27,11 +28,20 @@ pub enum DeviceTier {
//HighEnd
}

impl std::fmt::Display for DeviceTier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Limited => "limited",
Self::FullWebGpuSupport => "full_webgpu_support",
})
}
}

impl DeviceTier {
/// Whether the current device tier supports sampling from textures with a sample count higher than 1.
pub fn support_sampling_msaa_texture(&self) -> bool {
match self {
Self::Gles => false,
Self::Limited => false,
Self::FullWebGpuSupport => true,
}
}
Expand All @@ -41,7 +51,7 @@ impl DeviceTier {
/// If this returns false, we first have to create a copy of the depth buffer by rendering depth to a different texture.
pub fn support_depth_readback(&self) -> bool {
match self {
Self::Gles => false,
Self::Limited => false,
Self::FullWebGpuSupport => true,
}
}
Expand All @@ -50,7 +60,7 @@ impl DeviceTier {
match self {
// TODO(wgpu#3583): Incorrectly reported by wgpu right now.
// GLES2 does not support BGRA textures!
Self::Gles => false,
Self::Limited => false,
Self::FullWebGpuSupport => true,
}
}
Expand All @@ -59,7 +69,7 @@ impl DeviceTier {
pub fn required_downlevel_capabilities(&self) -> wgpu::DownlevelCapabilities {
wgpu::DownlevelCapabilities {
flags: match self {
Self::Gles => wgpu::DownlevelFlags::empty(),
Self::Limited => wgpu::DownlevelFlags::empty(),
// Require fully WebGPU compliance for the native tier.
Self::FullWebGpuSupport => wgpu::DownlevelFlags::all(),
},
Expand Down Expand Up @@ -182,7 +192,7 @@ impl DeviceCaps {
// We pass the WebGPU min-spec!
DeviceTier::FullWebGpuSupport
} else {
DeviceTier::Gles
DeviceTier::Limited
};

let backend_type = match adapter.get_info().backend {
Expand Down Expand Up @@ -220,7 +230,7 @@ impl DeviceCaps {
caps.tier
.check_required_downlevel_capabilities(&adapter.get_downlevel_capabilities())?;

if caps.tier == DeviceTier::Gles {
if caps.tier == DeviceTier::Limited {
// Check texture format support. If `WEBGPU_TEXTURE_FORMAT_SUPPORT` is enabled, we're generally fine.
// This is an implicit requirement for the WebGPU tier and above.
if !adapter
Expand Down
6 changes: 4 additions & 2 deletions crates/viewer/re_renderer/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use type_map::concurrent::{self, TypeMap};

use crate::{
allocator::{CpuWriteGpuReadBelt, GpuReadbackBelt},
config::{DeviceCaps, DeviceTier},
config::{DeviceCaps, WgpuBackendType},
error_handling::{ErrorTracker, WgpuErrorScope},
global_bindings::GlobalBindings,
renderer::Renderer,
Expand Down Expand Up @@ -236,7 +236,9 @@ impl RenderContext {
// knowing that we're not _actually_ blocking.
//
// For more details check https://github.com/gfx-rs/wgpu/issues/3601
if cfg!(target_arch = "wasm32") && self.device_caps.tier == DeviceTier::Gles {
if cfg!(target_arch = "wasm32")
&& self.device_caps.backend_type == WgpuBackendType::WgpuCore
{
self.device.poll(wgpu::Maintain::Wait);
return;
}
Expand Down
30 changes: 24 additions & 6 deletions crates/viewer/re_viewer/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,7 @@ impl App {
build_info: re_build_info::BuildInfo,
app_env: &crate::AppEnvironment,
startup_options: StartupOptions,
egui_ctx: egui::Context,
storage: Option<&dyn eframe::Storage>,
creation_context: &eframe::CreationContext<'_>,
) -> Self {
re_tracing::profile_function!();

Expand All @@ -246,7 +245,7 @@ impl App {
}

let mut state: AppState = if startup_options.persist_state {
storage
creation_context.storage
.and_then(|storage| {
// This re-implements: `eframe::get_value` so we can customize the warning message.
// TODO(#2849): More thorough error-handling.
Expand Down Expand Up @@ -283,7 +282,7 @@ impl App {

#[cfg(not(target_arch = "wasm32"))]
if let Some(screenshot_path) = startup_options.screenshot_to_path_then_quit.clone() {
screenshotter.screenshot_to_path_then_quit(&egui_ctx, screenshot_path);
screenshotter.screenshot_to_path_then_quit(&creation_context.egui_ctx, screenshot_path);
}

let (command_sender, command_receiver) = command_channel();
Expand All @@ -296,7 +295,26 @@ impl App {
.checked_sub(web_time::Duration::from_secs(1_000_000_000))
.unwrap_or(web_time::Instant::now());

analytics.on_viewer_started(build_info);
let (adapter_backend, device_tier) = creation_context.wgpu_render_state.as_ref().map_or(
(
wgpu::Backend::Empty,
re_renderer::config::DeviceTier::Limited,
),
|render_state| {
let egui_renderer = render_state.renderer.read();
let render_ctx = egui_renderer
.callback_resources
.get::<re_renderer::RenderContext>();

(
render_state.adapter.get_info().backend,
render_ctx.map_or(re_renderer::config::DeviceTier::Limited, |ctx| {
ctx.device_caps().tier
}),
)
},
);
analytics.on_viewer_started(build_info, adapter_backend, device_tier);

let panel_state_overrides = startup_options.panel_state_overrides;

Expand All @@ -313,7 +331,7 @@ impl App {
startup_options,
start_time: web_time::Instant::now(),
ram_limit_warner: re_memory::RamLimitWarner::warn_at_fraction_of_max(0.75),
egui_ctx,
egui_ctx: creation_context.egui_ctx.clone(),
screenshotter,

#[cfg(target_arch = "wasm32")]
Expand Down
10 changes: 2 additions & 8 deletions crates/viewer/re_viewer/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,8 @@ pub fn run_native_viewer_with_messages(
run_native_app(
main_thread_token,
Box::new(move |cc| {
let mut app = crate::App::new(
main_thread_token,
build_info,
&app_env,
startup_options,
cc.egui_ctx.clone(),
cc.storage,
);
let mut app =
crate::App::new(main_thread_token, build_info, &app_env, startup_options, cc);
app.add_receiver(rx);
Box::new(app)
}),
Expand Down
13 changes: 11 additions & 2 deletions crates/viewer/re_viewer/src/viewer_analytics/event.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::AppEnvironment;

use re_analytics::{
event::{Id, Identify, OpenRecording, StoreInfo, ViewerStarted},
event::{Id, Identify, OpenRecording, StoreInfo, ViewerRuntimeInformation, ViewerStarted},
Config, Property,
};

Expand Down Expand Up @@ -32,10 +32,19 @@ pub fn identify(
}
}

pub fn viewer_started(app_env: &AppEnvironment) -> ViewerStarted {
pub fn viewer_started(
app_env: &AppEnvironment,
adapter_backend: wgpu::Backend,
device_tier: re_renderer::config::DeviceTier,
) -> ViewerStarted {
ViewerStarted {
url: app_env.url().cloned(),
app_env: app_env.name(),
runtime_info: ViewerRuntimeInformation {
is_wsl: super::wsl::is_wsl(),
graphics_adapter_backend: adapter_backend.to_string(),
re_renderer_device_tier: device_tier.to_string(),
},
}
}

Expand Down
20 changes: 15 additions & 5 deletions crates/viewer/re_viewer/src/viewer_analytics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#[cfg(feature = "analytics")]
mod event;

#[cfg(feature = "analytics")]
mod wsl;

use crate::AppEnvironment;
use crate::StartupOptions;

Expand Down Expand Up @@ -52,7 +55,13 @@ impl ViewerAnalytics {
}

/// When the viewer is first started
pub fn on_viewer_started(&self, build_info: re_build_info::BuildInfo) {
#[allow(unused_variables)]
pub fn on_viewer_started(
&self,
build_info: re_build_info::BuildInfo,
adapter_backend: wgpu::Backend,
device_tier: re_renderer::config::DeviceTier,
) {
re_tracing::profile_function!();

#[cfg(feature = "analytics")]
Expand All @@ -66,11 +75,12 @@ impl ViewerAnalytics {
build_info,
&self.app_env,
));
analytics.record(event::viewer_started(&self.app_env));
analytics.record(event::viewer_started(
&self.app_env,
adapter_backend,
device_tier,
));
}

#[cfg(not(feature = "analytics"))]
let _ = build_info;
}

/// When we have loaded the start of a new recording.
Expand Down
17 changes: 17 additions & 0 deletions crates/viewer/re_viewer/src/viewer_analytics/wsl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// Returns true if the current process is running under WSL.
#[cfg(target_os = "linux")]
pub fn is_wsl() -> bool {
if let Ok(b) = std::fs::read("/proc/sys/kernel/osrelease") {
if let Ok(s) = std::str::from_utf8(&b) {
let a = s.to_ascii_lowercase();
return a.contains("microsoft") || a.contains("wsl");
}
}
false
}

/// Returns true if the current process is running under WSL.
#[cfg(not(target_os = "linux"))]
pub fn is_wsl() -> bool {
false
}
9 changes: 1 addition & 8 deletions crates/viewer/re_viewer/src/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,14 +410,7 @@ fn create_app(
};
crate::customize_eframe_and_setup_renderer(cc)?;

let mut app = crate::App::new(
main_thread_token,
build_info,
&app_env,
startup_options,
cc.egui_ctx.clone(),
cc.storage,
);
let mut app = crate::App::new(main_thread_token, build_info, &app_env, startup_options, cc);

if enable_history {
install_popstate_listener(&mut app).ok_or_log_js_error();
Expand Down
3 changes: 1 addition & 2 deletions examples/rust/custom_callback/src/viewer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
re_viewer::build_info(),
&app_env,
startup_options,
cc.egui_ctx.clone(),
cc.storage,
cc,
);

rerun_app.add_receiver(rx);
Expand Down
3 changes: 1 addition & 2 deletions examples/rust/custom_view/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
re_viewer::build_info(),
&app_env,
startup_options,
cc.egui_ctx.clone(),
cc.storage,
cc,
);
app.add_receiver(rx);

Expand Down
3 changes: 1 addition & 2 deletions examples/rust/extend_viewer_ui/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
re_viewer::build_info(),
&app_env,
startup_options,
cc.egui_ctx.clone(),
cc.storage,
cc,
);
rerun_app.add_receiver(rx);
Ok(Box::new(MyApp { rerun_app }))
Expand Down
Loading