Do the zeroing of the buffer in assembly

This commit is contained in:
Gwilym Kuiper 2022-06-12 17:53:39 +01:00
parent 33c948208a
commit 24749ac645
2 changed files with 29 additions and 5 deletions

View file

@ -150,13 +150,13 @@ agb_arm_func agb_rs__init_buffer
push {r4-r5}
@ zero registers r3-r5
mov r2, #constant_zero
ldr r2, =constant_zero
ldm r2, {r3-r5,r12}
1:
@ zero 4 words worth of the buffer
stmia r0, {r3-r5,r12}
subs r1, r1, #16
stmia r0!, {r3-r5,r12}
subs r1, r1, #(4 * 4)
@ loop if we haven't zeroed everything
bne 1b

View file

@ -1,4 +1,6 @@
use core::cell::RefCell;
use core::mem;
use core::mem::MaybeUninit;
use bare_metal::{CriticalSection, Mutex};
@ -27,6 +29,8 @@ extern "C" {
fn agb_rs__mixer_add_stereo(sound_data: *const u8, sound_buffer: *mut Num<i16, 4>);
fn agb_rs__mixer_collapse(sound_buffer: *mut i8, input_buffer: *const Num<i16, 4>);
fn agb_rs__init_buffer(buffer: *mut MaybeUninit<Num<i16, 4>>, size_in_bytes: usize);
}
pub struct Mixer {
@ -231,8 +235,28 @@ impl MixerBuffer {
}
fn write_channels<'a>(&mut self, channels: impl Iterator<Item = &'a mut SoundChannel>) {
let mut buffer: [Num<i16, 4>; constants::SOUND_BUFFER_SIZE * 2] =
[Num::new(0); constants::SOUND_BUFFER_SIZE * 2];
// This code is equivalent to:
// let mut buffer: [Num<i16, 4>; constants::SOUND_BUFFER_SIZE * 2] =
// [Num::new(0); constants::SOUND_BUFFER_SIZE * 2];
// but the above uses approximately 7% of the CPU time if running at 32kHz
let mut buffer: [Num<i16, 4>; constants::SOUND_BUFFER_SIZE * 2] = {
// Create an uninitialized array of `MaybeUninit`. The `assume_init` is
// safe because the type we are claiming to have initialized here is a
// bunch of `MaybeUninit`s, which do not require initialization.
let mut data: [MaybeUninit<Num<i16, 4>>; constants::SOUND_BUFFER_SIZE * 2] =
unsafe { MaybeUninit::uninit().assume_init() };
// Actually init the array (by filling it with zeros) and then transmute it (which is safe because
// we have now zeroed everything)
unsafe {
agb_rs__init_buffer(
data.as_mut_ptr(),
mem::size_of::<Num<i16, 4>>() * data.len(),
);
mem::transmute(data)
}
};
for channel in channels {
if channel.is_done {