diff --git a/agb/examples/animated_background.rs b/agb/examples/animated_background.rs index d0dab120..29c14469 100644 --- a/agb/examples/animated_background.rs +++ b/agb/examples/animated_background.rs @@ -17,7 +17,6 @@ fn main(mut gba: agb::Gba) -> ! { let vblank = agb::interrupt::VBlank::get(); let tileset = TileSet::new(water_tiles::water_tiles.tiles, TileFormat::FourBpp); - let tileset_ref = vram.add_tileset(tileset); vram.set_background_palettes(water_tiles::water_tiles.palettes); @@ -28,7 +27,7 @@ fn main(mut gba: agb::Gba) -> ! { bg.set_tile( &mut vram, (x, y).into(), - tileset_ref, + &tileset, TileSetting::new(0, false, false, 0), ); } @@ -41,7 +40,7 @@ fn main(mut gba: agb::Gba) -> ! { loop { i = (i + 1) % 8; - vram.replace_tile(tileset_ref, 0, tileset_ref, i); + vram.replace_tile(&tileset, 0, &tileset, i); vblank.wait_for_vblank(); } diff --git a/agb/examples/chicken.rs b/agb/examples/chicken.rs index ef0278d0..9620b36b 100644 --- a/agb/examples/chicken.rs +++ b/agb/examples/chicken.rs @@ -53,7 +53,6 @@ fn main(mut gba: agb::Gba) -> ! { vram.set_background_palette_raw(&MAP_PALETTE); let tileset = TileSet::new(&MAP_TILES, TileFormat::FourBpp); - let tileset_ref = vram.add_tileset(tileset); let mut background = gfx.background(agb::display::Priority::P0); @@ -62,7 +61,7 @@ fn main(mut gba: agb::Gba) -> ! { background.set_tile( &mut vram, (i % 32, i / 32).into(), - tileset_ref, + &tileset, TileSetting::from_raw(tile), ); } diff --git a/agb/src/display/example_logo.rs b/agb/src/display/example_logo.rs index 46db1afc..f53b35f1 100644 --- a/agb/src/display/example_logo.rs +++ b/agb/src/display/example_logo.rs @@ -6,7 +6,6 @@ pub fn display_logo(map: &mut RegularMap, vram: &mut VRamManager) { vram.set_background_palettes(agb_logo::test_logo.palettes); let background_tilemap = TileSet::new(agb_logo::test_logo.tiles, TileFormat::FourBpp); - let background_tilemap_reference = vram.add_tileset(background_tilemap); for y in 0..20 { for x in 0..30 { @@ -15,12 +14,7 @@ pub fn display_logo(map: &mut RegularMap, vram: &mut VRamManager) { let palette_entry = agb_logo::test_logo.palette_assignments[tile_id as usize]; let tile_setting = TileSetting::new(tile_id, false, false, palette_entry); - map.set_tile( - vram, - (x, y).into(), - background_tilemap_reference, - tile_setting, - ); + map.set_tile(vram, (x, y).into(), &background_tilemap, tile_setting); } } diff --git a/agb/src/display/tiled/infinite_scrolled_map.rs b/agb/src/display/tiled/infinite_scrolled_map.rs index dba4bef2..56a4cfde 100644 --- a/agb/src/display/tiled/infinite_scrolled_map.rs +++ b/agb/src/display/tiled/infinite_scrolled_map.rs @@ -1,6 +1,6 @@ use alloc::boxed::Box; -use super::{MapLoan, RegularMap, TileSetReference, TileSetting, VRamManager}; +use super::{MapLoan, RegularMap, TileSet, TileSetting, VRamManager}; use crate::{ display, @@ -9,7 +9,7 @@ use crate::{ pub struct InfiniteScrolledMap<'a> { map: MapLoan<'a, RegularMap>, - tile: Box) -> (TileSetReference, TileSetting)>, + tile: Box) -> (&'a TileSet<'a>, TileSetting)>, current_pos: Vector2D, offset: Vector2D, @@ -26,7 +26,7 @@ pub enum PartialUpdateStatus { impl<'a> InfiniteScrolledMap<'a> { pub fn new( map: MapLoan<'a, RegularMap>, - tile: Box) -> (TileSetReference, TileSetting)>, + tile: Box) -> (&'a TileSet<'a>, TileSetting)>, ) -> Self { Self { map, @@ -79,12 +79,12 @@ impl<'a> InfiniteScrolledMap<'a> { { for (x_idx, x) in (x_start..x_end).enumerate() { let pos = (x, y).into(); - let (tile_set_ref, tile_setting) = (self.tile)(pos); + let (tileset, tile_setting) = (self.tile)(pos); self.map.set_tile( vram, (x_idx as u16, (y_idx + copy_from as usize) as u16).into(), - tile_set_ref, + tileset, tile_setting, ); } @@ -172,7 +172,7 @@ impl<'a> InfiniteScrolledMap<'a> { .iter() .chain(horizontal_rect_to_update.iter()) { - let (tile_set_ref, tile_setting) = (self.tile)((tile_x, tile_y).into()); + let (tileset, tile_setting) = (self.tile)((tile_x, tile_y).into()); self.map.set_tile( vram, @@ -181,7 +181,7 @@ impl<'a> InfiniteScrolledMap<'a> { (tile_y - self.offset.y).rem_euclid(32) as u16, ) .into(), - tile_set_ref, + tileset, tile_setting, ); } diff --git a/agb/src/display/tiled/map.rs b/agb/src/display/tiled/map.rs index ca33ee63..4cfdfd43 100644 --- a/agb/src/display/tiled/map.rs +++ b/agb/src/display/tiled/map.rs @@ -7,7 +7,7 @@ use crate::dma::dma_copy16; use crate::fixnum::Vector2D; use crate::memory_mapped::MemoryMapped; -use super::{Tile, TileSetReference, TileSetting, VRamManager}; +use super::{Tile, TileSet, TileSetting, VRamManager}; pub struct RegularMap { background_id: u8, @@ -42,7 +42,7 @@ impl RegularMap { &mut self, vram: &mut VRamManager, pos: Vector2D, - tileset_ref: TileSetReference, + tileset: &TileSet<'_>, tile_setting: TileSetting, ) { let pos = (pos.x + pos.y * 32) as usize; @@ -55,7 +55,7 @@ impl RegularMap { let tile_index = tile_setting.index(); let new_tile = if tile_index != TRANSPARENT_TILE_INDEX { - let new_tile_idx = vram.add_tile(tileset_ref, tile_index); + let new_tile_idx = vram.add_tile(tileset, tile_index); Tile::new(new_tile_idx, tile_setting) } else { Tile::default() diff --git a/agb/src/display/tiled/mod.rs b/agb/src/display/tiled/mod.rs index 0e2e042a..b1d239f8 100644 --- a/agb/src/display/tiled/mod.rs +++ b/agb/src/display/tiled/mod.rs @@ -6,7 +6,7 @@ mod vram_manager; pub use infinite_scrolled_map::{InfiniteScrolledMap, PartialUpdateStatus}; pub use map::{MapLoan, RegularMap}; pub use tiled0::Tiled0; -pub use vram_manager::{TileFormat, TileIndex, TileSet, TileSetReference, VRamManager}; +pub use vram_manager::{TileFormat, TileIndex, TileSet, VRamManager}; #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] #[repr(transparent)] diff --git a/agb/src/display/tiled/vram_manager.rs b/agb/src/display/tiled/vram_manager.rs index 3b4aa57a..aeeb9f5c 100644 --- a/agb/src/display/tiled/vram_manager.rs +++ b/agb/src/display/tiled/vram_manager.rs @@ -24,18 +24,6 @@ static TILE_ALLOCATOR: BlockAllocator = unsafe { const TILE_LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(8 * 8 / 2, 8 * 8 / 2) }; -#[cfg(debug_assertions)] -unsafe fn debug_unreachable_unchecked(message: &'static str) -> ! { - unreachable!("{}", message); -} - -#[cfg(not(debug_assertions))] -const unsafe fn debug_unreachable_unchecked(_message: &'static str) -> ! { - use core::hint::unreachable_unchecked; - - unreachable_unchecked(); -} - #[derive(Clone, Copy, Debug)] pub enum TileFormat { FourBpp, @@ -59,17 +47,9 @@ impl<'a> TileSet<'a> { pub fn new(tiles: &'a [u8], format: TileFormat) -> Self { Self { tiles, format } } -} -#[derive(Clone, Copy, PartialEq, Eq)] -pub struct TileSetReference { - id: u16, - generation: u16, -} - -impl TileSetReference { - fn new(id: u16, generation: u16) -> Self { - Self { id, generation } + fn reference(&self) -> NonNull<[u8]> { + self.tiles.into() } } @@ -89,84 +69,22 @@ impl TileIndex { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] struct TileReference(NonNull); -enum ArenaStorageItem { - EndOfFreeList, - NextFree(usize), - Data(T, u16), +pub struct VRamManager { + tile_set_to_vram: HashMap<(NonNull<[u8]>, u16), TileReference>, + reference_counts: Vec<(u16, Option<(NonNull<[u8]>, u16)>)>, } -pub struct VRamManager<'a> { - tilesets: Vec>>, - generation: u16, - free_pointer: Option, - - tile_set_to_vram: HashMap<(u16, u16), TileReference>, - reference_counts: Vec<(u16, Option<(TileSetReference, u16)>)>, -} - -impl<'a> VRamManager<'a> { +impl VRamManager { pub(crate) fn new() -> Self { - let tile_set_to_vram: HashMap<(u16, u16), TileReference> = HashMap::with_capacity(256); + let tile_set_to_vram: HashMap<(NonNull<[u8]>, u16), TileReference> = + HashMap::with_capacity(256); Self { - tilesets: Vec::new(), - generation: 0, - free_pointer: None, - tile_set_to_vram, reference_counts: Default::default(), } } - pub fn add_tileset(&mut self, tileset: TileSet<'a>) -> TileSetReference { - let generation = self.generation; - self.generation = self.generation.wrapping_add(1); - - let tileset = ArenaStorageItem::Data(tileset, generation); - - let index = if let Some(ptr) = self.free_pointer.take() { - match self.tilesets[ptr] { - ArenaStorageItem::EndOfFreeList => { - self.tilesets[ptr] = tileset; - ptr - } - ArenaStorageItem::NextFree(next_free) => { - self.free_pointer = Some(next_free); - self.tilesets[ptr] = tileset; - ptr - } - _ => unsafe { debug_unreachable_unchecked("Free pointer cannot point to data") }, - } - } else { - self.tilesets.push(tileset); - self.tilesets.len() - 1 - }; - - TileSetReference::new(index as u16, generation) - } - - pub fn remove_tileset(&mut self, tile_set_ref: TileSetReference) { - let tileset = &self.tilesets[tile_set_ref.id as usize]; - - match tileset { - ArenaStorageItem::Data(_, generation) => { - debug_assert_eq!( - *generation, tile_set_ref.generation, - "Tileset generation must be the same when removing" - ); - - self.tilesets[tile_set_ref.id as usize] = if let Some(ptr) = self.free_pointer { - ArenaStorageItem::NextFree(ptr) - } else { - ArenaStorageItem::EndOfFreeList - }; - - self.free_pointer = Some(tile_set_ref.id as usize); - } - _ => panic!("Must remove valid tileset"), - } - } - fn index_from_reference(reference: TileReference) -> usize { let difference = reference.0.as_ptr() as usize - TILE_RAM_START; difference / (8 * 8 / 2) @@ -177,8 +95,8 @@ impl<'a> VRamManager<'a> { TileReference(NonNull::new(ptr as *mut _).unwrap()) } - pub(crate) fn add_tile(&mut self, tile_set_ref: TileSetReference, tile: u16) -> TileIndex { - let reference = self.tile_set_to_vram.get(&(tile_set_ref.id, tile)); + pub(crate) fn add_tile(&mut self, tile_set: &TileSet<'_>, tile: u16) -> TileIndex { + let reference = self.tile_set_to_vram.get(&(tile_set.reference(), tile)); if let Some(reference) = reference { let index = Self::index_from_reference(*reference); @@ -190,17 +108,17 @@ impl<'a> VRamManager<'a> { unsafe { TILE_ALLOCATOR.alloc(TILE_LAYOUT) }.unwrap().cast(); let tile_reference = TileReference(new_reference); - self.copy_tile_to_location(tile_set_ref, tile, tile_reference); + self.copy_tile_to_location(tile_set, tile, tile_reference); let index = Self::index_from_reference(tile_reference); self.tile_set_to_vram - .insert((tile_set_ref.id, tile), tile_reference); + .insert((tile_set.reference(), tile), tile_reference); self.reference_counts .resize(self.reference_counts.len().max(index + 1), (0, None)); - self.reference_counts[index] = (1, Some((tile_set_ref, tile))); + self.reference_counts[index] = (1, Some((tile_set.reference(), tile))); TileIndex::new(index) } @@ -225,44 +143,34 @@ impl<'a> VRamManager<'a> { } let tile_ref = self.reference_counts[index].1.unwrap(); - self.tile_set_to_vram.remove(&(tile_ref.0.id, tile_ref.1)); + self.tile_set_to_vram.remove(&tile_ref); self.reference_counts[index].1 = None; } pub fn replace_tile( &mut self, - source_tile_set_ref: TileSetReference, + source_tile_set: &TileSet<'_>, source_tile: u16, - target_tile_set_ref: TileSetReference, + target_tile_set: &TileSet<'_>, target_tile: u16, ) { if let Some(&reference) = self .tile_set_to_vram - .get(&(source_tile_set_ref.id, source_tile)) + .get(&(source_tile_set.reference(), source_tile)) { - self.copy_tile_to_location(target_tile_set_ref, target_tile, reference); + self.copy_tile_to_location(target_tile_set, target_tile, reference); } } fn copy_tile_to_location( &self, - tile_set_ref: TileSetReference, + tile_set: &TileSet<'_>, tile_id: u16, tile_reference: TileReference, ) { - let tile_slice = if let ArenaStorageItem::Data(data, generation) = - &self.tilesets[tile_set_ref.id as usize] - { - debug_assert_eq!( - *generation, tile_set_ref.generation, - "Stale tile data requested" - ); - - let tile_offset = (tile_id as usize) * data.format.tile_size(); - &data.tiles[tile_offset..(tile_offset + data.format.tile_size())] - } else { - panic!("Target tile set ref must point to an existing tile set reference") - }; + let tile_size = tile_set.format.tile_size(); + let tile_offset = (tile_id as usize) * tile_size; + let tile_slice = &tile_set.tiles[tile_offset..(tile_offset + tile_size)]; let tile_size_in_half_words = tile_slice.len() / 2; diff --git a/agb/src/display/video.rs b/agb/src/display/video.rs index 046ff12c..57ae60e3 100644 --- a/agb/src/display/video.rs +++ b/agb/src/display/video.rs @@ -18,7 +18,7 @@ impl Video { unsafe { Bitmap4::new() } } - pub fn tiled0(&mut self) -> (Tiled0, VRamManager<'_>) { + pub fn tiled0(&mut self) -> (Tiled0, VRamManager) { (unsafe { Tiled0::new() }, VRamManager::new()) } }