ez_ffmpeg/wgpu_filter/params.rs
1//! Shared, thread-safe handles surfaced to users: live shader parameters
2//! and cumulative per-stage timing statistics.
3
4use std::marker::PhantomData;
5use std::sync::atomic::{AtomicBool, Ordering};
6use std::sync::{Arc, Mutex};
7
8/// Cumulative per-stage timings, readable while the filter runs via
9/// [`crate::wgpu_filter::WgpuFrameFilter::stats_handle`].
10#[derive(Clone, Copy, Debug, Default)]
11pub struct WgpuFilterStats {
12 /// Number of frames fully processed (readback completed).
13 pub frames: u64,
14 /// CPU time spent uploading planes/uniforms and encoding GPU passes.
15 pub upload_secs: f64,
16 /// Wall time the pipeline thread spent blocked waiting for GPU results.
17 /// With `frames_in_flight > 1`, GPU work overlaps the next frame's CPU
18 /// work, so this is typically much smaller than the actual GPU time.
19 pub gpu_secs: f64,
20 /// CPU time spent copying mapped readback bytes into output frames.
21 pub download_secs: f64,
22}
23
24/// Live handle for updating shader parameters from any thread while the
25/// filter runs inside a pipeline. Created via
26/// [`crate::wgpu_filter::WgpuFrameFilter::params_handle`].
27pub struct WgpuParamsHandle<P: bytemuck::Pod> {
28 pub(crate) bytes: Arc<Mutex<Vec<u8>>>,
29 pub(crate) dirty: Arc<AtomicBool>,
30 pub(crate) _marker: PhantomData<P>,
31}
32
33impl<P: bytemuck::Pod> WgpuParamsHandle<P> {
34 /// Replaces the parameter value; the new bytes are uploaded before the
35 /// next frame is rendered.
36 pub fn set(&self, value: P) {
37 // Tolerate a poisoned lock (the byte buffer is always left in a
38 // valid state) so a panicked pipeline thread cannot take the user's
39 // control thread down with it.
40 let mut bytes = self
41 .bytes
42 .lock()
43 .unwrap_or_else(std::sync::PoisonError::into_inner);
44 bytes.clear();
45 bytes.extend_from_slice(bytemuck::bytes_of(&value));
46 self.dirty.store(true, Ordering::Release);
47 }
48}
49
50/// Parameter state shared between the filter, its params handles, and the
51/// per-frame upload path.
52pub(crate) struct SharedParams {
53 pub(crate) bytes: Arc<Mutex<Vec<u8>>>,
54 pub(crate) dirty: Arc<AtomicBool>,
55 pub(crate) len: usize,
56}
57
58impl SharedParams {
59 pub(crate) fn new(initial: Vec<u8>) -> Self {
60 Self {
61 len: initial.len(),
62 bytes: Arc::new(Mutex::new(initial)),
63 dirty: Arc::new(AtomicBool::new(true)),
64 }
65 }
66}