Make sure FTZ is always enabled
This commit is contained in:
parent
dfedd7b2c4
commit
e642fb5ff8
|
@ -118,7 +118,6 @@ impl Plugin for Gain {
|
|||
}
|
||||
|
||||
fn process(&mut self, buffer: &mut Buffer, _context: &dyn ProcessContext) -> ProcessStatus {
|
||||
// TODO: The wrapper should set FTZ if not yet enabled, mention ths in the process fuctnion
|
||||
for samples in buffer.iter_mut() {
|
||||
// Smoothing is optionally built into the parameters themselves
|
||||
let gain = self.params.gain.smoothed.next();
|
||||
|
|
|
@ -93,7 +93,6 @@ pub trait Plugin: Default + Send + Sync {
|
|||
///
|
||||
/// TODO: Provide a way to access auxiliary input channels if the IO configuration is
|
||||
/// assymetric
|
||||
/// TODO: Handle FTZ stuff on the wrapper side and mention that this has been handled
|
||||
/// TODO: Pass transport and other context information to the plugin
|
||||
fn process(&mut self, buffer: &mut Buffer, context: &dyn ProcessContext) -> ProcessStatus;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use std::cmp;
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_char;
|
||||
use vst3_sys::vst::TChar;
|
||||
use widestring::U16CString;
|
||||
|
@ -92,6 +93,9 @@ pub fn u16strlcpy(dest: &mut [TChar], src: &str) {
|
|||
/// `assert_no_alloc` if needed, while also making sure that things like FTZ are set up correctly if
|
||||
/// the host has not already done so.
|
||||
pub fn process_wrapper<T, F: FnOnce() -> T>(f: F) -> T {
|
||||
// Make sure FTZ is always enabled, even if the host doesn't do it for us
|
||||
let _ftz_guard = ScopedFtz::enable();
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(debug_assertions, feature = "assert_process_allocs"))] {
|
||||
assert_no_alloc::assert_no_alloc(f)
|
||||
|
@ -100,3 +104,54 @@ pub fn process_wrapper<T, F: FnOnce() -> T>(f: F) -> T {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable the CPU's Flush To Zero flag while this object is in scope. If the flag was not already
|
||||
/// set, it will be restored to its old value when this gets dropped.
|
||||
struct ScopedFtz {
|
||||
/// The old FTZ mode to restore to, if FTZ was not already set.
|
||||
old_ftz_mode: Option<u32>,
|
||||
/// We can't directly implement !Send and !Sync, but this will do the same thing. This object
|
||||
/// affects the current thread's floating point registers, so it may only be dropped on the
|
||||
/// current thread.
|
||||
send_sync_marker: PhantomData<*const ()>,
|
||||
}
|
||||
|
||||
impl ScopedFtz {
|
||||
fn enable() -> Self {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_feature = "sse")] {
|
||||
let mode = unsafe { std::arch::x86_64::_MM_GET_FLUSH_ZERO_MODE() };
|
||||
if mode != std::arch::x86_64::_MM_FLUSH_ZERO_ON {
|
||||
unsafe { std::arch::x86_64::_MM_SET_FLUSH_ZERO_MODE(std::arch::x86_64::_MM_FLUSH_ZERO_ON) };
|
||||
|
||||
Self {
|
||||
old_ftz_mode: Some(mode),
|
||||
send_sync_marker: PhantomData,
|
||||
}
|
||||
} else {
|
||||
Self {
|
||||
old_ftz_mode: None,
|
||||
send_sync_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Self {
|
||||
old_ftz_mode: None,
|
||||
send_sync_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ScopedFtz {
|
||||
fn drop(&mut self) {
|
||||
if let Some(mode) = self.old_ftz_mode {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_feature = "sse")] {
|
||||
unsafe { std::arch::x86_64::_MM_SET_FLUSH_ZERO_MODE(mode) };
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue