From c7186de881311d5fc67cc7609708d0258a4cfeb9 Mon Sep 17 00:00:00 2001 From: Otto Date: Thu, 1 Jun 2023 09:19:57 +0200 Subject: [PATCH 1/2] Remove hardcoded RENDER_QUANTUM_SIZE from Allocator --- src/context/offline.rs | 4 +-- src/context/online.rs | 2 +- src/param.rs | 4 +-- src/render/graph.rs | 11 +++++---- src/render/quantum.rs | 56 ++++++++++++++++++++++++------------------ src/render/thread.rs | 1 + 6 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/context/offline.rs b/src/context/offline.rs index d4781d4e..eea43a8a 100644 --- a/src/context/offline.rs +++ b/src/context/offline.rs @@ -2,10 +2,10 @@ use std::sync::atomic::AtomicU64; use std::sync::Arc; -use crate::assert_valid_sample_rate; use crate::buffer::AudioBuffer; use crate::context::{BaseAudioContext, ConcreteBaseAudioContext}; use crate::render::RenderThread; +use crate::{assert_valid_sample_rate, RENDER_QUANTUM_SIZE}; /// The `OfflineAudioContext` doesn't render the audio to the device hardware; instead, it generates /// it, as fast as it can, and outputs the result to an `AudioBuffer`. @@ -66,7 +66,7 @@ impl OfflineAudioContext { // communication channel to the render thread let (sender, receiver) = crossbeam_channel::unbounded(); - let graph = crate::render::graph::Graph::new(); + let graph = crate::render::graph::Graph::new(RENDER_QUANTUM_SIZE); let message = crate::message::ControlMessage::Startup { graph }; sender.send(message).unwrap(); diff --git a/src/context/online.rs b/src/context/online.rs index e0542c2d..43714c31 100644 --- a/src/context/online.rs +++ b/src/context/online.rs @@ -170,7 +170,7 @@ impl AudioContext { event_recv, } = control_thread_init; - let graph = crate::render::graph::Graph::new(); + let graph = crate::render::graph::Graph::new(crate::RENDER_QUANTUM_SIZE); let message = crate::message::ControlMessage::Startup { graph }; ctrl_msg_send.send(message).unwrap(); diff --git a/src/param.rs b/src/param.rs index 3299b3ed..4e334f34 100644 --- a/src/param.rs +++ b/src/param.rs @@ -3215,7 +3215,7 @@ mod tests { #[test] fn test_varying_param_size_modulated() { - let alloc = Alloc::with_capacity(1); + let alloc = Alloc::new(RENDER_QUANTUM_SIZE, 1); // buffer length is 1 and input is silence (no modulation) { @@ -3282,7 +3282,7 @@ mod tests { #[test] fn test_full_render_chain() { - let alloc = Alloc::with_capacity(1); + let alloc = Alloc::new(RENDER_QUANTUM_SIZE, 1); // prevent regression between the different processing stage let context = OfflineAudioContext::new(1, 0, 48000.); diff --git a/src/render/graph.rs b/src/render/graph.rs index 93781033..55628798 100644 --- a/src/render/graph.rs +++ b/src/render/graph.rs @@ -92,7 +92,7 @@ pub(crate) struct Graph { } impl Graph { - pub fn new() -> Self { + pub fn new(buffer_size: usize) -> Self { Graph { nodes: FxHashMap::default(), ordered: vec![], @@ -100,7 +100,7 @@ impl Graph { marked_temp: vec![], in_cycle: vec![], cycle_breakers: vec![], - alloc: Alloc::with_capacity(64), + alloc: Alloc::new(buffer_size, 64), } } @@ -471,6 +471,7 @@ impl Graph { #[cfg(test)] mod tests { use super::*; + use crate::RENDER_QUANTUM_SIZE; #[derive(Debug, Clone)] struct TestNode {} @@ -498,7 +499,7 @@ mod tests { #[test] fn test_add_remove() { - let mut graph = Graph::new(); + let mut graph = Graph::new(RENDER_QUANTUM_SIZE); let node = Box::new(TestNode {}); graph.add_node(AudioNodeId(0), node.clone(), 1, 1, config()); @@ -549,7 +550,7 @@ mod tests { #[test] fn test_remove_all() { - let mut graph = Graph::new(); + let mut graph = Graph::new(RENDER_QUANTUM_SIZE); let node = Box::new(TestNode {}); graph.add_node(AudioNodeId(0), node.clone(), 1, 1, config()); @@ -588,7 +589,7 @@ mod tests { #[test] fn test_cycle() { - let mut graph = Graph::new(); + let mut graph = Graph::new(RENDER_QUANTUM_SIZE); let node = Box::new(TestNode {}); graph.add_node(AudioNodeId(0), node.clone(), 1, 1, config()); diff --git a/src/render/quantum.rs b/src/render/quantum.rs index 5bc023f8..cac5caf6 100644 --- a/src/render/quantum.rs +++ b/src/render/quantum.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use crate::node::{ChannelConfig, ChannelCountMode, ChannelInterpretation}; use crate::assert_valid_number_of_channels; -use crate::{MAX_CHANNELS, RENDER_QUANTUM_SIZE}; +use crate::MAX_CHANNELS; // object pool for `AudioRenderQuantumChannel`s, only allocate if the pool is empty pub(crate) struct Alloc { @@ -15,16 +15,19 @@ pub(crate) struct Alloc { #[derive(Debug)] struct AllocInner { - pool: RefCell>>, - zeroes: Rc<[f32; RENDER_QUANTUM_SIZE]>, + buffer_size: usize, + pool: RefCell>>, + zeroes: Rc<[f32]>, } impl Alloc { - pub fn with_capacity(n: usize) -> Self { - let pool: Vec<_> = (0..n).map(|_| Rc::new([0.; RENDER_QUANTUM_SIZE])).collect(); - let zeroes = Rc::new([0.; RENDER_QUANTUM_SIZE]); + pub fn new(buffer_size: usize, capacity: usize) -> Self { + let array = vec![0.; buffer_size]; + let pool: Vec<_> = (0..capacity).map(|_| Rc::from(array.as_slice())).collect(); + let zeroes = Rc::from(array); let inner = AllocInner { + buffer_size, pool: RefCell::new(pool), zeroes, }; @@ -56,17 +59,18 @@ impl Alloc { } impl AllocInner { - fn allocate(&self) -> Rc<[f32; RENDER_QUANTUM_SIZE]> { + fn allocate(&self) -> Rc<[f32]> { if let Some(rc) = self.pool.borrow_mut().pop() { // re-use from pool rc } else { // allocate - Rc::new([0.; RENDER_QUANTUM_SIZE]) + let array = vec![0.; self.buffer_size]; + Rc::from(array.as_slice()) } } - fn push(&self, data: Rc<[f32; RENDER_QUANTUM_SIZE]>) { + fn push(&self, data: Rc<[f32]>) { self.pool .borrow_mut() // infallible when single threaded .push(data); @@ -96,19 +100,21 @@ impl AllocInner { /// ``` #[derive(Clone, Debug)] pub struct AudioRenderQuantumChannel { - data: Rc<[f32; RENDER_QUANTUM_SIZE]>, + data: Rc<[f32]>, alloc: Rc, } impl AudioRenderQuantumChannel { - fn make_mut(&mut self) -> &mut [f32; RENDER_QUANTUM_SIZE] { + fn make_mut(&mut self) -> &mut [f32] { if Rc::strong_count(&self.data) != 1 { let mut new = self.alloc.allocate(); - Rc::make_mut(&mut new).copy_from_slice(self.data.deref()); + Rc::get_mut(&mut new) + .unwrap() + .copy_from_slice(self.data.deref()); self.data = new; } - Rc::make_mut(&mut self.data) + Rc::get_mut(&mut self.data).unwrap() } /// `O(1)` check if this buffer is equal to the 'silence buffer' @@ -141,7 +147,7 @@ impl Deref for AudioRenderQuantumChannel { type Target = [f32]; fn deref(&self) -> &Self::Target { - self.data.as_slice() + &self.data[..] } } @@ -674,10 +680,12 @@ mod tests { use super::*; + use crate::RENDER_QUANTUM_SIZE; + #[test] fn test_pool() { // Create pool of size 2 - let alloc = Alloc::with_capacity(2); + let alloc = Alloc::new(RENDER_QUANTUM_SIZE, 2); assert_eq!(alloc.pool_size(), 2); alloc_counter::deny_alloc(|| { @@ -755,7 +763,7 @@ mod tests { #[test] fn test_silence() { - let alloc = Alloc::with_capacity(1); + let alloc = Alloc::new(RENDER_QUANTUM_SIZE, 1); let silence = alloc.silence(); assert_float_eq!(&silence[..], &[0.; RENDER_QUANTUM_SIZE][..], abs_all <= 0.); @@ -784,7 +792,7 @@ mod tests { #[test] fn test_channel_add() { - let alloc = Alloc::with_capacity(1); + let alloc = Alloc::new(RENDER_QUANTUM_SIZE, 1); let silence = alloc.silence(); let mut signal1 = alloc.silence(); @@ -809,7 +817,7 @@ mod tests { #[test] fn test_audiobuffer_channels() { - let alloc = Alloc::with_capacity(1); + let alloc = Alloc::new(RENDER_QUANTUM_SIZE, 1); let silence = alloc.silence(); let buffer = AudioRenderQuantum::from(silence); @@ -826,7 +834,7 @@ mod tests { #[test] fn test_audiobuffer_mix_discrete() { - let alloc = Alloc::with_capacity(1); + let alloc = Alloc::new(RENDER_QUANTUM_SIZE, 1); let mut signal = alloc.silence(); signal.copy_from_slice(&[1.; RENDER_QUANTUM_SIZE]); @@ -868,7 +876,7 @@ mod tests { #[test] fn test_audiobuffer_upmix_speakers() { - let alloc = Alloc::with_capacity(1); + let alloc = Alloc::new(RENDER_QUANTUM_SIZE, 1); { // 1 -> 2 @@ -1274,7 +1282,7 @@ mod tests { #[test] fn test_audiobuffer_downmix_speakers() { - let alloc = Alloc::with_capacity(1); + let alloc = Alloc::new(RENDER_QUANTUM_SIZE, 1); { // 2 -> 1 @@ -1626,7 +1634,7 @@ mod tests { #[test] fn test_audiobuffer_add() { - let alloc = Alloc::with_capacity(1); + let alloc = Alloc::new(RENDER_QUANTUM_SIZE, 1); let mut signal = alloc.silence(); signal.copy_from_slice(&[1.; RENDER_QUANTUM_SIZE]); @@ -1661,7 +1669,7 @@ mod tests { #[test] fn test_is_silent_quantum() { - let alloc = Alloc::with_capacity(1); + let alloc = Alloc::new(RENDER_QUANTUM_SIZE, 1); // create 2 channel silent buffer let signal = alloc.silence(); @@ -1684,7 +1692,7 @@ mod tests { #[test] fn test_is_not_silent_quantum() { - let alloc = Alloc::with_capacity(1); + let alloc = Alloc::new(RENDER_QUANTUM_SIZE, 1); // create 2 channel silent buffer let mut signal = alloc.silence(); diff --git a/src/render/thread.rs b/src/render/thread.rs index 14514388..17b5e5db 100644 --- a/src/render/thread.rs +++ b/src/render/thread.rs @@ -177,6 +177,7 @@ impl RenderThread { } pub fn render + Clone>(&mut self, buffer: &mut [S]) { + dbg!("buffer len {}", buffer.len()); // collect timing information let render_start = Instant::now(); From 736d26ce31b10c29722f02ab0c497710f32eec01 Mon Sep 17 00:00:00 2001 From: Otto Date: Thu, 1 Jun 2023 20:05:49 +0200 Subject: [PATCH 2/2] Remove debugging statement --- src/render/thread.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/render/thread.rs b/src/render/thread.rs index 17b5e5db..14514388 100644 --- a/src/render/thread.rs +++ b/src/render/thread.rs @@ -177,7 +177,6 @@ impl RenderThread { } pub fn render + Clone>(&mut self, buffer: &mut [S]) { - dbg!("buffer len {}", buffer.len()); // collect timing information let render_start = Instant::now();