From 1acf7142daab5d14ae0c4f564f3d84e03f53d385 Mon Sep 17 00:00:00 2001 From: Corwin Date: Sun, 2 Oct 2022 17:14:41 +0100 Subject: [PATCH] switch to using rust Rc --- agb/src/display/object.rs | 360 ++++++++++++++------------------------ 1 file changed, 136 insertions(+), 224 deletions(-) diff --git a/agb/src/display/object.rs b/agb/src/display/object.rs index d3d8b385..a2b9c250 100644 --- a/agb/src/display/object.rs +++ b/agb/src/display/object.rs @@ -1,4 +1,5 @@ #![deny(missing_docs)] +use alloc::rc::{Rc, Weak}; use alloc::vec::Vec; use core::alloc::Layout; @@ -398,6 +399,10 @@ impl Size { (self as u8 >> 2, self as u8 & 0b11) } + fn layout(self) -> Layout { + Layout::from_size_align(self.number_of_tiles() * BYTES_PER_TILE_4BPP, 8).unwrap() + } + #[must_use] /// Creates a size from width and height in pixels, panics if the width and /// height is not representable by GBA sprites. @@ -443,38 +448,9 @@ impl Size { /// counted and can be cloned to keep it in vram or otherwise manipulated. If /// objects no longer refer to this sprite, then it's vram slot is freed for the /// next sprite. This is obtained from the [ObjectController]. -pub struct SpriteBorrow<'a> { - id: SpriteId, - sprite_location: u16, - palette_location: u16, - controller: ObjectControllerReference<'a>, -} - -#[derive(Clone, Copy)] -struct Storage { - location: u16, - count: u16, -} - -impl Storage { - fn from_sprite_ptr(d: NonNull) -> Self { - Self { - location: (((d.as_ptr() as usize) - TILE_SPRITE) / BYTES_PER_TILE_4BPP) as u16, - count: 1, - } - } - fn from_palette_ptr(d: NonNull) -> Self { - Self { - location: ((d.as_ptr() as usize - PALETTE_SPRITE) / Palette16::layout().size()) as u16, - count: 1, - } - } - fn as_palette_ptr(self) -> *mut u8 { - (self.location as usize * Palette16::layout().size() + PALETTE_SPRITE) as *mut u8 - } - fn as_sprite_ptr(self) -> *mut u8 { - (self.location as usize * BYTES_PER_TILE_4BPP + TILE_SPRITE) as *mut u8 - } +#[derive(Clone)] +pub struct SpriteBorrow { + sprite: SpriteVram, } #[derive(PartialEq, Eq)] @@ -527,9 +503,56 @@ pub struct Object<'a> { loan: Loan<'a>, } +#[derive(Clone, Copy)] +struct Location(usize); + +impl Location { + fn from_sprite_ptr(d: NonNull) -> Self { + Self(((d.as_ptr() as usize) - TILE_SPRITE) / BYTES_PER_TILE_4BPP) + } + fn from_palette_ptr(d: NonNull) -> Self { + Self((d.as_ptr() as usize - PALETTE_SPRITE) / Palette16::layout().size()) + } + fn as_palette_ptr(self) -> *mut u8 { + (self.0 as usize * Palette16::layout().size() + PALETTE_SPRITE) as *mut u8 + } + fn as_sprite_ptr(self) -> *mut u8 { + (self.0 as usize * BYTES_PER_TILE_4BPP + TILE_SPRITE) as *mut u8 + } +} + +#[derive(Clone)] +struct PaletteVram(Rc); + +#[derive(Clone)] +struct SpriteVram(Rc); + +struct PaletteData { + location: Location, +} + +impl Drop for PaletteData { + fn drop(&mut self) { + unsafe { PALETTE_ALLOCATOR.dealloc(self.location.as_palette_ptr(), Palette16::layout()) }; + } +} + +struct SpriteArena { + location: Location, + size: Size, + palette: PaletteVram, +} + +impl Drop for SpriteArena { + fn drop(&mut self) { + unsafe { SPRITE_ALLOCATOR.dealloc(self.location.as_sprite_ptr(), self.size.layout()) } + } +} + +#[derive(Default)] struct SpriteControllerInner { - palette: HashMap, - sprite: HashMap, + static_palette_map: HashMap>, + static_sprite_map: HashMap>, } struct Loan<'a> { @@ -552,8 +575,8 @@ impl Drop for Loan<'_> { struct ObjectInner { attrs: Attributes, - sprite: SpriteBorrow<'static>, - previous_sprite: SpriteBorrow<'static>, + sprite: SpriteBorrow, + previous_sprite: SpriteBorrow, destroy: bool, z: i32, } @@ -620,15 +643,10 @@ impl ObjectController { .write_volatile(HIDDEN_VALUE); } - let a = unsafe { s.shadow_oam[z as usize].take().unwrap_unchecked() }; - a.previous_sprite.drop(&mut s.sprite_controller); - a.sprite.drop(&mut s.sprite_controller); + let _ = unsafe { s.shadow_oam[z as usize].take().unwrap_unchecked() }; } else { o.attrs.commit(i); - - let mut a = o.sprite.clone(&mut s.sprite_controller); - core::mem::swap(&mut o.previous_sprite, &mut a); - a.drop(&mut s.sprite_controller); + o.previous_sprite = o.sprite.clone(); } } else { unsafe { @@ -731,7 +749,7 @@ impl ObjectController { /// # } /// ``` #[must_use] - pub fn object<'a>(&'a self, sprite: SpriteBorrow<'a>) -> Object<'a> { + pub fn object(&self, sprite: SpriteBorrow) -> Object { self.try_get_object(sprite).expect("No object available") } @@ -757,28 +775,28 @@ impl ObjectController { /// # } /// ``` #[must_use] - pub fn try_get_object<'a>(&'a self, sprite: SpriteBorrow<'a>) -> Option> { + pub fn try_get_object(&self, sprite: SpriteBorrow) -> Option { let mut s = unsafe { self.inner.borrow_mut() }; let mut attrs = Attributes::new(); - attrs.a2.set_tile_index(sprite.sprite_location); - let shape_size = sprite.id.sprite().size.shape_size(); - attrs.a2.set_palete_bank(sprite.palette_location as u8); + attrs.a2.set_tile_index(sprite.sprite.0.location.0 as u16); + let shape_size = sprite.sprite.0.size.shape_size(); + attrs + .a2 + .set_palete_bank((sprite.sprite.0.palette.0.location.0) as u8); attrs.a0.set_shape(shape_size.0); attrs.a1a.set_size(shape_size.1); attrs.a1s.set_size(shape_size.1); let index = s.free_object.pop()?; - let new_sprite: SpriteBorrow<'static> = unsafe { core::mem::transmute(sprite) }; - s.shadow_oam[index as usize] = Some(ObjectInner { attrs, z: 0, - previous_sprite: new_sprite.clone(&mut s.sprite_controller), + previous_sprite: sprite.clone(), destroy: false, - sprite: new_sprite, + sprite, }); let loan = Loan { @@ -840,7 +858,7 @@ impl ObjectController { pub fn try_get_sprite(&self, sprite: &'static Sprite) -> Option { unsafe { self.inner.borrow_mut() } .sprite_controller - .try_get_sprite(sprite, self.inner) + .try_get_sprite(sprite) } } @@ -863,52 +881,24 @@ impl<'a> Object<'a> { } } - unsafe fn inner_controller( - &self, - ) -> ( - impl DerefMut + 'a, - impl DerefMut + 'a, - ) { - #[cfg(debug_assertions)] - { - core::cell::RefMut::map_split(self.loan.controller.borrow_cell_ref(), |s| { - ( - &mut s.sprite_controller, - s.shadow_oam[self.loan.index as usize] - .as_mut() - .unwrap_unchecked(), - ) - }) - } - #[cfg(not(debug_assertions))] - { - let s = self.loan.controller.borrow_direct(); - ( - &mut s.sprite_controller, - s.shadow_oam[self.loan.index as usize] - .as_mut() - .unwrap_unchecked(), - ) - } - } - /// Swaps out the current sprite. This handles changing of size, palette, /// etc. No change will be seen until [ObjectController::commit] is called. - pub fn set_sprite(&'_ mut self, sprite: SpriteBorrow<'a>) { - let (mut sprite_controller, mut object_inner) = unsafe { self.inner_controller() }; - object_inner.attrs.a2.set_tile_index(sprite.sprite_location); - let shape_size = sprite.id.sprite().size.shape_size(); + pub fn set_sprite(&'_ mut self, sprite: SpriteBorrow) { + let mut object_inner = unsafe { self.object_inner() }; object_inner .attrs .a2 - .set_palete_bank(sprite.palette_location as u8); + .set_tile_index(sprite.sprite.0.location.0 as u16); + let shape_size = sprite.sprite.0.size.shape_size(); + object_inner + .attrs + .a2 + .set_palete_bank(sprite.sprite.0.palette.0.location.0 as u8); object_inner.attrs.a0.set_shape(shape_size.0); object_inner.attrs.a1a.set_size(shape_size.1); object_inner.attrs.a1s.set_size(shape_size.1); - let mut sprite = unsafe { core::mem::transmute(sprite) }; - core::mem::swap(&mut object_inner.sprite, &mut sprite); - sprite.drop(&mut sprite_controller); + object_inner.sprite = sprite; } /// Shows the sprite. No change will be seen until @@ -1027,15 +1017,6 @@ impl<'a> Object<'a> { #[derive(Clone, Copy, PartialEq, Eq, Hash)] struct SpriteId(usize); -impl SpriteId { - fn sprite(self) -> &'static Sprite { - // # Safety - // This must be constructed using the id() of a sprite, so - // they are always valid and always static - unsafe { (self.0 as *const Sprite).as_ref().unwrap_unchecked() } - } -} - /// The palette id is a thin wrapper around the pointer to the palette in rom /// and is therefore a unique reference to a palette #[derive(Copy, Clone, PartialEq, Eq, Hash)] @@ -1076,145 +1057,76 @@ impl Sprite { } impl SpriteControllerInner { - fn try_get_sprite<'a>( - &mut self, - sprite: &'static Sprite, - controller_reference: ObjectControllerReference<'a>, - ) -> Option> { + fn try_get_sprite<'a>(&mut self, sprite: &'static Sprite) -> Option { let id = sprite.id(); - if let Some(storage) = self.sprite.get_mut(&id) { - storage.count += 1; - let location = storage.location; - let palette_location = self.palette(sprite.palette).unwrap(); - Some(SpriteBorrow { - id, - palette_location, - sprite_location: location, - controller: controller_reference, - }) - } else { - // layout is non zero sized, so this is safe to call - - let dest = unsafe { SPRITE_ALLOCATOR.alloc(sprite.layout())? }; - - let palette_location = self.palette(sprite.palette); - let palette_location = match palette_location { - Some(a) => a, - None => { - unsafe { SPRITE_ALLOCATOR.dealloc(dest.as_ptr(), sprite.layout()) } - return None; - } - }; - - unsafe { - dma::dma_copy16( - sprite.data.as_ptr().cast(), - dest.as_ptr().cast(), - sprite.data.len() / 2, - ); + if let Some(storage) = self.static_sprite_map.get_mut(&id) { + if let Some(strong) = storage.upgrade() { + return Some(SpriteBorrow { + sprite: SpriteVram(strong), + }); } - - let storage = Storage::from_sprite_ptr(dest); - self.sprite.insert(id, storage); - - Some(SpriteBorrow { - id, - palette_location, - sprite_location: storage.location, - controller: controller_reference, - }) } - } -} -impl SpriteControllerInner { + // layout is non zero sized, so this is safe to call + + let dest = unsafe { SPRITE_ALLOCATOR.alloc(sprite.layout())? }; + + let palette_location = self.palette(sprite.palette); + let palette_location = match palette_location { + Some(a) => a, + None => { + unsafe { SPRITE_ALLOCATOR.dealloc(dest.as_ptr(), sprite.layout()) } + return None; + } + }; + + unsafe { + dma::dma_copy16( + sprite.data.as_ptr().cast(), + dest.as_ptr().cast(), + sprite.data.len() / 2, + ); + } + + let sprite = SpriteVram(Rc::new(SpriteArena { + location: Location::from_sprite_ptr(dest), + size: sprite.size(), + palette: palette_location, + })); + + self.static_sprite_map.insert(id, Rc::downgrade(&sprite.0)); + + Some(SpriteBorrow { sprite }) + } + fn new() -> Self { - Self { - palette: HashMap::default(), - sprite: HashMap::default(), - } + Default::default() } - fn palette(&mut self, palette: &'static Palette16) -> Option { + fn palette(&mut self, palette: &'static Palette16) -> Option { let id = palette.id(); - if let Some(storage) = self.palette.get_mut(&id) { - storage.count += 1; - Some(storage.location) - } else { - let dest = unsafe { PALETTE_ALLOCATOR.alloc(Palette16::layout())? }; - - unsafe { - dma::dma_copy16( - palette.colours.as_ptr().cast(), - dest.as_ptr().cast(), - palette.colours.len(), - ); - } - - let storage = Storage::from_palette_ptr(dest); - self.palette.insert(id, storage); - - Some(storage.location) - } - } - - fn return_sprite(&mut self, sprite: &'static Sprite) { - let storage = self.sprite.get_mut(&sprite.id()); - - if let Some(storage) = storage { - storage.count -= 1; - - if storage.count == 0 { - unsafe { SPRITE_ALLOCATOR.dealloc(storage.as_sprite_ptr(), sprite.layout()) }; - self.sprite.remove(&sprite.id()); + if let Some(storage) = self.static_palette_map.get(&id) { + if let Some(up) = storage.upgrade() { + return Some(PaletteVram(up)); } } - self.return_palette(sprite.palette); - } + let dest = unsafe { PALETTE_ALLOCATOR.alloc(Palette16::layout())? }; - fn return_palette(&mut self, palette: &'static Palette16) { - let id = palette.id(); - - if let Some(storage) = self.palette.get_mut(&id) { - storage.count -= 1; - - if storage.count == 0 { - unsafe { PALETTE_ALLOCATOR.dealloc(storage.as_palette_ptr(), Palette16::layout()) }; - self.palette.remove(&id); - } + unsafe { + dma::dma_copy16( + palette.colours.as_ptr().cast(), + dest.as_ptr().cast(), + palette.colours.len(), + ); } - } -} -impl<'a> Drop for SpriteBorrow<'a> { - fn drop(&mut self) { - let mut s = unsafe { self.controller.borrow_mut() }; - s.sprite_controller.return_sprite(self.id.sprite()); - } -} + let storage = PaletteVram(Rc::new(PaletteData { + location: Location::from_palette_ptr(dest), + })); + self.static_palette_map + .insert(id, Rc::downgrade(&storage.0)); -impl<'a> SpriteBorrow<'a> { - fn drop(self, s: &mut SpriteControllerInner) { - s.return_sprite(self.id.sprite()); - core::mem::forget(self); - } - - fn clone(&self, s: &mut SpriteControllerInner) -> Self { - s.sprite.entry(self.id).and_modify(|a| a.count += 1); - let _ = s.palette(self.id.sprite().palette).unwrap(); - Self { - id: self.id, - sprite_location: self.sprite_location, - palette_location: self.palette_location, - controller: self.controller, - } - } -} - -impl<'a> Clone for SpriteBorrow<'a> { - fn clone(&self) -> Self { - let mut s = unsafe { self.controller.borrow_mut() }; - self.clone(&mut s.sprite_controller) + Some(storage) } }