From 456655b26998268c63266b4376cc146f40b78742 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sun, 30 Oct 2022 14:15:54 +0100 Subject: [PATCH] Use the clap_plugin::plugin_data field Instead of relying on the struct layout and doing raw pointer casts. We still need to do this for the CLAP plugin factory though. --- src/wrapper/clap/factory.rs | 7 +- src/wrapper/clap/wrapper.rs | 194 ++++++++++++++++++------------------ 2 files changed, 103 insertions(+), 98 deletions(-) diff --git a/src/wrapper/clap/factory.rs b/src/wrapper/clap/factory.rs index b05fa039..e6f408e5 100644 --- a/src/wrapper/clap/factory.rs +++ b/src/wrapper/clap/factory.rs @@ -15,7 +15,8 @@ use crate::plugin::ClapPlugin; #[doc(hidden)] #[repr(C)] pub struct Factory { - // Keep the vtable as the first field so we can do a simple pointer cast + // Keep the vtable as the first field so we can do a simple pointer cast. There's no data + // pointer as the API expects this thing to be entirely static, which in our case it isn't. pub clap_plugin_factory: clap_plugin_factory, plugin_descriptor: PluginDescriptor

, @@ -64,7 +65,9 @@ impl Factory

{ // Arc does not have a convenient leak function like Box, so this gets a bit awkward // This pointer gets turned into an Arc and its reference count decremented in // [Wrapper::destroy()] - &(*Arc::into_raw(Wrapper::

::new(host))).clap_plugin + (*Arc::into_raw(Wrapper::

::new(host))) + .clap_plugin + .as_ptr() } else { ptr::null() } diff --git a/src/wrapper/clap/wrapper.rs b/src/wrapper/clap/wrapper.rs index c0038fb1..b8dac2cc 100644 --- a/src/wrapper/clap/wrapper.rs +++ b/src/wrapper/clap/wrapper.rs @@ -97,11 +97,7 @@ use crate::wrapper::util::{hash_param_id, process_wrapper, strlcpy}; /// more than this many parameters at a time will cause changes to get lost. const OUTPUT_EVENT_QUEUE_CAPACITY: usize = 2048; -#[repr(C)] pub struct Wrapper { - // Keep the vtable as the first field so we can do a simple pointer cast - pub clap_plugin: clap_plugin, - /// A reference to this object, upgraded to an `Arc` for the GUI context. this: AtomicRefCell>, @@ -178,10 +174,6 @@ pub struct Wrapper { /// The receiver belonging to [`new_state_sender`][Self::new_state_sender]. updated_state_receiver: channel::Receiver, - /// Needs to be boxed because the plugin object is supposed to contain a static reference to - /// this. - plugin_descriptor: Box>, - // We'll query all of the host's extensions upfront host_callback: ClapPtr, @@ -195,6 +187,13 @@ pub struct Wrapper { /// TODO: Support surround setups once a plugin needs that supported_bus_configs: Vec, + // The main `clap_plugin` vtable. A pointer to this `Wrapper

` instance is stored in the + // `plugin_data` field. This pointer is set after creating the `Arc>`. + pub clap_plugin: AtomicRefCell, + /// Needs to be boxed because the plugin object is supposed to contain a static reference to + /// this. + _plugin_descriptor: Box>, + clap_plugin_audio_ports: clap_plugin_audio_ports, clap_plugin_gui: clap_plugin_gui, @@ -540,27 +539,6 @@ impl Wrapper

{ } let wrapper = Self { - clap_plugin: clap_plugin { - // This needs to live on the heap because the plugin object contains a direct - // reference to the manifest as a value. We could share this between instances of - // the plugin using an `Arc`, but this doesn't consume a lot of memory so it's not a - // huge deal. - desc: plugin_descriptor.clap_plugin_descriptor(), - // We already need to use pointer casts in the factory, so might as well continue - // doing that here - plugin_data: ptr::null_mut(), - init: Some(Self::init), - destroy: Some(Self::destroy), - activate: Some(Self::activate), - deactivate: Some(Self::deactivate), - start_processing: Some(Self::start_processing), - stop_processing: Some(Self::stop_processing), - reset: Some(Self::reset), - process: Some(Self::process), - get_extension: Some(Self::get_extension), - on_main_thread: Some(Self::on_main_thread), - }, - this: AtomicRefCell::new(Weak::new()), plugin: Mutex::new(plugin), @@ -591,10 +569,29 @@ impl Wrapper

{ updated_state_sender, updated_state_receiver, - plugin_descriptor, - host_callback, + clap_plugin: AtomicRefCell::new(clap_plugin { + // This needs to live on the heap because the plugin object contains a direct + // reference to the manifest as a value. We could share this between instances of + // the plugin using an `Arc`, but this doesn't consume a lot of memory so it's not a + // huge deal. + desc: plugin_descriptor.clap_plugin_descriptor(), + // This pointer will be set to point at our wrapper instance later + plugin_data: ptr::null_mut(), + init: Some(Self::init), + destroy: Some(Self::destroy), + activate: Some(Self::activate), + deactivate: Some(Self::deactivate), + start_processing: Some(Self::start_processing), + stop_processing: Some(Self::stop_processing), + reset: Some(Self::reset), + process: Some(Self::process), + get_extension: Some(Self::get_extension), + on_main_thread: Some(Self::on_main_thread), + }), + _plugin_descriptor: plugin_descriptor, + clap_plugin_audio_ports_config: clap_plugin_audio_ports_config { count: Some(Self::ext_audio_ports_config_count), get: Some(Self::ext_audio_ports_config_get), @@ -696,6 +693,10 @@ impl Wrapper

{ let wrapper = Arc::new(wrapper); *wrapper.this.borrow_mut() = Arc::downgrade(&wrapper); + // The `clap_plugin::plugin_data` field needs to point to this wrapper so we can access it + // from the vtable functions + wrapper.clap_plugin.borrow_mut().plugin_data = Arc::as_ptr(&wrapper) as *mut _; + // The editor also needs to be initialized later so the Async executor can work. *wrapper.editor.borrow_mut() = wrapper .plugin @@ -1714,8 +1715,8 @@ impl Wrapper

{ } unsafe extern "C" fn init(plugin: *const clap_plugin) -> bool { - check_null_ptr!(false, plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); // We weren't allowed to query these in the constructor, so we need to do it now instead. *wrapper.host_gui.borrow_mut() = @@ -1737,7 +1738,8 @@ impl Wrapper

{ } unsafe extern "C" fn destroy(plugin: *const clap_plugin) { - drop(Arc::from_raw(plugin as *mut Self)); + assert!(!plugin.is_null() && !(*plugin).plugin_data.is_null()); + drop(Arc::from_raw((*plugin).plugin_data as *mut Self)); } unsafe extern "C" fn activate( @@ -1746,8 +1748,8 @@ impl Wrapper

{ min_frames_count: u32, max_frames_count: u32, ) -> bool { - check_null_ptr!(false, plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); let bus_config = wrapper.current_bus_config.load(); let buffer_config = BufferConfig { @@ -1833,8 +1835,8 @@ impl Wrapper

{ } unsafe extern "C" fn deactivate(plugin: *const clap_plugin) { - check_null_ptr!((), plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!((), plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); wrapper.plugin.lock().deactivate(); } @@ -1842,8 +1844,8 @@ impl Wrapper

{ unsafe extern "C" fn start_processing(plugin: *const clap_plugin) -> bool { // We just need to keep track of our processing state so we can request a flush when // updating parameters from the GUI while the processing loop isn't running - check_null_ptr!(false, plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); // Always reset the processing status when the plugin gets activated or deactivated wrapper.last_process_status.store(ProcessStatus::Normal); @@ -1857,15 +1859,15 @@ impl Wrapper

{ } unsafe extern "C" fn stop_processing(plugin: *const clap_plugin) { - check_null_ptr!((), plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!((), plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); wrapper.is_processing.store(false, Ordering::SeqCst); } unsafe extern "C" fn reset(plugin: *const clap_plugin) { - check_null_ptr!((), plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!((), plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); process_wrapper(|| wrapper.plugin.lock().reset()); } @@ -1874,8 +1876,8 @@ impl Wrapper

{ plugin: *const clap_plugin, process: *const clap_process, ) -> clap_process_status { - check_null_ptr!(CLAP_PROCESS_ERROR, plugin, process); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(CLAP_PROCESS_ERROR, plugin, (*plugin).plugin_data, process); + let wrapper = &*((*plugin).plugin_data as *const Self); // Panic on allocations if the `assert_process_allocs` feature has been enabled, and make // sure that FTZ is set up correctly @@ -2340,8 +2342,8 @@ impl Wrapper

{ plugin: *const clap_plugin, id: *const c_char, ) -> *const c_void { - check_null_ptr!(ptr::null(), plugin, id); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(ptr::null(), plugin, (*plugin).plugin_data, id); + let wrapper = &*((*plugin).plugin_data as *const Self); let id = CStr::from_ptr(id); @@ -2375,8 +2377,8 @@ impl Wrapper

{ } unsafe extern "C" fn on_main_thread(plugin: *const clap_plugin) { - check_null_ptr!((), plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!((), plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); // [Self::schedule_gui] posts a task to the queue and asks the host to call this function // on the main thread, so once that's done we can just handle all requests here @@ -2386,8 +2388,8 @@ impl Wrapper

{ } unsafe extern "C" fn ext_audio_ports_config_count(plugin: *const clap_plugin) -> u32 { - check_null_ptr!(0, plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(0, plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); wrapper.supported_bus_configs.len() as u32 } @@ -2397,8 +2399,8 @@ impl Wrapper

{ index: u32, config: *mut clap_audio_ports_config, ) -> bool { - check_null_ptr!(false, plugin, config); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data, config); + let wrapper = &*((*plugin).plugin_data as *const Self); match wrapper.supported_bus_configs.get(index as usize) { Some(bus_config) => { @@ -2471,8 +2473,8 @@ impl Wrapper

{ plugin: *const clap_plugin, config_id: clap_id, ) -> bool { - check_null_ptr!(false, plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); // We use the vector indices for the config ID match wrapper.supported_bus_configs.get(config_id as usize) { @@ -2493,8 +2495,8 @@ impl Wrapper

{ } unsafe extern "C" fn ext_audio_ports_count(plugin: *const clap_plugin, is_input: bool) -> u32 { - check_null_ptr!(0, plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(0, plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); let bus_config = wrapper.current_bus_config.load(); if is_input { @@ -2524,8 +2526,8 @@ impl Wrapper

{ is_input: bool, info: *mut clap_audio_port_info, ) -> bool { - check_null_ptr!(false, plugin, info); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data, info); + let wrapper = &*((*plugin).plugin_data as *const Self); let num_input_ports = Self::ext_audio_ports_count(plugin, true); let num_output_ports = Self::ext_audio_ports_count(plugin, false); @@ -2699,8 +2701,8 @@ impl Wrapper

{ // In CLAP creating the editor window and embedding it in another window are separate, and // those things are one and the same in our framework. So we'll just pretend we did // something here. - check_null_ptr!(false, plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); let editor_handle = wrapper.editor_handle.lock(); if editor_handle.is_none() { @@ -2712,8 +2714,8 @@ impl Wrapper

{ } unsafe extern "C" fn ext_gui_destroy(plugin: *const clap_plugin) { - check_null_ptr!((), plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!((), plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); let mut editor_handle = wrapper.editor_handle.lock(); if editor_handle.is_some() { @@ -2724,8 +2726,8 @@ impl Wrapper

{ } unsafe extern "C" fn ext_gui_set_scale(plugin: *const clap_plugin, scale: f64) -> bool { - check_null_ptr!(false, plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); // On macOS scaling is done by the OS, and all window sizes are in logical pixels if cfg!(target_os = "macos") { @@ -2755,8 +2757,8 @@ impl Wrapper

{ width: *mut u32, height: *mut u32, ) -> bool { - check_null_ptr!(false, plugin, width, height); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data, width, height); + let wrapper = &*((*plugin).plugin_data as *const Self); // For macOS the scaling factor is always 1 let (unscaled_width, unscaled_height) = @@ -2799,8 +2801,8 @@ impl Wrapper

{ ) -> bool { // TODO: Implement Host->Plugin GUI resizing // TODO: The host will also call this if an asynchronous (on Linux) resize request fails - check_null_ptr!(false, plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); let (unscaled_width, unscaled_height) = wrapper.editor.borrow().as_ref().unwrap().lock().size(); @@ -2817,9 +2819,9 @@ impl Wrapper

{ plugin: *const clap_plugin, window: *const clap_window, ) -> bool { - check_null_ptr!(false, plugin, window); + check_null_ptr!(false, plugin, (*plugin).plugin_data, window); // For this function we need the underlying Arc so we can pass it to the editor - let wrapper = Arc::from_raw(plugin as *const Self); + let wrapper = Arc::from_raw((*plugin).plugin_data as *const Self); let window = &*window; @@ -2890,8 +2892,8 @@ impl Wrapper

{ } unsafe extern "C" fn ext_latency_get(plugin: *const clap_plugin) -> u32 { - check_null_ptr!(0, plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(0, plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); wrapper.current_latency.load(Ordering::SeqCst) } @@ -2945,8 +2947,8 @@ impl Wrapper

{ } unsafe extern "C" fn ext_params_count(plugin: *const clap_plugin) -> u32 { - check_null_ptr!(0, plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(0, plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); wrapper.param_hashes.len() as u32 } @@ -2956,8 +2958,8 @@ impl Wrapper

{ param_index: u32, param_info: *mut clap_param_info, ) -> bool { - check_null_ptr!(false, plugin, param_info); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data, param_info); + let wrapper = &*((*plugin).plugin_data as *const Self); if param_index > Self::ext_params_count(plugin) { return false; @@ -3017,8 +3019,8 @@ impl Wrapper

{ param_id: clap_id, value: *mut f64, ) -> bool { - check_null_ptr!(false, plugin, value); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data, value); + let wrapper = &*((*plugin).plugin_data as *const Self); match wrapper.param_by_hash.get(¶m_id) { Some(param_ptr) => { @@ -3038,8 +3040,8 @@ impl Wrapper

{ display: *mut c_char, size: u32, ) -> bool { - check_null_ptr!(false, plugin, display); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data, display); + let wrapper = &*((*plugin).plugin_data as *const Self); let dest = std::slice::from_raw_parts_mut(display, size as usize); @@ -3066,8 +3068,8 @@ impl Wrapper

{ display: *const c_char, value: *mut f64, ) -> bool { - check_null_ptr!(false, plugin, display, value); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data, display, value); + let wrapper = &*((*plugin).plugin_data as *const Self); let display = match CStr::from_ptr(display).to_str() { Ok(s) => s, @@ -3093,8 +3095,8 @@ impl Wrapper

{ in_: *const clap_input_events, out: *const clap_output_events, ) { - check_null_ptr!((), plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!((), plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); if !in_.is_null() { wrapper.handle_in_events(&*in_, 0); @@ -3115,8 +3117,8 @@ impl Wrapper

{ plugin: *const clap_plugin, mode: clap_plugin_render_mode, ) -> bool { - check_null_ptr!(false, plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); let mode = match mode { CLAP_RENDER_REALTIME => ProcessMode::Realtime, @@ -3136,8 +3138,8 @@ impl Wrapper

{ plugin: *const clap_plugin, stream: *const clap_ostream, ) -> bool { - check_null_ptr!(false, plugin, stream); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data, stream); + let wrapper = &*((*plugin).plugin_data as *const Self); let serialized = state::serialize_json::

( wrapper.params.clone(), @@ -3176,8 +3178,8 @@ impl Wrapper

{ plugin: *const clap_plugin, stream: *const clap_istream, ) -> bool { - check_null_ptr!(false, plugin, stream); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data, stream); + let wrapper = &*((*plugin).plugin_data as *const Self); // CLAP does not have a way to tell how much data there is left in a stream, so we've // prepended the size in front of our JSON state @@ -3232,8 +3234,8 @@ impl Wrapper

{ } unsafe extern "C" fn ext_tail_get(plugin: *const clap_plugin) -> u32 { - check_null_ptr!(0, plugin); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(0, plugin, (*plugin).plugin_data); + let wrapper = &*((*plugin).plugin_data as *const Self); match wrapper.last_process_status.load() { ProcessStatus::Tail(samples) => samples, @@ -3246,8 +3248,8 @@ impl Wrapper

{ plugin: *const clap_plugin, info: *mut clap_voice_info, ) -> bool { - check_null_ptr!(false, plugin, info); - let wrapper = &*(plugin as *const Self); + check_null_ptr!(false, plugin, (*plugin).plugin_data, info); + let wrapper = &*((*plugin).plugin_data as *const Self); match P::CLAP_POLY_MODULATION_CONFIG { Some(config) => {