use std::{
sync::Arc,
time::{Duration, Instant},
};
use gled_model::{
asset::scene::{effect::Effect, grid::GridLocation, instance::SceneInstance},
collection::Collections,
patching::{
fixture::{Fixture, LayoutPosition},
layout::LayoutRef,
},
};
use super::{ClientState, EngineState, Outbox};
use crate::{
input::project_inputs::update_input_state, output_state::ProjectState,
pipeline::extract_output::OutputConfig, runtime::render_thread::RenderSnapshot,
storage::asset::project::Project,
};
const TICKS: u32 = 300;
const PROJECT_STATE_SUBSCRIBERS: usize = 2;
fn large_project() -> Project {
let mut project = Project::default();
project.set_grid_size(8, 6);
for index in 0..500 {
project.patch.add_fixture(
Fixture::new(format!("bar {index}")),
LayoutPosition::default(),
);
}
for _ in 0..3 {
let layout = project.patch.add_layout();
let ids: Vec<_> = project.patch.topology.fixtures.keys().copied().collect();
for id in ids {
project.patch.add_member(LayoutRef::Layout(layout), id);
}
}
for row in 0..6 {
for col in 0..8 {
let mut instance =
SceneInstance::from_scene_id(Default::default(), &Collections::default());
for _ in 0..3 {
instance.scene.effects.push(Effect::default());
}
project.add_scene_instance(GridLocation::new(col, row), instance);
}
}
project
}
fn tick(
project: &mut Option<Arc<Project>>,
assets: &Arc<Collections>,
outbox: &mut Outbox,
rendered: &mut Option<RenderSnapshot>,
fader: Option<f32>,
) {
if let Some(value) = fader
&& let Some(project) = project.as_mut().map(Arc::make_mut)
&& let Some(scene) = project
.scenes_instances_grid
.get_mut(&GridLocation::new(0, 0))
{
scene.opacity.multiplier = value;
}
if let Some(project) = project.as_mut() {
update_input_state(project, 0.5);
}
*rendered = Some(RenderSnapshot {
project: project.clone(),
blackout: false,
output_config: OutputConfig::default(),
fps_limit: 60.0,
layout_generation: 1,
});
let state = ProjectState {
project: project.clone(),
selected_scene_instance: GridLocation::default(),
blackout: false,
beats_per_minute: 120.0,
beat_progression: 0.5,
};
let fanned: Vec<_> = (0..PROJECT_STATE_SUBSCRIBERS)
.map(|_| state.clone())
.collect();
let shared = Arc::new(EngineState {
project: project.clone(),
..EngineState::default()
});
let messages = outbox.messages(ClientState {
shared,
applied_sequence: 0,
assets: assets.clone(),
preview: None,
sound: Arc::default(),
input_log: Arc::default(),
midi_log: Arc::default(),
learn_log: Arc::default(),
});
drop((state, fanned, messages));
}
fn measure(fader: bool) -> Duration {
let mut project = Some(Arc::new(large_project()));
let mut outbox = Outbox::default();
let assets = Arc::default();
let mut rendered = None;
tick(&mut project, &assets, &mut outbox, &mut rendered, None);
let mut ticks = Vec::with_capacity(TICKS as usize);
for index in 0..TICKS {
let start = Instant::now();
tick(
&mut project,
&assets,
&mut outbox,
&mut rendered,
fader.then_some(index as f32 / TICKS as f32),
);
ticks.push(start.elapsed());
}
ticks.sort();
ticks[ticks.len() / 2]
}
#[test]
#[ignore = "a measurement, not a test"]
fn tick_bench() {
let idle = measure(false);
let fader = measure(true);
println!("engine tick, project work (median): idle {idle:?}, one fader moving {fader:?}");
}