librashader_runtime/
parameters.rs

1use arc_swap::ArcSwap;
2use librashader_common::map::{FastHashMap, ShortString};
3use librashader_presets::ParameterMeta;
4use std::sync::atomic::{AtomicUsize, Ordering};
5use std::sync::Arc;
6
7/// Trait for filter chains that allow runtime reflection of shader parameters.
8pub trait FilterChainParameters {
9    /// Get the runtime parameters for this filter chain.
10    fn parameters(&self) -> &RuntimeParameters;
11}
12
13/// Runtime reflection of shader parameters for filter chains.
14///
15/// All operations on runtime parameters are atomic and can be done on
16/// any thread.
17pub struct RuntimeParameters {
18    passes_enabled: AtomicUsize,
19    pub(crate) parameters: ArcSwap<FastHashMap<ShortString, f32>>,
20}
21
22impl RuntimeParameters {
23    /// Create a new instance of runtime parameters from a `Vec` of
24    /// shader parameters from a [`ShaderPreset`](librashader_presets::ShaderPreset).
25    pub fn new(passes_enabled: usize, parameters: Vec<ParameterMeta>) -> Self {
26        RuntimeParameters {
27            passes_enabled: AtomicUsize::new(passes_enabled),
28            parameters: ArcSwap::new(Arc::new(
29                parameters
30                    .into_iter()
31                    .map(|param| (param.name, param.value))
32                    .collect(),
33            )),
34        }
35    }
36
37    /// Get the value of a runtime parameter
38    pub fn parameter_value(&self, name: &str) -> Option<f32> {
39        self.parameters.load().get::<str>(name.as_ref()).copied()
40    }
41
42    /// Set a runtime parameter.
43    ///
44    /// This is a relatively slow operation as it will be synchronized across threads.
45    /// If updating multiple parameters, see [`RuntimeParameters::update_parameters`].
46    pub fn set_parameter_value(&self, name: &str, new_value: f32) -> Option<f32> {
47        let mut updated_map = FastHashMap::clone(&self.parameters.load());
48
49        if let Some(value) = updated_map.get_mut::<str>(name.as_ref()) {
50            let old = *value;
51            *value = new_value;
52
53            self.parameters.store(Arc::new(updated_map));
54
55            Some(old)
56        } else {
57            None
58        }
59    }
60
61    /// Update multiple runtime parameters atomically through a function.
62    pub fn update_parameters(&self, updater: impl FnOnce(&mut FastHashMap<ShortString, f32>)) {
63        let mut updated_map = FastHashMap::clone(&self.parameters.load());
64        updater(&mut updated_map);
65        self.parameters.store(Arc::new(updated_map));
66    }
67
68    /// Get a reference to the runtime parameters.
69    pub fn parameters(&self) -> Arc<FastHashMap<ShortString, f32>> {
70        self.parameters.load_full()
71    }
72
73    /// Get the number of passes enabled.
74    ///
75    /// If set from [`RuntimeParameters::set_passes_enabled`] from a different thread,
76    /// it is not guaranteed to be immediately visible.
77    #[inline(always)]
78    pub fn passes_enabled(&self) -> usize {
79        self.passes_enabled.load(Ordering::Relaxed)
80    }
81
82    /// Set the number of passes enabled.
83    ///
84    /// This is an atomic operation and is thread-safe.
85    #[inline(always)]
86    pub fn set_passes_enabled(&self, count: usize) {
87        self.passes_enabled.store(count, Ordering::Relaxed);
88    }
89}
90
91#[macro_export]
92macro_rules! impl_filter_chain_parameters {
93    ($ty:ty) => {
94        impl ::librashader_runtime::parameters::FilterChainParameters for $ty {
95            fn parameters(&self) -> &::librashader_runtime::parameters::RuntimeParameters {
96                &self.common.config
97            }
98        }
99    };
100}