1
0
Fork 0

Account for Params::deserialize_fields allocating

When state through `GuiContext`.
This commit is contained in:
Robbert van der Helm 2023-03-03 13:12:47 +01:00
parent a97c8ea554
commit a202c3801a
3 changed files with 49 additions and 30 deletions

View file

@ -2362,22 +2362,31 @@ impl<P: ClapPlugin> Wrapper<P> {
// doesn't do that // doesn't do that
let updated_state = permit_alloc(|| wrapper.updated_state_receiver.try_recv()); let updated_state = permit_alloc(|| wrapper.updated_state_receiver.try_recv());
if let Ok(mut state) = updated_state { if let Ok(mut state) = updated_state {
// FIXME: This is obviously not realtime-safe, but loading presets without doing
// this could lead to inconsistencies. It's the plugin's responsibility to
// not perform any realtime-unsafe work when the initialize function is
// called a second time if it supports runtime preset loading.
// `state::deserialize_object()` normally never allocates, but if the plugin
// has persistent non-parameter data then its `deserialize_fields()`
// implementation may still allocate.
permit_alloc(|| {
state::deserialize_object::<P>( state::deserialize_object::<P>(
&mut state, &mut state,
wrapper.params.clone(), wrapper.params.clone(),
state::make_params_getter(&wrapper.param_by_hash, &wrapper.param_id_to_hash), state::make_params_getter(
&wrapper.param_by_hash,
&wrapper.param_id_to_hash,
),
wrapper.current_buffer_config.load().as_ref(), wrapper.current_buffer_config.load().as_ref(),
); );
});
// NOTE: This needs to be dropped after the `plugin` lock to avoid deadlocks // NOTE: This needs to be dropped after the `plugin` lock to avoid deadlocks
let mut init_context = wrapper.make_init_context(); let mut init_context = wrapper.make_init_context();
let audio_io_layout = wrapper.current_audio_io_layout.load(); let audio_io_layout = wrapper.current_audio_io_layout.load();
let buffer_config = wrapper.current_buffer_config.load().unwrap(); let buffer_config = wrapper.current_buffer_config.load().unwrap();
let mut plugin = wrapper.plugin.lock(); let mut plugin = wrapper.plugin.lock();
// FIXME: This is obviously not realtime-safe, but loading presets without doing // See above
// this could lead to inconsistencies. It's the plugin's responsibility to
// not perform any realtime-unsafe work when the initialize function is
// called a second time if it supports runtime preset loading.
permit_alloc(|| { permit_alloc(|| {
plugin.initialize(&audio_io_layout, &buffer_config, &mut init_context) plugin.initialize(&audio_io_layout, &buffer_config, &mut init_context)
}); });

View file

@ -515,20 +515,24 @@ impl<P: Plugin, B: Backend<P>> Wrapper<P, B> {
// alternative that doesn't do that // alternative that doesn't do that
let updated_state = permit_alloc(|| self.updated_state_receiver.try_recv()); let updated_state = permit_alloc(|| self.updated_state_receiver.try_recv());
if let Ok(mut state) = updated_state { if let Ok(mut state) = updated_state {
unsafe { // FIXME: This is obviously not realtime-safe, but loading presets without
// doing this could lead to inconsistencies. It's the plugin's
// responsibility to not perform any realtime-unsafe work when the
// initialize function is called a second time if it supports
// runtime preset loading. `state::deserialize_object()` normally
// never allocates, but if the plugin has persistent non-parameter
// data then its `deserialize_fields()` implementation may still
// allocate.
permit_alloc(|| unsafe {
state::deserialize_object::<P>( state::deserialize_object::<P>(
&mut state, &mut state,
self.params.clone(), self.params.clone(),
|param_id| self.param_id_to_ptr.get(param_id).copied(), |param_id| self.param_id_to_ptr.get(param_id).copied(),
Some(&self.buffer_config), Some(&self.buffer_config),
); );
} });
// FIXME: This is obviously not realtime-safe, but loading presets without // See above
// doing this could lead to inconsistencies. It's the plugin's
// responsibility to not perform any realtime-unsafe work when the
// initialize function is called a second time if it supports
// runtime preset loading.
permit_alloc(|| { permit_alloc(|| {
plugin.initialize( plugin.initialize(
&self.audio_io_layout, &self.audio_io_layout,

View file

@ -1795,6 +1795,14 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
// doesn't do that // doesn't do that
let updated_state = permit_alloc(|| self.inner.updated_state_receiver.try_recv()); let updated_state = permit_alloc(|| self.inner.updated_state_receiver.try_recv());
if let Ok(mut state) = updated_state { if let Ok(mut state) = updated_state {
// FIXME: This is obviously not realtime-safe, but loading presets without doing
// this could lead to inconsistencies. It's the plugin's responsibility to
// not perform any realtime-unsafe work when the initialize function is
// called a second time if it supports runtime preset loading.
// `state::deserialize_object()` normally never allocates, but if the plugin
// has persistent non-parameter data then its `deserialize_fields()`
// implementation may still allocate.
permit_alloc(|| {
state::deserialize_object::<P>( state::deserialize_object::<P>(
&mut state, &mut state,
self.inner.params.clone(), self.inner.params.clone(),
@ -1804,16 +1812,14 @@ impl<P: Vst3Plugin> IAudioProcessor for Wrapper<P> {
), ),
self.inner.current_buffer_config.load().as_ref(), self.inner.current_buffer_config.load().as_ref(),
); );
});
// NOTE: This needs to be dropped after the `plugin` lock to avoid deadlocks // NOTE: This needs to be dropped after the `plugin` lock to avoid deadlocks
let mut init_context = self.inner.make_init_context(); let mut init_context = self.inner.make_init_context();
let audio_io_layout = self.inner.current_audio_io_layout.load(); let audio_io_layout = self.inner.current_audio_io_layout.load();
let buffer_config = self.inner.current_buffer_config.load().unwrap(); let buffer_config = self.inner.current_buffer_config.load().unwrap();
let mut plugin = self.inner.plugin.lock(); let mut plugin = self.inner.plugin.lock();
// FIXME: This is obviously not realtime-safe, but loading presets without doing // See above
// this could lead to inconsistencies. It's the plugin's responsibility to
// not perform any realtime-unsafe work when the initialize function is
// called a second time if it supports runtime preset loading.
permit_alloc(|| { permit_alloc(|| {
plugin.initialize(&audio_io_layout, &buffer_config, &mut init_context) plugin.initialize(&audio_io_layout, &buffer_config, &mut init_context)
}); });