//! Opt-in, reproducible category/resize measurements. No hardware settings change. use super::*; use cosmic::Application; use cosmic::iced::advanced::renderer::{Headless, Renderer as _}; use cosmic::iced::advanced::{Layout, Shell, clipboard, layout, mouse, renderer, widget::Tree}; use cosmic::iced::{Color, Event, Font, Pixels, Rectangle, Size, window}; fn fixture() -> App { let source = std::env::var_os("FERESE_BENCH_CONFIG") .map(|p| std::fs::read_to_string(p).unwrap()) .unwrap_or_else(|| include_str!("../../../packaging/config.kdl").into()); let (mut app, _) = App::init( Core::default(), ( "/unused/settings-performance.kdl".into(), Snapshot::parse(source), None, None, ), ); app.options_loaded(all_options::catalog()); app.connections.snapshot = Some(connections::performance_snapshot()); app.tray_apps = (0..12) .map(|i| tray_controls::Application { id: format!("app-{i}"), title: format!("Application {i}"), }) .collect(); app.displays = (0..3) .map(|i| displays::Display { connector: format!("DP-{}", i + 1), identity: format!("Test display {i}"), profile: None, logical_width: Some(1920), focused: i == 0, current: Some(displays::Mode { width: 3840, height: 2160, refresh: 60000, }), modes: vec![ displays::Mode { width: 3840, height: 2160, refresh: 60000, }, displays::Mode { width: 2560, height: 1440, refresh: 60000, }, ], }) .collect(); app } #[test] #[ignore = "category/resize profile; requires the matching compositor schema binary"] fn profile_all_categories_and_resizing() { let runtime = tokio::runtime::Builder::new_current_thread() .enable_all() .build() .unwrap(); let backend = std::env::var("FERESE_BENCH_BACKEND").unwrap_or_else(|_| "wgpu".into()); let mut renderer = runtime .block_on(cosmic::Renderer::new( Font::default(), Pixels(14.), Some(&backend), )) .unwrap(); let scale = 2.; for page in Page::ALL { let mut app = fixture(); drop(app.update(Message::Page(page))); let theme = app.native_palette.native_theme(); let mut tree: Option = None; for frame in 0..18 { let scenario = if frame == 0 { "cold" } else if frame < 4 { "warm" } else if frame < 14 { "resize" } else { "switch" }; if frame >= 14 { drop(app.update(Message::Page(Page::General))); drop(app.update(Message::Page(page))); } let size = if (4..14).contains(&frame) && frame % 2 == 0 { Size::new(631., 568.) } else { Size::new(1272., 760.) }; let viewport = Rectangle::with_size(size); let mut messages = Vec::new(); let started = std::time::Instant::now(); let mut view = app.page_view(); let tree = tree.get_or_insert_with(|| Tree::new(&view)); cosmic::iced::advanced::widget::tree::NAMED .with(|named| *named.borrow_mut() = tree.take_all_named()); tree.diff(view.as_widget_mut()); let node = view.as_widget_mut().layout( tree, &renderer, &layout::Limits::new(Size::ZERO, size), ); cosmic::iced::advanced::widget::tree::NAMED.with(|named| named.borrow_mut().clear()); view.as_widget_mut().update( tree, &Event::Window(window::Event::RedrawRequested(std::time::Instant::now())), Layout::new(&node), mouse::Cursor::Unavailable, &renderer, &mut clipboard::Null, &mut Shell::new(&mut messages), &viewport, ); let layout_us = started.elapsed().as_micros(); renderer.reset(viewport); let started = std::time::Instant::now(); view.as_widget().draw( tree, &mut renderer, &theme, &renderer::Style { text_color: Color::WHITE, icon_color: Color::WHITE, scale_factor: scale as f64, }, Layout::new(&node), mouse::Cursor::Unavailable, &viewport, ); let draw_us = started.elapsed().as_micros(); drop(view); let started = std::time::Instant::now(); let pixels = Headless::screenshot( &mut renderer, Size::new((size.width * scale) as u32, (size.height * scale) as u32), scale, theme.cosmic().bg_color().into(), ); let render_us = started.elapsed().as_micros(); if matches!(frame, 0 | 4 | 5) && let Some(dir) = std::env::var_os("FERESE_BENCH_IMAGES_DIR") { let path = PathBuf::from(dir); std::fs::create_dir_all(&path).unwrap(); image::save_buffer( path.join(format!("{page:?}-{frame}.png")), &pixels, (size.width * scale) as u32, (size.height * scale) as u32, image::ColorType::Rgba8, ) .unwrap(); } for message in messages { drop(app.update(message)); } eprintln!( "AUDIT {}", serde_json::json!({"backend":backend,"page":format!("{page:?}"),"frame":frame,"scenario":scenario,"width":size.width,"layout_us":layout_us,"draw_us":draw_us,"render_us":render_us}) ); } } }