Skip to main content

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}