librashader_runtime/
parameters.rs

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