switch to using rust Rc

This commit is contained in:
Corwin 2022-10-02 17:14:41 +01:00
parent 5d21f720a5
commit 1acf7142da

View file

@ -1,4 +1,5 @@
#![deny(missing_docs)] #![deny(missing_docs)]
use alloc::rc::{Rc, Weak};
use alloc::vec::Vec; use alloc::vec::Vec;
use core::alloc::Layout; use core::alloc::Layout;
@ -398,6 +399,10 @@ impl Size {
(self as u8 >> 2, self as u8 & 0b11) (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] #[must_use]
/// Creates a size from width and height in pixels, panics if the width and /// Creates a size from width and height in pixels, panics if the width and
/// height is not representable by GBA sprites. /// 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 /// 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 /// objects no longer refer to this sprite, then it's vram slot is freed for the
/// next sprite. This is obtained from the [ObjectController]. /// next sprite. This is obtained from the [ObjectController].
pub struct SpriteBorrow<'a> { #[derive(Clone)]
id: SpriteId, pub struct SpriteBorrow {
sprite_location: u16, sprite: SpriteVram,
palette_location: u16,
controller: ObjectControllerReference<'a>,
}
#[derive(Clone, Copy)]
struct Storage {
location: u16,
count: u16,
}
impl Storage {
fn from_sprite_ptr(d: NonNull<u8>) -> Self {
Self {
location: (((d.as_ptr() as usize) - TILE_SPRITE) / BYTES_PER_TILE_4BPP) as u16,
count: 1,
}
}
fn from_palette_ptr(d: NonNull<u8>) -> 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(PartialEq, Eq)] #[derive(PartialEq, Eq)]
@ -527,9 +503,56 @@ pub struct Object<'a> {
loan: Loan<'a>, loan: Loan<'a>,
} }
#[derive(Clone, Copy)]
struct Location(usize);
impl Location {
fn from_sprite_ptr(d: NonNull<u8>) -> Self {
Self(((d.as_ptr() as usize) - TILE_SPRITE) / BYTES_PER_TILE_4BPP)
}
fn from_palette_ptr(d: NonNull<u8>) -> 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<PaletteData>);
#[derive(Clone)]
struct SpriteVram(Rc<SpriteArena>);
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 { struct SpriteControllerInner {
palette: HashMap<PaletteId, Storage>, static_palette_map: HashMap<PaletteId, Weak<PaletteData>>,
sprite: HashMap<SpriteId, Storage>, static_sprite_map: HashMap<SpriteId, Weak<SpriteArena>>,
} }
struct Loan<'a> { struct Loan<'a> {
@ -552,8 +575,8 @@ impl Drop for Loan<'_> {
struct ObjectInner { struct ObjectInner {
attrs: Attributes, attrs: Attributes,
sprite: SpriteBorrow<'static>, sprite: SpriteBorrow,
previous_sprite: SpriteBorrow<'static>, previous_sprite: SpriteBorrow,
destroy: bool, destroy: bool,
z: i32, z: i32,
} }
@ -620,15 +643,10 @@ impl ObjectController {
.write_volatile(HIDDEN_VALUE); .write_volatile(HIDDEN_VALUE);
} }
let a = unsafe { s.shadow_oam[z as usize].take().unwrap_unchecked() }; let _ = 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);
} else { } else {
o.attrs.commit(i); o.attrs.commit(i);
o.previous_sprite = o.sprite.clone();
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);
} }
} else { } else {
unsafe { unsafe {
@ -731,7 +749,7 @@ impl ObjectController {
/// # } /// # }
/// ``` /// ```
#[must_use] #[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") self.try_get_object(sprite).expect("No object available")
} }
@ -757,28 +775,28 @@ impl ObjectController {
/// # } /// # }
/// ``` /// ```
#[must_use] #[must_use]
pub fn try_get_object<'a>(&'a self, sprite: SpriteBorrow<'a>) -> Option<Object<'a>> { pub fn try_get_object(&self, sprite: SpriteBorrow) -> Option<Object> {
let mut s = unsafe { self.inner.borrow_mut() }; let mut s = unsafe { self.inner.borrow_mut() };
let mut attrs = Attributes::new(); let mut attrs = Attributes::new();
attrs.a2.set_tile_index(sprite.sprite_location); attrs.a2.set_tile_index(sprite.sprite.0.location.0 as u16);
let shape_size = sprite.id.sprite().size.shape_size(); let shape_size = sprite.sprite.0.size.shape_size();
attrs.a2.set_palete_bank(sprite.palette_location as u8); attrs
.a2
.set_palete_bank((sprite.sprite.0.palette.0.location.0) as u8);
attrs.a0.set_shape(shape_size.0); attrs.a0.set_shape(shape_size.0);
attrs.a1a.set_size(shape_size.1); attrs.a1a.set_size(shape_size.1);
attrs.a1s.set_size(shape_size.1); attrs.a1s.set_size(shape_size.1);
let index = s.free_object.pop()?; let index = s.free_object.pop()?;
let new_sprite: SpriteBorrow<'static> = unsafe { core::mem::transmute(sprite) };
s.shadow_oam[index as usize] = Some(ObjectInner { s.shadow_oam[index as usize] = Some(ObjectInner {
attrs, attrs,
z: 0, z: 0,
previous_sprite: new_sprite.clone(&mut s.sprite_controller), previous_sprite: sprite.clone(),
destroy: false, destroy: false,
sprite: new_sprite, sprite,
}); });
let loan = Loan { let loan = Loan {
@ -840,7 +858,7 @@ impl ObjectController {
pub fn try_get_sprite(&self, sprite: &'static Sprite) -> Option<SpriteBorrow> { pub fn try_get_sprite(&self, sprite: &'static Sprite) -> Option<SpriteBorrow> {
unsafe { self.inner.borrow_mut() } unsafe { self.inner.borrow_mut() }
.sprite_controller .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<Target = SpriteControllerInner> + 'a,
impl DerefMut<Target = ObjectInner> + '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, /// Swaps out the current sprite. This handles changing of size, palette,
/// etc. No change will be seen until [ObjectController::commit] is called. /// etc. No change will be seen until [ObjectController::commit] is called.
pub fn set_sprite(&'_ mut self, sprite: SpriteBorrow<'a>) { pub fn set_sprite(&'_ mut self, sprite: SpriteBorrow) {
let (mut sprite_controller, mut object_inner) = unsafe { self.inner_controller() }; let mut object_inner = unsafe { self.object_inner() };
object_inner.attrs.a2.set_tile_index(sprite.sprite_location);
let shape_size = sprite.id.sprite().size.shape_size();
object_inner object_inner
.attrs .attrs
.a2 .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.a0.set_shape(shape_size.0);
object_inner.attrs.a1a.set_size(shape_size.1); object_inner.attrs.a1a.set_size(shape_size.1);
object_inner.attrs.a1s.set_size(shape_size.1); object_inner.attrs.a1s.set_size(shape_size.1);
let mut sprite = unsafe { core::mem::transmute(sprite) }; object_inner.sprite = sprite;
core::mem::swap(&mut object_inner.sprite, &mut sprite);
sprite.drop(&mut sprite_controller);
} }
/// Shows the sprite. No change will be seen until /// Shows the sprite. No change will be seen until
@ -1027,15 +1017,6 @@ impl<'a> Object<'a> {
#[derive(Clone, Copy, PartialEq, Eq, Hash)] #[derive(Clone, Copy, PartialEq, Eq, Hash)]
struct SpriteId(usize); 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 /// The palette id is a thin wrapper around the pointer to the palette in rom
/// and is therefore a unique reference to a palette /// and is therefore a unique reference to a palette
#[derive(Copy, Clone, PartialEq, Eq, Hash)] #[derive(Copy, Clone, PartialEq, Eq, Hash)]
@ -1076,23 +1057,16 @@ impl Sprite {
} }
impl SpriteControllerInner { impl SpriteControllerInner {
fn try_get_sprite<'a>( fn try_get_sprite<'a>(&mut self, sprite: &'static Sprite) -> Option<SpriteBorrow> {
&mut self,
sprite: &'static Sprite,
controller_reference: ObjectControllerReference<'a>,
) -> Option<SpriteBorrow<'a>> {
let id = sprite.id(); let id = sprite.id();
if let Some(storage) = self.sprite.get_mut(&id) { if let Some(storage) = self.static_sprite_map.get_mut(&id) {
storage.count += 1; if let Some(strong) = storage.upgrade() {
let location = storage.location; return Some(SpriteBorrow {
let palette_location = self.palette(sprite.palette).unwrap(); sprite: SpriteVram(strong),
Some(SpriteBorrow { });
id, }
palette_location, }
sprite_location: location,
controller: controller_reference,
})
} else {
// layout is non zero sized, so this is safe to call // layout is non zero sized, so this is safe to call
let dest = unsafe { SPRITE_ALLOCATOR.alloc(sprite.layout())? }; let dest = unsafe { SPRITE_ALLOCATOR.alloc(sprite.layout())? };
@ -1114,32 +1088,28 @@ impl SpriteControllerInner {
); );
} }
let storage = Storage::from_sprite_ptr(dest); let sprite = SpriteVram(Rc::new(SpriteArena {
self.sprite.insert(id, storage); location: Location::from_sprite_ptr(dest),
size: sprite.size(),
palette: palette_location,
}));
Some(SpriteBorrow { self.static_sprite_map.insert(id, Rc::downgrade(&sprite.0));
id,
palette_location, Some(SpriteBorrow { sprite })
sprite_location: storage.location,
controller: controller_reference,
})
}
}
} }
impl SpriteControllerInner {
fn new() -> Self { fn new() -> Self {
Self { Default::default()
palette: HashMap::default(),
sprite: HashMap::default(),
} }
} fn palette(&mut self, palette: &'static Palette16) -> Option<PaletteVram> {
fn palette(&mut self, palette: &'static Palette16) -> Option<u16> {
let id = palette.id(); let id = palette.id();
if let Some(storage) = self.palette.get_mut(&id) { if let Some(storage) = self.static_palette_map.get(&id) {
storage.count += 1; if let Some(up) = storage.upgrade() {
Some(storage.location) return Some(PaletteVram(up));
} else { }
}
let dest = unsafe { PALETTE_ALLOCATOR.alloc(Palette16::layout())? }; let dest = unsafe { PALETTE_ALLOCATOR.alloc(Palette16::layout())? };
unsafe { unsafe {
@ -1150,71 +1120,13 @@ impl SpriteControllerInner {
); );
} }
let storage = Storage::from_palette_ptr(dest); let storage = PaletteVram(Rc::new(PaletteData {
self.palette.insert(id, storage); location: Location::from_palette_ptr(dest),
}));
self.static_palette_map
.insert(id, Rc::downgrade(&storage.0));
Some(storage.location) Some(storage)
}
}
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());
}
}
self.return_palette(sprite.palette);
}
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);
}
}
}
}
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());
}
}
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)
} }
} }