Skip to content

Commit

Permalink
Do not recreate the effect when the properties are changed only throu…
Browse files Browse the repository at this point in the history
…gh the UI
  • Loading branch information
Jakub Hlusička committed Apr 20, 2020
1 parent 3095556 commit 52cff2b
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 71 deletions.
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions src/effect/effect_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,11 @@ impl BindableProperty for EffectParamCustomBool {
self.property.add_properties(properties);
}

fn reload_settings(&mut self, settings: &mut SettingsContext) {
self.property.reload_settings(settings);
self.effect_param.prepare_value(self.property.get_value());
}

fn prepare_values(&mut self) {}

fn stage_value<'a>(&mut self, graphics_context: &'a GraphicsContext) {
Expand Down Expand Up @@ -330,6 +335,11 @@ impl BindableProperty for EffectParamCustomInt {
self.property.add_properties(properties);
}

fn reload_settings(&mut self, settings: &mut SettingsContext) {
self.property.reload_settings(settings);
self.effect_param.prepare_value(self.property.get_value());
}

fn prepare_values(&mut self) {}

fn stage_value<'a>(&mut self, graphics_context: &'a GraphicsContext) {
Expand Down Expand Up @@ -392,6 +402,11 @@ impl BindableProperty for EffectParamCustomFloat {
self.property.add_properties(properties);
}

fn reload_settings(&mut self, settings: &mut SettingsContext) {
self.property.reload_settings(settings);
self.effect_param.prepare_value(self.property.get_value() as f32);
}

fn prepare_values(&mut self) {}

fn stage_value<'a>(&mut self, graphics_context: &'a GraphicsContext) {
Expand Down Expand Up @@ -449,6 +464,11 @@ impl BindableProperty for EffectParamCustomColor {
self.property.add_properties(properties);
}

fn reload_settings(&mut self, settings: &mut SettingsContext) {
self.property.reload_settings(settings);
self.effect_param.prepare_value((self.property.get_value() as Color).into());
}

fn prepare_values(&mut self) {}

fn stage_value<'a>(&mut self, graphics_context: &'a GraphicsContext) {
Expand Down Expand Up @@ -577,6 +597,13 @@ impl BindableProperty for EffectParamCustomFFT {
self.property_dampening_factor_release.add_properties(properties);
}

fn reload_settings(&mut self, settings: &mut SettingsContext) {
self.property_mix.reload_settings(settings);
self.property_channel.reload_settings(settings);
self.property_dampening_factor_attack.reload_settings(settings);
self.property_dampening_factor_release.reload_settings(settings);
}

fn prepare_values(&mut self) {
let fft_result = if let Some(result) = self.audio_fft.retrieve_result() {
result
Expand Down
50 changes: 35 additions & 15 deletions src/effect/loaded_value.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::fmt::Debug;
use std::str::FromStr;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
Expand Down Expand Up @@ -60,6 +61,8 @@ pub trait LoadedValueType: Sized {
}
}

fn reload_settings(&mut self, settings: &mut SettingsContext);

fn add_properties(&self, properties: &mut Properties);

fn get_value(&self) -> Self::Output;
Expand All @@ -72,6 +75,7 @@ pub struct LoadedValueTypeSourceArgs<T> where T: FromStr + Clone {
/// A loaded value of which the value can only be specified in the shader source code.
/// Returns `Some(T)`, if a default value is specified.
/// Otherwise, may return `None`.
#[derive(Debug)]
pub struct LoadedValueTypeSource<T> where T: FromStr + Clone {
value: Option<T>,
}
Expand All @@ -93,6 +97,10 @@ impl<T> LoadedValueType for LoadedValueTypeSource<T> where T: FromStr + Clone {
Ok(Self { value })
}

fn reload_settings(&mut self, _settings: &mut SettingsContext) {
// All values are taken from the source code, nothing to reload
}

fn add_properties(&self, _properties: &mut Properties) {
// Simple property types do not produce any UI
}
Expand All @@ -102,6 +110,7 @@ impl<T> LoadedValueType for LoadedValueTypeSource<T> where T: FromStr + Clone {
}
}

#[derive(Debug)]
pub struct LoadedValueTypePropertyDescriptorArgs<T: PropertyDescriptorSpecialization> {
default_value: T,
}
Expand Down Expand Up @@ -143,6 +152,10 @@ where T: PropertyDescriptorSpecialization + Sized,
<Self as LoadedValueTypePropertyDescriptor>::from_identifier(args, identifier, preprocess_result, settings)
}

fn reload_settings(&mut self, settings: &mut SettingsContext) {
// Descriptors are loaded from the source code, not the settings
}

fn add_properties(&self, properties: &mut Properties) {
<Self as LoadedValueTypePropertyDescriptor>::add_properties(self, properties)
}
Expand All @@ -154,6 +167,7 @@ where T: PropertyDescriptorSpecialization + Sized,

/// A loaded value type, which loads a property descriptor from the shader source code.
/// Useful for creating loaded values which retrieve their data from the effect UI.
#[derive(Debug)]
pub struct LoadedValueTypePropertyDescriptorF64 {
descriptor: PropertyDescriptor<PropertyDescriptorSpecializationF64>,
description: LoadedValueTypeSource<String>,
Expand Down Expand Up @@ -253,6 +267,7 @@ impl LoadedValueTypePropertyDescriptor for LoadedValueTypePropertyDescriptorF64
}
}

#[derive(Debug)]
pub struct LoadedValueTypePropertyDescriptorI32 {
descriptor: PropertyDescriptor<PropertyDescriptorSpecializationI32>,
description: LoadedValueTypeSource<String>,
Expand Down Expand Up @@ -352,6 +367,7 @@ impl LoadedValueTypePropertyDescriptor for LoadedValueTypePropertyDescriptorI32
}
}

#[derive(Debug)]
pub struct LoadedValueTypePropertyDescriptorColor {
descriptor: PropertyDescriptor<PropertyDescriptorSpecializationColor>,
description: LoadedValueTypeSource<String>,
Expand Down Expand Up @@ -398,6 +414,7 @@ impl LoadedValueTypePropertyDescriptor for LoadedValueTypePropertyDescriptorColo
}
}

#[derive(Debug)]
pub struct LoadedValueTypePropertyDescriptorBool {
descriptor: PropertyDescriptor<PropertyDescriptorSpecializationBool>,
description: LoadedValueTypeSource<String>,
Expand Down Expand Up @@ -443,11 +460,9 @@ impl LoadedValueTypePropertyDescriptor for LoadedValueTypePropertyDescriptorBool
}
}

pub struct LoadedValueTypePropertyArgs<T>
where T: LoadedValueTypePropertyDescriptor,
<T as LoadedValueTypePropertyDescriptor>::Specialization: ValuePropertyDescriptorSpecialization,
<<T as LoadedValueTypePropertyDescriptor>::Specialization as ValuePropertyDescriptorSpecialization>::ValueType: FromStr + Clone,
{
pub trait LoadedValueTypePropertyBounds = LoadedValueTypePropertyDescriptor<Specialization: ValuePropertyDescriptorSpecialization<ValueType: FromStr + Clone>> + Debug;

pub struct LoadedValueTypePropertyArgs<T: LoadedValueTypePropertyBounds> {
pub allow_definitions_in_source: bool,
pub default_descriptor_specialization: <T as LoadedValueTypePropertyDescriptor>::Specialization,
pub default_value: <<T as LoadedValueTypePropertyDescriptor>::Specialization as ValuePropertyDescriptorSpecialization>::ValueType,
Expand All @@ -456,21 +471,14 @@ where T: LoadedValueTypePropertyDescriptor,
/// Represents a hierarchically-loaded value.
/// This value can be either provided by the shader source code,
/// or from the effect settings properties.
pub struct LoadedValueTypeProperty<T>
where T: LoadedValueTypePropertyDescriptor,
<T as LoadedValueTypePropertyDescriptor>::Specialization: ValuePropertyDescriptorSpecialization,
<<T as LoadedValueTypePropertyDescriptor>::Specialization as ValuePropertyDescriptorSpecialization>::ValueType: FromStr + Clone,
{
pub struct LoadedValueTypeProperty<T: LoadedValueTypePropertyBounds> {
loaded_value_descriptor: Option<T>,
loaded_value_default: Option<LoadedValueTypeSource::<<<T as LoadedValueTypePropertyDescriptor>::Specialization as ValuePropertyDescriptorSpecialization>::ValueType>>,
default_value: Option<<<T as LoadedValueTypePropertyDescriptor>::Specialization as ValuePropertyDescriptorSpecialization>::ValueType>,
value: <<T as LoadedValueTypePropertyDescriptor>::Specialization as ValuePropertyDescriptorSpecialization>::ValueType,
}

impl<T> LoadedValueType for LoadedValueTypeProperty<T>
where T: LoadedValueTypePropertyDescriptor,
<T as LoadedValueTypePropertyDescriptor>::Specialization: ValuePropertyDescriptorSpecialization,
<<T as LoadedValueTypePropertyDescriptor>::Specialization as ValuePropertyDescriptorSpecialization>::ValueType: FromStr + Clone,
{
impl<T: LoadedValueTypePropertyBounds> LoadedValueType for LoadedValueTypeProperty<T> {
type Output = <<T as LoadedValueTypePropertyDescriptor>::Specialization as ValuePropertyDescriptorSpecialization>::ValueType;
type Args = LoadedValueTypePropertyArgs<T>;

Expand All @@ -491,6 +499,7 @@ where T: LoadedValueTypePropertyDescriptor,
Self {
loaded_value_descriptor: None,
loaded_value_default: None,
default_value: None,
value: result?,
}
},
Expand Down Expand Up @@ -537,12 +546,23 @@ where T: LoadedValueTypePropertyDescriptor,
Self {
loaded_value_descriptor: Some(loaded_value_descriptor),
loaded_value_default,
default_value: Some(default_value),
value: loaded_value,
}
}
})
}

fn reload_settings(&mut self, settings: &mut SettingsContext) {
// Assumes that it is not necessary to reload the descriptors and default values, otherwise
// we would need to reload both loaded values and figure out the default value as in
// `from_identifier`.
if let Some(loaded_value_descriptor) = self.loaded_value_descriptor.as_ref() {
let descriptor = loaded_value_descriptor.get_value();
self.value = settings.get_property_value(&descriptor, self.default_value.as_ref().unwrap());
}
}

fn add_properties(&self, properties: &mut Properties) {
if let &Some(ref default) = &self.loaded_value_default {
default.add_properties(properties);
Expand Down
49 changes: 49 additions & 0 deletions src/effect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub use loaded_value::*;
/// An object representing a binding of setting-properties to graphics uniforms.
pub trait BindableProperty: Downcast {
fn add_properties(&self, properties: &mut Properties);
fn reload_settings(&mut self, settings: &mut SettingsContext);
fn prepare_values(&mut self);
fn stage_value<'a>(&mut self, graphics_context: &'a GraphicsContext);
fn assign_value<'a>(&mut self, graphics_context: &'a FilterContext);
Expand Down Expand Up @@ -177,6 +178,10 @@ impl EffectParamsCustom {
Ok(())
}

pub fn reload_settings(&mut self, settings: &mut SettingsContext) {
self.params.iter_mut().for_each(|param| param.reload_settings(settings));
}

pub fn prepare_values(&mut self) {
self.params.iter_mut().for_each(|param| param.prepare_values());
}
Expand Down Expand Up @@ -231,6 +236,10 @@ pub struct EffectParams {
}

impl EffectParams {
pub fn reload_settings(&mut self, settings: &mut SettingsContext) {
self.custom.reload_settings(settings);
}

pub fn stage_values(&mut self, graphics_context: &GraphicsContext) {
self.frame.stage_value(graphics_context);
self.framerate.stage_value(graphics_context);
Expand Down Expand Up @@ -278,4 +287,44 @@ impl PreparedEffect {
pub fn add_properties(&self, properties: &mut Properties) {
self.params.add_properties(properties);
}

pub fn create_effect<'a>(shader_path: &PathBuf, shader_source: &str, graphics_context: &'a GraphicsContext) -> Result<(GraphicsContextDependentEnabled<'a, GraphicsEffect>, PreprocessResult), Cow<'static, str>> {
const EFFECT_SOURCE_TEMPLATE: &'static str = include_str!("../effect_template.effect");

let (preprocess_result, effect_source) = {
let pattern = Regex::new(r"(?P<shader>__SHADER__)").unwrap();
let effect_source = pattern.replace_all(EFFECT_SOURCE_TEMPLATE, shader_source);

let (preprocess_result, effect_source) = preprocess(&effect_source);

(preprocess_result, effect_source.into_owned())
};

let shader_path_c = CString::new(
shader_path.to_str().ok_or_else(|| {
"Specified shader path is not a valid UTF-8 string."
})?
).map_err(|_| "Shader path cannot be converted to a C string.")?;
let effect_source_c = CString::new(effect_source.clone())
.map_err(|_| "Shader contents cannot be converted to a C string.")?;

let effect = {
let capture = LogCaptureHandler::new(LogLevel::Error).unwrap();
let result = GraphicsEffect::from_effect_string(
effect_source_c.as_c_str(),
shader_path_c.as_c_str(),
&graphics_context,
);

result.map_err(|err| {
if let Some(err) = err {
Cow::Owned(format!("Could not create the effect due to the following error: {}", err))
} else {
Cow::Owned(format!("Could not create the effect due to the following error:\n{}", capture.to_string()))
}
})
}?;

Ok((effect, preprocess_result))
}
}
Loading

0 comments on commit 52cff2b

Please sign in to comment.