diff --git a/Cargo.lock b/Cargo.lock index d140377..d63f2f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -123,6 +123,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arg_enum_proc_macro" version = "0.3.4" @@ -1749,6 +1755,7 @@ dependencies = [ name = "librashader-runtime" version = "0.3.3" dependencies = [ + "arc-swap", "array-concat", "bytemuck", "image", diff --git a/librashader-capi/src/runtime/d3d11/filter_chain.rs b/librashader-capi/src/runtime/d3d11/filter_chain.rs index 8a5aaec..1345616 100644 --- a/librashader-capi/src/runtime/d3d11/filter_chain.rs +++ b/librashader-capi/src/runtime/d3d11/filter_chain.rs @@ -260,14 +260,14 @@ extern_fn! { chain: *mut libra_d3d11_filter_chain_t, param_name: *const c_char, value: f32 - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); assert_non_null!(param_name); unsafe { let name = CStr::from_ptr(param_name); let name = name.to_str()?; - if chain.set_parameter(name, value).is_none() { + if chain.parameters().set_parameter(name, value).is_none() { return LibrashaderError::UnknownShaderParameter(param_name).export() } } @@ -282,17 +282,17 @@ extern_fn! { /// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_d3d11_filter_chain_t`. /// - `param_name` must be either null or a null terminated string. fn libra_d3d11_filter_chain_get_param( - chain: *mut libra_d3d11_filter_chain_t, + chain: *const libra_d3d11_filter_chain_t, param_name: *const c_char, out: *mut MaybeUninit<f32> - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); assert_non_null!(param_name); unsafe { let name = CStr::from_ptr(param_name); let name = name.to_str()?; - let Some(value) = chain.get_parameter(name) else { + let Some(value) = chain.parameters().get_parameter(name) else { return LibrashaderError::UnknownShaderParameter(param_name).export() }; @@ -309,9 +309,9 @@ extern_fn! { fn libra_d3d11_filter_chain_set_active_pass_count( chain: *mut libra_d3d11_filter_chain_t, value: u32 - ) mut |chain| { - assert_some_ptr!(mut chain); - chain.set_enabled_pass_count(value as usize); + ) |chain| { + assert_some_ptr!(chain); + chain.parameters().set_passes_enabled(value as usize); } } @@ -321,12 +321,12 @@ extern_fn! { /// ## Safety /// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_d3d11_filter_chain_t`. fn libra_d3d11_filter_chain_get_active_pass_count( - chain: *mut libra_d3d11_filter_chain_t, + chain: *const libra_d3d11_filter_chain_t, out: *mut MaybeUninit<u32> - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); unsafe { - let value = chain.get_enabled_pass_count(); + let value = chain.parameters().passes_enabled(); out.write(MaybeUninit::new(value as u32)) } } diff --git a/librashader-capi/src/runtime/d3d12/filter_chain.rs b/librashader-capi/src/runtime/d3d12/filter_chain.rs index ec00429..8a115d5 100644 --- a/librashader-capi/src/runtime/d3d12/filter_chain.rs +++ b/librashader-capi/src/runtime/d3d12/filter_chain.rs @@ -280,14 +280,14 @@ extern_fn! { chain: *mut libra_d3d12_filter_chain_t, param_name: *const c_char, value: f32 - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); assert_non_null!(param_name); unsafe { let name = CStr::from_ptr(param_name); let name = name.to_str()?; - if chain.set_parameter(name, value).is_none() { + if chain.parameters().set_parameter(name, value).is_none() { return LibrashaderError::UnknownShaderParameter(param_name).export() } } @@ -302,17 +302,17 @@ extern_fn! { /// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_d3d12_filter_chain_t`. /// - `param_name` must be either null or a null terminated string. fn libra_d3d12_filter_chain_get_param( - chain: *mut libra_d3d12_filter_chain_t, + chain: *const libra_d3d12_filter_chain_t, param_name: *const c_char, out: *mut MaybeUninit<f32> - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); assert_non_null!(param_name); unsafe { let name = CStr::from_ptr(param_name); let name = name.to_str()?; - let Some(value) = chain.get_parameter(name) else { + let Some(value) = chain.parameters().get_parameter(name) else { return LibrashaderError::UnknownShaderParameter(param_name).export() }; @@ -329,9 +329,9 @@ extern_fn! { fn libra_d3d12_filter_chain_set_active_pass_count( chain: *mut libra_d3d12_filter_chain_t, value: u32 - ) mut |chain| { - assert_some_ptr!(mut chain); - chain.set_enabled_pass_count(value as usize); + ) |chain| { + assert_some_ptr!(chain); + chain.parameters().set_passes_enabled(value as usize); } } @@ -341,12 +341,12 @@ extern_fn! { /// ## Safety /// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_d3d12_filter_chain_t`. fn libra_d3d12_filter_chain_get_active_pass_count( - chain: *mut libra_d3d12_filter_chain_t, + chain: *const libra_d3d12_filter_chain_t, out: *mut MaybeUninit<u32> - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); unsafe { - let value = chain.get_enabled_pass_count(); + let value = chain.parameters().passes_enabled(); out.write(MaybeUninit::new(value as u32)) } } diff --git a/librashader-capi/src/runtime/d3d9/filter_chain.rs b/librashader-capi/src/runtime/d3d9/filter_chain.rs index 8750e7d..e9770b3 100644 --- a/librashader-capi/src/runtime/d3d9/filter_chain.rs +++ b/librashader-capi/src/runtime/d3d9/filter_chain.rs @@ -170,14 +170,14 @@ extern_fn! { chain: *mut libra_d3d9_filter_chain_t, param_name: *const c_char, value: f32 - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); assert_non_null!(param_name); unsafe { let name = CStr::from_ptr(param_name); let name = name.to_str()?; - if chain.set_parameter(name, value).is_none() { + if chain.parameters().set_parameter(name, value).is_none() { return LibrashaderError::UnknownShaderParameter(param_name).export() } } @@ -192,17 +192,17 @@ extern_fn! { /// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_d3d9_filter_chain_t`. /// - `param_name` must be either null or a null terminated string. fn libra_d3d9_filter_chain_get_param( - chain: *mut libra_d3d9_filter_chain_t, + chain: *const libra_d3d9_filter_chain_t, param_name: *const c_char, out: *mut MaybeUninit<f32> - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); assert_non_null!(param_name); unsafe { let name = CStr::from_ptr(param_name); let name = name.to_str()?; - let Some(value) = chain.get_parameter(name) else { + let Some(value) = chain.parameters().get_parameter(name) else { return LibrashaderError::UnknownShaderParameter(param_name).export() }; @@ -219,9 +219,9 @@ extern_fn! { fn libra_d3d9_filter_chain_set_active_pass_count( chain: *mut libra_d3d9_filter_chain_t, value: u32 - ) mut |chain| { - assert_some_ptr!(mut chain); - chain.set_enabled_pass_count(value as usize); + ) |chain| { + assert_some_ptr!(chain); + chain.parameters().set_passes_enabled(value as usize); } } @@ -231,12 +231,12 @@ extern_fn! { /// ## Safety /// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_d3d9_filter_chain_t`. fn libra_d3d9_filter_chain_get_active_pass_count( - chain: *mut libra_d3d9_filter_chain_t, + chain: *const libra_d3d9_filter_chain_t, out: *mut MaybeUninit<u32> - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); unsafe { - let value = chain.get_enabled_pass_count(); + let value = chain.parameters().passes_enabled(); out.write(MaybeUninit::new(value as u32)) } } diff --git a/librashader-capi/src/runtime/gl/filter_chain.rs b/librashader-capi/src/runtime/gl/filter_chain.rs index e23c06d..f42ba47 100644 --- a/librashader-capi/src/runtime/gl/filter_chain.rs +++ b/librashader-capi/src/runtime/gl/filter_chain.rs @@ -227,14 +227,14 @@ extern_fn! { chain: *mut libra_gl_filter_chain_t, param_name: *const c_char, value: f32 - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); assert_non_null!(param_name); unsafe { let name = CStr::from_ptr(param_name); let name = name.to_str()?; - if chain.set_parameter(name, value).is_none() { + if chain.parameters().set_parameter(name, value).is_none() { return LibrashaderError::UnknownShaderParameter(param_name).export() } } @@ -249,17 +249,17 @@ extern_fn! { /// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_gl_filter_chain_t`. /// - `param_name` must be either null or a null terminated string. fn libra_gl_filter_chain_get_param( - chain: *mut libra_gl_filter_chain_t, + chain: *const libra_gl_filter_chain_t, param_name: *const c_char, out: *mut MaybeUninit<f32> - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); assert_non_null!(param_name); unsafe { let name = CStr::from_ptr(param_name); let name = name.to_str()?; - let Some(value) = chain.get_parameter(name) else { + let Some(value) = chain.parameters().get_parameter(name) else { return LibrashaderError::UnknownShaderParameter(param_name).export() }; @@ -276,9 +276,9 @@ extern_fn! { fn libra_gl_filter_chain_set_active_pass_count( chain: *mut libra_gl_filter_chain_t, value: u32 - ) mut |chain| { - assert_some_ptr!(mut chain); - chain.set_enabled_pass_count(value as usize); + ) |chain| { + assert_some_ptr!(chain); + chain.parameters().set_passes_enabled(value as usize); } } @@ -292,7 +292,7 @@ extern_fn! { out: *mut MaybeUninit<u32> ) mut |chain| { assert_some_ptr!(mut chain); - let value = chain.get_enabled_pass_count(); + let value = chain.parameters().passes_enabled(); unsafe { out.write(MaybeUninit::new(value as u32)) } diff --git a/librashader-capi/src/runtime/mtl/filter_chain.rs b/librashader-capi/src/runtime/mtl/filter_chain.rs index d885f92..5821e89 100644 --- a/librashader-capi/src/runtime/mtl/filter_chain.rs +++ b/librashader-capi/src/runtime/mtl/filter_chain.rs @@ -229,13 +229,13 @@ extern_fn! { chain: *mut libra_mtl_filter_chain_t, param_name: *const c_char, value: f32 - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); unsafe { let name = CStr::from_ptr(param_name); let name = name.to_str()?; - if chain.set_parameter(name, value).is_none() { + if chain.parameters().set_parameter(name, value).is_none() { return LibrashaderError::UnknownShaderParameter(param_name).export() } } @@ -250,17 +250,17 @@ extern_fn! { /// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_mtl_filter_chain_t`. /// - `param_name` must be either null or a null terminated string. fn libra_mtl_filter_chain_get_param( - chain: *mut libra_mtl_filter_chain_t, + chain: *const libra_mtl_filter_chain_t, param_name: *const c_char, out: *mut MaybeUninit<f32> - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); unsafe { let name = CStr::from_ptr(param_name); let name = name.to_str()?; - let Some(value) = chain.get_parameter(name) else { + let Some(value) = chain.parameters().get_parameter(name) else { return LibrashaderError::UnknownShaderParameter(param_name).export() }; @@ -277,9 +277,9 @@ extern_fn! { fn libra_mtl_filter_chain_set_active_pass_count( chain: *mut libra_mtl_filter_chain_t, value: u32 - ) mut |chain| { - assert_some_ptr!(mut chain); - chain.set_enabled_pass_count(value as usize); + ) |chain| { + assert_some_ptr!(chain); + chain.parameters().set_passes_enabled(value as usize); } } @@ -289,11 +289,11 @@ extern_fn! { /// ## Safety /// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_mtl_filter_chain_t`. fn libra_mtl_filter_chain_get_active_pass_count( - chain: *mut libra_mtl_filter_chain_t, + chain: *const libra_mtl_filter_chain_t, out: *mut MaybeUninit<u32> - ) mut |chain| { - assert_some_ptr!(mut chain); - let value = chain.get_enabled_pass_count(); + ) |chain| { + assert_some_ptr!(chain); + let value = chain.parameters().passes_enabled(); unsafe { out.write(MaybeUninit::new(value as u32)) } diff --git a/librashader-capi/src/runtime/vk/filter_chain.rs b/librashader-capi/src/runtime/vk/filter_chain.rs index 0e9fe50..20040d3 100644 --- a/librashader-capi/src/runtime/vk/filter_chain.rs +++ b/librashader-capi/src/runtime/vk/filter_chain.rs @@ -306,14 +306,14 @@ extern_fn! { chain: *mut libra_vk_filter_chain_t, param_name: *const c_char, value: f32 - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); assert_non_null!(param_name); unsafe { let name = CStr::from_ptr(param_name); let name = name.to_str()?; - if chain.set_parameter(name, value).is_none() { + if chain.parameters().set_parameter(name, value).is_none() { return LibrashaderError::UnknownShaderParameter(param_name).export() } } @@ -328,17 +328,17 @@ extern_fn! { /// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_vk_filter_chain_t`. /// - `param_name` must be either null or a null terminated string. fn libra_vk_filter_chain_get_param( - chain: *mut libra_vk_filter_chain_t, + chain: *const libra_vk_filter_chain_t, param_name: *const c_char, out: *mut MaybeUninit<f32> - ) mut |chain| { - assert_some_ptr!(mut chain); + ) |chain| { + assert_some_ptr!(chain); assert_non_null!(param_name); unsafe { let name = CStr::from_ptr(param_name); let name = name.to_str()?; - let Some(value) = chain.get_parameter(name) else { + let Some(value) = chain.parameters().get_parameter(name) else { return LibrashaderError::UnknownShaderParameter(param_name).export() }; @@ -355,9 +355,9 @@ extern_fn! { fn libra_vk_filter_chain_set_active_pass_count( chain: *mut libra_vk_filter_chain_t, value: u32 - ) mut |chain| { - assert_some_ptr!(mut chain); - chain.set_enabled_pass_count(value as usize); + ) |chain| { + assert_some_ptr!(chain); + chain.parameters().set_passes_enabled(value as usize); } } @@ -367,11 +367,11 @@ extern_fn! { /// ## Safety /// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_vk_filter_chain_t`. fn libra_vk_filter_chain_get_active_pass_count( - chain: *mut libra_vk_filter_chain_t, + chain: *const libra_vk_filter_chain_t, out: *mut MaybeUninit<u32> - ) mut |chain| { - assert_some_ptr!(mut chain); - let value = chain.get_enabled_pass_count(); + ) |chain| { + assert_some_ptr!(chain); + let value = chain.parameters().passes_enabled(); unsafe { out.write(MaybeUninit::new(value as u32)) } diff --git a/librashader-runtime-d3d11/src/filter_chain.rs b/librashader-runtime-d3d11/src/filter_chain.rs index 41fe0a7..169bf9a 100644 --- a/librashader-runtime-d3d11/src/filter_chain.rs +++ b/librashader-runtime-d3d11/src/filter_chain.rs @@ -43,11 +43,6 @@ use windows::Win32::Graphics::Direct3D11::{ }; use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_R8G8B8A8_UNORM; -pub struct FilterMutable { - pub(crate) passes_enabled: usize, - pub(crate) parameters: FastHashMap<String, f32>, -} - /// A Direct3D 11 filter chain. pub struct FilterChainD3D11 { pub(crate) common: FilterCommon, @@ -71,7 +66,7 @@ pub(crate) struct FilterCommon { pub output_textures: Box<[Option<InputTexture>]>, pub feedback_textures: Box<[Option<InputTexture>]>, pub history_textures: Box<[Option<InputTexture>]>, - pub config: FilterMutable, + pub config: RuntimeParameters, pub disable_mipmaps: bool, pub(crate) draw_quad: DrawQuad, } @@ -103,6 +98,7 @@ mod compile { } use compile::{compile_passes, ShaderPassMeta}; +use librashader_runtime::parameters::RuntimeParameters; impl FilterChainD3D11 { /// Load the shader preset at the given path into a filter chain. @@ -193,14 +189,7 @@ impl FilterChainD3D11 { _device: device.clone(), immediate_context, }, - config: FilterMutable { - passes_enabled: preset.shader_count as usize, - parameters: preset - .parameters - .into_iter() - .map(|param| (param.name, param.value)) - .collect(), - }, + config: RuntimeParameters::new(preset.shader_count as usize, preset.parameters), disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps), luts, samplers, @@ -405,7 +394,7 @@ impl FilterChainD3D11 { frame_count: usize, options: Option<&FrameOptionsD3D11>, ) -> error::Result<()> { - let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled); + let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled()); // Need to clone this because pushing history needs a mutable borrow. let immediate_context = &self.common.d3d11.immediate_context.clone(); diff --git a/librashader-runtime-d3d11/src/filter_pass.rs b/librashader-runtime-d3d11/src/filter_pass.rs index 935872c..0c2451e 100644 --- a/librashader-runtime-d3d11/src/filter_pass.rs +++ b/librashader-runtime-d3d11/src/filter_pass.rs @@ -139,7 +139,7 @@ impl FilterPass { parent.history_textures.iter().map(|o| o.as_ref()), parent.luts.iter().map(|(u, i)| (*u, i.as_ref())), &self.source.parameters, - &parent.config.parameters, + &parent.config, ); } diff --git a/librashader-runtime-d3d12/src/filter_chain.rs b/librashader-runtime-d3d12/src/filter_chain.rs index 5530621..61e3a44 100644 --- a/librashader-runtime-d3d12/src/filter_chain.rs +++ b/librashader-runtime-d3d12/src/filter_chain.rs @@ -60,11 +60,6 @@ use rayon::prelude::*; const MIPMAP_RESERVED_WORKHEAP_DESCRIPTORS: usize = 4096; -pub struct FilterMutable { - pub(crate) passes_enabled: usize, - pub(crate) parameters: FastHashMap<String, f32>, -} - /// A Direct3D 12 filter chain. pub struct FilterChainD3D12 { pub(crate) common: FilterCommon, @@ -92,7 +87,7 @@ pub(crate) struct FilterCommon { pub output_textures: Box<[Option<InputTexture>]>, pub feedback_textures: Box<[Option<InputTexture>]>, pub history_textures: Box<[Option<InputTexture>]>, - pub config: FilterMutable, + pub config: RuntimeParameters, // pub disable_mipmaps: bool, pub luts: FastHashMap<usize, LutTexture>, pub mipmap_gen: D3D12MipmapGen, @@ -222,6 +217,7 @@ mod compile { } use compile::{compile_passes_dxil, compile_passes_hlsl, DxilShaderPassMeta, HlslShaderPassMeta}; +use librashader_runtime::parameters::RuntimeParameters; impl FilterChainD3D12 { /// Load the shader preset at the given path into a filter chain. @@ -387,14 +383,7 @@ impl FilterChainD3D12 { mipmap_gen, root_signature, draw_quad, - config: FilterMutable { - passes_enabled: preset.shader_count as usize, - parameters: preset - .parameters - .into_iter() - .map(|param| (param.name, param.value)) - .collect(), - }, + config: RuntimeParameters::new(preset.shader_count as usize, preset.parameters), history_textures, }, staging_heap, @@ -669,6 +658,13 @@ impl FilterChainD3D12 { ) -> error::Result<()> { self.residuals.dispose(); + // limit number of passes to those enabled. + let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled()); + let passes = &mut self.passes[0..max]; + if passes.is_empty() { + return Ok(()); + } + if let Some(options) = options { if options.clear_history { for framebuffer in &mut self.history_framebuffers { @@ -677,22 +673,8 @@ impl FilterChainD3D12 { } } - // limit number of passes to those enabled. - let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled); - let passes = &mut self.passes[0..max]; - - if passes.is_empty() { - return Ok(()); - } - let options = options.unwrap_or(&self.default_options); - let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled); - let passes = &mut self.passes[0..max]; - if passes.is_empty() { - return Ok(()); - } - let filter = passes[0].config.filter; let wrap_mode = passes[0].config.wrap_mode; diff --git a/librashader-runtime-d3d12/src/filter_pass.rs b/librashader-runtime-d3d12/src/filter_pass.rs index abdaa92..9552d61 100644 --- a/librashader-runtime-d3d12/src/filter_pass.rs +++ b/librashader-runtime-d3d12/src/filter_pass.rs @@ -122,7 +122,7 @@ impl FilterPass { parent.history_textures.iter().map(|o| o.as_ref()), parent.luts.iter().map(|(u, i)| (*u, i.as_ref())), &self.source.parameters, - &parent.config.parameters, + &parent.config, ); } diff --git a/librashader-runtime-d3d9/src/filter_chain.rs b/librashader-runtime-d3d9/src/filter_chain.rs index fcbff44..cdaa61b 100644 --- a/librashader-runtime-d3d9/src/filter_chain.rs +++ b/librashader-runtime-d3d9/src/filter_chain.rs @@ -36,11 +36,6 @@ use crate::util::GetSize; use windows::Win32::Graphics::Direct3D9::{IDirect3DDevice9, IDirect3DSurface9, IDirect3DTexture9}; -pub struct FilterMutable { - pub(crate) passes_enabled: usize, - pub(crate) parameters: FastHashMap<String, f32>, -} - pub(crate) struct FilterCommon { pub(crate) d3d9: IDirect3DDevice9, pub(crate) luts: FastHashMap<usize, LutTexture>, @@ -48,7 +43,7 @@ pub(crate) struct FilterCommon { pub output_textures: Box<[Option<D3D9InputTexture>]>, pub feedback_textures: Box<[Option<D3D9InputTexture>]>, pub history_textures: Box<[Option<D3D9InputTexture>]>, - pub config: FilterMutable, + pub config: RuntimeParameters, pub disable_mipmaps: bool, pub(crate) draw_quad: DrawQuad, } @@ -90,6 +85,7 @@ mod compile { } use compile::{compile_passes, ShaderPassMeta}; +use librashader_runtime::parameters::RuntimeParameters; impl FilterChainD3D9 { fn init_passes( @@ -255,14 +251,7 @@ impl FilterChainD3D9 { history_framebuffers, common: FilterCommon { d3d9: device.clone(), - config: FilterMutable { - passes_enabled: preset.shader_count as usize, - parameters: preset - .parameters - .into_iter() - .map(|param| (param.name, param.value)) - .collect(), - }, + config: RuntimeParameters::new(preset.shader_count as usize, preset.parameters), disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps), luts, samplers, @@ -295,7 +284,8 @@ impl FilterChainD3D9 { frame_count: usize, options: Option<&FrameOptionsD3D9>, ) -> error::Result<()> { - let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled); + let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled()); + let passes = &mut self.passes[0..max]; if let Some(options) = options { if options.clear_history { diff --git a/librashader-runtime-d3d9/src/filter_pass.rs b/librashader-runtime-d3d9/src/filter_pass.rs index b141cae..594401f 100644 --- a/librashader-runtime-d3d9/src/filter_pass.rs +++ b/librashader-runtime-d3d9/src/filter_pass.rs @@ -133,7 +133,7 @@ impl FilterPass { parent.history_textures.iter().map(|o| o.as_ref()), parent.luts.iter().map(|(u, i)| (*u, i.as_ref())), &self.source.parameters, - &parent.config.parameters, + &parent.config, ); } diff --git a/librashader-runtime-gl/src/filter_chain/filter_impl.rs b/librashader-runtime-gl/src/filter_chain/filter_impl.rs index 3da0d51..aea776f 100644 --- a/librashader-runtime-gl/src/filter_chain/filter_impl.rs +++ b/librashader-runtime-gl/src/filter_chain/filter_impl.rs @@ -43,7 +43,7 @@ pub(crate) struct FilterChainImpl<T: GLInterface> { pub(crate) struct FilterCommon { // semantics: ReflectSemantics, - pub config: FilterMutable, + pub config: RuntimeParameters, pub luts: FastHashMap<usize, InputTexture>, pub samplers: SamplerSet, pub output_textures: Box<[InputTexture]>, @@ -52,11 +52,6 @@ pub(crate) struct FilterCommon { pub disable_mipmaps: bool, } -pub struct FilterMutable { - pub(crate) passes_enabled: usize, - pub(crate) parameters: FastHashMap<String, f32>, -} - impl<T: GLInterface> FilterChainImpl<T> { fn reflect_uniform_location(pipeline: GLuint, meta: &dyn UniformMeta) -> VariableLocation { let mut location = VariableLocation { @@ -119,6 +114,7 @@ mod compile { } use compile::{compile_passes, ShaderPassMeta}; +use librashader_runtime::parameters::RuntimeParameters; impl<T: GLInterface> FilterChainImpl<T> { /// Load a filter chain from a pre-parsed `ShaderPreset`. @@ -178,14 +174,7 @@ impl<T: GLInterface> FilterChainImpl<T> { history_framebuffers, draw_quad, common: FilterCommon { - config: FilterMutable { - passes_enabled: preset.shader_count as usize, - parameters: preset - .parameters - .into_iter() - .map(|param| (param.name, param.value)) - .collect(), - }, + config: RuntimeParameters::new(preset.shader_count as usize, preset.parameters), disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps), luts, samplers, @@ -274,7 +263,7 @@ impl<T: GLInterface> FilterChainImpl<T> { options: Option<&FrameOptionsGL>, ) -> error::Result<()> { // limit number of passes to those enabled. - let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled); + let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled()); let passes = &mut self.passes[0..max]; if let Some(options) = options { diff --git a/librashader-runtime-gl/src/filter_chain/parameters.rs b/librashader-runtime-gl/src/filter_chain/parameters.rs index cc69243..e6eb793 100644 --- a/librashader-runtime-gl/src/filter_chain/parameters.rs +++ b/librashader-runtime-gl/src/filter_chain/parameters.rs @@ -2,7 +2,7 @@ use crate::filter_chain::filter_impl::FilterChainImpl; use crate::filter_chain::inner::FilterChainDispatch; use crate::gl::GLInterface; use crate::FilterChainGL; -use librashader_runtime::parameters::FilterChainParameters; +use librashader_runtime::parameters::{FilterChainParameters, RuntimeParameters}; impl AsRef<dyn FilterChainParameters + 'static> for FilterChainDispatch { fn as_ref<'a>(&'a self) -> &'a (dyn FilterChainParameters + 'static) { @@ -23,60 +23,13 @@ impl AsMut<dyn FilterChainParameters + 'static> for FilterChainDispatch { } impl FilterChainParameters for FilterChainGL { - fn get_enabled_pass_count(&self) -> usize { - self.filter.as_ref().get_enabled_pass_count() - } - - fn set_enabled_pass_count(&mut self, count: usize) { - self.filter.as_mut().set_enabled_pass_count(count) - } - - fn enumerate_parameters(&self) -> ::librashader_common::map::halfbrown::Iter<String, f32> { - self.filter.as_ref().enumerate_parameters() - } - - fn get_parameter(&self, parameter: &str) -> Option<f32> { - self.filter.as_ref().get_parameter(parameter) - } - - fn set_parameter(&mut self, parameter: &str, new_value: f32) -> Option<f32> { - self.filter.as_mut().set_parameter(parameter, new_value) + fn parameters(&self) -> &RuntimeParameters { + self.filter.as_ref().parameters() } } impl<T: GLInterface> FilterChainParameters for FilterChainImpl<T> { - fn get_enabled_pass_count(&self) -> usize { - self.common.config.passes_enabled - } - - fn set_enabled_pass_count(&mut self, count: usize) { - self.common.config.passes_enabled = count - } - - fn enumerate_parameters(&self) -> ::librashader_common::map::halfbrown::Iter<String, f32> { - self.common.config.parameters.iter() - } - - fn get_parameter(&self, parameter: &str) -> Option<f32> { - self.common - .config - .parameters - .get::<str>(parameter.as_ref()) - .copied() - } - - fn set_parameter(&mut self, parameter: &str, new_value: f32) -> Option<f32> { - if let Some(value) = self - .common - .config - .parameters - .get_mut::<str>(parameter.as_ref()) - { - let old = *value; - *value = new_value; - Some(old) - } else { - None - } + fn parameters(&self) -> &RuntimeParameters { + &self.common.config } } diff --git a/librashader-runtime-gl/src/filter_pass.rs b/librashader-runtime-gl/src/filter_pass.rs index 42591bd..4c5d487 100644 --- a/librashader-runtime-gl/src/filter_pass.rs +++ b/librashader-runtime-gl/src/filter_pass.rs @@ -196,7 +196,7 @@ impl<T: GLInterface> FilterPass<T> { parent.history_textures.iter().map(|o| o.bound()), parent.luts.iter().map(|(u, i)| (*u, i)), &self.source.parameters, - &parent.config.parameters, + &parent.config, ); } } diff --git a/librashader-runtime-mtl/src/filter_chain.rs b/librashader-runtime-mtl/src/filter_chain.rs index f135970..d7a944d 100644 --- a/librashader-runtime-mtl/src/filter_chain.rs +++ b/librashader-runtime-mtl/src/filter_chain.rs @@ -57,6 +57,7 @@ mod compile { } use compile::{compile_passes, ShaderPassMeta}; +use librashader_runtime::parameters::RuntimeParameters; /// A Metal filter chain. pub struct FilterChainMetal { @@ -75,18 +76,13 @@ impl Debug for FilterChainMetal { } } -pub struct FilterMutable { - pub passes_enabled: usize, - pub(crate) parameters: FastHashMap<String, f32>, -} - pub(crate) struct FilterCommon { pub output_textures: Box<[Option<InputTexture>]>, pub feedback_textures: Box<[Option<InputTexture>]>, pub history_textures: Box<[Option<InputTexture>]>, pub luts: FastHashMap<usize, LutTexture>, pub samplers: SamplerSet, - pub config: FilterMutable, + pub config: RuntimeParameters, pub internal_frame_count: i32, pub(crate) draw_quad: DrawQuad, device: Id<ProtocolObject<dyn MTLDevice>>, @@ -301,14 +297,7 @@ impl FilterChainMetal { common: FilterCommon { luts, samplers, - config: FilterMutable { - passes_enabled: preset.shader_count as usize, - parameters: preset - .parameters - .into_iter() - .map(|param| (param.name, param.value)) - .collect(), - }, + config: RuntimeParameters::new(preset.shader_count as usize, preset.parameters), draw_quad, device, output_textures, @@ -336,7 +325,7 @@ impl FilterChainMetal { frame_count: usize, options: Option<&FrameOptionsMetal>, ) -> error::Result<()> { - let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled); + let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled()); let passes = &mut self.passes[0..max]; if let Some(options) = &options { let desc = unsafe { diff --git a/librashader-runtime-mtl/src/filter_pass.rs b/librashader-runtime-mtl/src/filter_pass.rs index d2e0590..f6d852b 100644 --- a/librashader-runtime-mtl/src/filter_pass.rs +++ b/librashader-runtime-mtl/src/filter_pass.rs @@ -163,7 +163,7 @@ impl FilterPass { parent.history_textures.iter().map(|o| o.as_ref()), parent.luts.iter().map(|(u, i)| (*u, i.as_ref())), &self.source.parameters, - &parent.config.parameters, + &parent.config, ); // flush to buffers diff --git a/librashader-runtime-vk/src/filter_chain.rs b/librashader-runtime-vk/src/filter_chain.rs index ca13c1f..669d609 100644 --- a/librashader-runtime-vk/src/filter_chain.rs +++ b/librashader-runtime-vk/src/filter_chain.rs @@ -128,11 +128,6 @@ pub struct FilterChainVulkan { default_options: FrameOptionsVulkan, } -pub struct FilterMutable { - pub(crate) passes_enabled: usize, - pub(crate) parameters: FastHashMap<String, f32>, -} - pub(crate) struct FilterCommon { pub(crate) luts: FastHashMap<usize, LutTexture>, pub samplers: SamplerSet, @@ -140,7 +135,7 @@ pub(crate) struct FilterCommon { pub output_textures: Box<[Option<InputImage>]>, pub feedback_textures: Box<[Option<InputImage>]>, pub history_textures: Box<[Option<InputImage>]>, - pub config: FilterMutable, + pub config: RuntimeParameters, pub device: Arc<ash::Device>, pub(crate) internal_frame_count: usize, } @@ -236,6 +231,7 @@ mod compile { } use compile::{compile_passes, ShaderPassMeta}; +use librashader_runtime::parameters::RuntimeParameters; impl FilterChainVulkan { /// Load the shader preset at the given path into a filter chain. @@ -386,14 +382,7 @@ impl FilterChainVulkan { common: FilterCommon { luts, samplers, - config: FilterMutable { - passes_enabled: preset.shader_count as usize, - parameters: preset - .parameters - .into_iter() - .map(|param| (param.name, param.value)) - .collect(), - }, + config: RuntimeParameters::new(preset.shader_count as usize, preset.parameters), draw_quad: DrawQuad::new(&device.device, &device.alloc)?, device: device.device.clone(), output_textures, @@ -576,7 +565,7 @@ impl FilterChainVulkan { intermediates.dispose(); // limit number of passes to those enabled. - let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled); + let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled()); let passes = &mut self.passes[0..max]; if let Some(options) = &options { diff --git a/librashader-runtime-vk/src/filter_pass.rs b/librashader-runtime-vk/src/filter_pass.rs index 83463db..b6499d6 100644 --- a/librashader-runtime-vk/src/filter_pass.rs +++ b/librashader-runtime-vk/src/filter_pass.rs @@ -219,7 +219,7 @@ impl FilterPass { parent.history_textures.iter().map(|o| o.as_ref()), parent.luts.iter().map(|(u, i)| (*u, i.as_ref())), &self.source.parameters, - &parent.config.parameters, + &parent.config, ); } } diff --git a/librashader-runtime-wgpu/src/filter_chain.rs b/librashader-runtime-wgpu/src/filter_chain.rs index 0d2baca..adaadb0 100644 --- a/librashader-runtime-wgpu/src/filter_chain.rs +++ b/librashader-runtime-wgpu/src/filter_chain.rs @@ -56,6 +56,7 @@ mod compile { } use compile::{compile_passes, ShaderPassMeta}; +use librashader_runtime::parameters::RuntimeParameters; /// A wgpu filter chain. pub struct FilterChainWgpu { @@ -69,19 +70,13 @@ pub struct FilterChainWgpu { default_frame_options: FrameOptionsWgpu, } -pub struct FilterMutable { - pub passes_enabled: usize, - pub(crate) parameters: FastHashMap<String, f32>, -} - pub(crate) struct FilterCommon { pub output_textures: Box<[Option<InputImage>]>, pub feedback_textures: Box<[Option<InputImage>]>, pub history_textures: Box<[Option<InputImage>]>, pub luts: FastHashMap<usize, LutTexture>, pub samplers: SamplerSet, - pub config: FilterMutable, - pub internal_frame_count: i32, + pub config: RuntimeParameters, pub(crate) draw_quad: DrawQuad, device: Arc<Device>, pub(crate) queue: Arc<wgpu::Queue>, @@ -199,21 +194,13 @@ impl FilterChainWgpu { common: FilterCommon { luts, samplers, - config: FilterMutable { - passes_enabled: preset.shader_count as usize, - parameters: preset - .parameters - .into_iter() - .map(|param| (param.name, param.value)) - .collect(), - }, + config: RuntimeParameters::new(preset.shader_count as usize, preset.parameters), draw_quad, device, queue, output_textures, feedback_textures, history_textures, - internal_frame_count: 0, }, passes: filters, output_framebuffers, @@ -377,7 +364,7 @@ impl FilterChainWgpu { frame_count: usize, options: Option<&FrameOptionsWgpu>, ) -> error::Result<()> { - let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled); + let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled()); let passes = &mut self.passes[0..max]; if let Some(options) = &options { @@ -513,7 +500,6 @@ impl FilterChainWgpu { } self.push_history(&input, cmd); - self.common.internal_frame_count = self.common.internal_frame_count.wrapping_add(1); Ok(()) } } diff --git a/librashader-runtime-wgpu/src/filter_pass.rs b/librashader-runtime-wgpu/src/filter_pass.rs index 9778973..b04a0f4 100644 --- a/librashader-runtime-wgpu/src/filter_pass.rs +++ b/librashader-runtime-wgpu/src/filter_pass.rs @@ -238,7 +238,7 @@ impl FilterPass { parent.history_textures.iter().map(|o| o.as_ref()), parent.luts.iter().map(|(u, i)| (*u, i.as_ref())), &self.source.parameters, - &parent.config.parameters, + &parent.config, ); // flush to buffers diff --git a/librashader-runtime/Cargo.toml b/librashader-runtime/Cargo.toml index 167478f..b4e4d73 100644 --- a/librashader-runtime/Cargo.toml +++ b/librashader-runtime/Cargo.toml @@ -19,6 +19,7 @@ librashader-reflect = { path = "../librashader-reflect", version = "0.3.3" } bytemuck = { version = "1.12.3", features = ["derive"] } num-traits = "0.2.15" array-concat = "0.5.2" +arc-swap = "1.7.1" tinymap = "0.4.0" diff --git a/librashader-runtime/src/binding.rs b/librashader-runtime/src/binding.rs index ee31e32..8848a99 100644 --- a/librashader-runtime/src/binding.rs +++ b/librashader-runtime/src/binding.rs @@ -1,3 +1,4 @@ +use crate::parameters::RuntimeParameters; use crate::uniforms::{BindUniform, NoUniformBinder, UniformStorage}; use librashader_common::map::FastHashMap; use librashader_common::Size; @@ -120,8 +121,9 @@ where original_history: impl Iterator<Item = Option<impl AsRef<Self::InputTexture>>>, lookup_textures: impl Iterator<Item = (usize, impl AsRef<Self::InputTexture>)>, parameter_defaults: &FastHashMap<String, ShaderParameter>, - runtime_parameters: &FastHashMap<String, f32>, + runtime_parameters: &RuntimeParameters, ) { + let runtime_parameters = runtime_parameters.parameters.load(); // Bind MVP if let Some(offset) = uniform_bindings.get(&UniqueSemantics::MVP.into()) { uniform_storage.bind_mat4( diff --git a/librashader-runtime/src/parameters.rs b/librashader-runtime/src/parameters.rs index 1ba9add..81c9638 100644 --- a/librashader-runtime/src/parameters.rs +++ b/librashader-runtime/src/parameters.rs @@ -1,64 +1,92 @@ +use std::ops::Deref; +use arc_swap::ArcSwap; +use librashader_common::map::FastHashMap; +use librashader_presets::ParameterConfig; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; + /// Trait for filter chains that allow runtime reflection of shader parameters. pub trait FilterChainParameters { - /// Gets the number of shader passes enabled at runtime. - fn get_enabled_pass_count(&self) -> usize; + /// Get the runtime parameters for this filter chain. + fn parameters(&self) -> &RuntimeParameters; +} - /// Sets the number of shader passes enabled at runtime. - fn set_enabled_pass_count(&mut self, count: usize); +/// Runtime reflection of shader parameters for filter chains. +/// +/// All operations on runtime parameters are atomic and can be done on +/// any thread. +pub struct RuntimeParameters { + passes_enabled: AtomicUsize, + pub(crate) parameters: ArcSwap<FastHashMap<String, f32>>, +} - /// Enumerates the active parameters as well as their values in the current filter chain. - fn enumerate_parameters<'a>( - &'a self, - ) -> ::librashader_common::map::halfbrown::Iter<String, f32>; +impl RuntimeParameters { + /// Create a new instance of runtime parameters from a `Vec` of + /// shader parameters from a [`ShaderPreset`](librashader_presets::ShaderPreset). + pub fn new(passes_enabled: usize, parameters: Vec<ParameterConfig>) -> Self { + RuntimeParameters { + passes_enabled: AtomicUsize::new(passes_enabled), + parameters: ArcSwap::new(Arc::new( + parameters + .into_iter() + .map(|param| (param.name, param.value)) + .collect(), + )), + } + } - /// Get the value of the given parameter if present. - fn get_parameter(&self, parameter: &str) -> Option<f32>; + /// Get the value of a runtime parameter + pub fn get_parameter(&self, name: &str) -> Option<f32> { + self.parameters.load().get::<str>(name.as_ref()).copied() + } - /// Set the value of the given parameter if present. + /// Set a runtime parameter. /// - /// Returns `None` if the parameter did not exist, or the old value if successful. - fn set_parameter(&mut self, parameter: &str, new_value: f32) -> Option<f32>; + /// This is a relatively slow operation as it will be synchronized across threads. + pub fn set_parameter(&self, name: &str, new_value: f32) -> Option<f32> { + let mut updated_map = FastHashMap::clone(&self.parameters.load()); + + if let Some(value) = updated_map.get_mut::<str>(name.as_ref()) { + let old = *value; + *value = new_value; + + self.parameters.store(Arc::new(updated_map)); + + Some(old) + } else { + None + } + } + + /// Get a reference to the runtime parameters. + pub fn parameters(&self) -> Arc<FastHashMap<String, f32>> { + self.parameters.load_full() + } + + /// Get the number of passes enabled. + /// + /// If set from [`RuntimeParameters::set_passes_enabled`] from a different thread, + /// it is not guaranteed to be immediately visible. + #[inline(always)] + pub fn passes_enabled(&self) -> usize { + self.passes_enabled.load(Ordering::Relaxed) + } + + /// Set the number of passes enabled. + /// + /// This is an atomic operation and is thread-safe. + #[inline(always)] + pub fn set_passes_enabled(&self, count: usize) { + self.passes_enabled.store(count, Ordering::Relaxed); + } } #[macro_export] macro_rules! impl_filter_chain_parameters { ($ty:ty) => { impl ::librashader_runtime::parameters::FilterChainParameters for $ty { - fn get_enabled_pass_count(&self) -> usize { - self.common.config.passes_enabled - } - - fn set_enabled_pass_count(&mut self, count: usize) { - self.common.config.passes_enabled = count - } - - fn enumerate_parameters<'a>( - &'a self, - ) -> ::librashader_common::map::halfbrown::Iter<String, f32> { - self.common.config.parameters.iter() - } - - fn get_parameter(&self, parameter: &str) -> Option<f32> { - self.common - .config - .parameters - .get::<str>(parameter.as_ref()) - .copied() - } - - fn set_parameter(&mut self, parameter: &str, new_value: f32) -> Option<f32> { - if let Some(value) = self - .common - .config - .parameters - .get_mut::<str>(parameter.as_ref()) - { - let old = *value; - *value = new_value; - Some(old) - } else { - None - } + fn parameters(&self) -> &::librashader_runtime::parameters::RuntimeParameters { + &self.common.config } } }; diff --git a/librashader/src/lib.rs b/librashader/src/lib.rs index 0dd8469..1f7c227 100644 --- a/librashader/src/lib.rs +++ b/librashader/src/lib.rs @@ -236,6 +236,7 @@ pub mod reflect { pub mod runtime { pub use librashader_common::{Size, Viewport}; pub use librashader_runtime::parameters::FilterChainParameters; + pub use librashader_runtime::parameters::RuntimeParameters; #[cfg(feature = "runtime-gl")] #[doc(cfg(feature = "runtime-gl"))]