mirror of
https://github.com/italicsjenga/agb.git
synced 2025-01-11 17:41:33 +11:00
Use the new allocator
This commit is contained in:
parent
f01d3bff36
commit
87c5d6ca6a
|
@ -72,7 +72,9 @@ impl RegularMap {
|
||||||
|
|
||||||
pub fn clear(&mut self, vram: &mut VRamManager) {
|
pub fn clear(&mut self, vram: &mut VRamManager) {
|
||||||
for tile in self.tiles.iter_mut() {
|
for tile in self.tiles.iter_mut() {
|
||||||
vram.remove_tile(tile.tile_index());
|
if *tile != Tile::default() {
|
||||||
|
vram.remove_tile(tile.tile_index());
|
||||||
|
}
|
||||||
|
|
||||||
*tile = Tile::default();
|
*tile = Tile::default();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ impl Tile {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tile_index(self) -> TileIndex {
|
fn tile_index(self) -> TileIndex {
|
||||||
TileIndex::new(self.0 & ((1 << 10) - 1))
|
TileIndex::new(self.0 as usize & ((1 << 10) - 1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,29 @@
|
||||||
|
use core::{alloc::Layout, ptr::NonNull};
|
||||||
|
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::{display::palette16, dma::dma_copy, memory_mapped::MemoryMapped1DArray};
|
use crate::{
|
||||||
|
agb_alloc::{block_allocator::BlockAllocator, bump_allocator::StartEnd},
|
||||||
|
display::palette16,
|
||||||
|
dma::dma_copy,
|
||||||
|
memory_mapped::MemoryMapped1DArray,
|
||||||
|
};
|
||||||
|
|
||||||
|
const TILE_RAM_START: usize = 0x0600_0000;
|
||||||
|
|
||||||
const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> =
|
const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> =
|
||||||
unsafe { MemoryMapped1DArray::new(0x0500_0000) };
|
unsafe { MemoryMapped1DArray::new(0x0500_0000) };
|
||||||
|
|
||||||
|
static TILE_ALLOCATOR: BlockAllocator = unsafe {
|
||||||
|
BlockAllocator::new(StartEnd {
|
||||||
|
start: || TILE_RAM_START,
|
||||||
|
end: || TILE_RAM_START + 0x8000,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
const TILE_LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(8 * 8 / 2, 8 * 8 / 2) };
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
unsafe fn debug_unreachable_unchecked(message: &'static str) -> ! {
|
unsafe fn debug_unreachable_unchecked(message: &'static str) -> ! {
|
||||||
unreachable!("{}", message);
|
unreachable!("{}", message);
|
||||||
|
@ -63,8 +81,8 @@ impl TileSetReference {
|
||||||
pub struct TileIndex(u16);
|
pub struct TileIndex(u16);
|
||||||
|
|
||||||
impl TileIndex {
|
impl TileIndex {
|
||||||
pub(crate) const fn new(index: u16) -> Self {
|
pub(crate) const fn new(index: usize) -> Self {
|
||||||
Self(index)
|
Self(index as u16)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) const fn index(&self) -> u16 {
|
pub(crate) const fn index(&self) -> u16 {
|
||||||
|
@ -73,31 +91,7 @@ impl TileIndex {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
struct TileReference(u16, u16);
|
struct TileReference(NonNull<u32>);
|
||||||
|
|
||||||
enum VRamState {
|
|
||||||
ReferenceCounted(u16, TileReference),
|
|
||||||
Free(u16),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VRamState {
|
|
||||||
fn increase_reference(&mut self) {
|
|
||||||
if let VRamState::ReferenceCounted(count, _) = self {
|
|
||||||
*count += 1;
|
|
||||||
} else {
|
|
||||||
unsafe { debug_unreachable_unchecked("Cannot increase reference count of free item") };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decrease_reference(&mut self) -> (u16, TileReference) {
|
|
||||||
if let VRamState::ReferenceCounted(count, tile_ref) = self {
|
|
||||||
*count -= 1;
|
|
||||||
(*count, *tile_ref)
|
|
||||||
} else {
|
|
||||||
unsafe { debug_unreachable_unchecked("Cannot decrease reference count of free item") };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ArenaStorageItem<T> {
|
enum ArenaStorageItem<T> {
|
||||||
EndOfFreeList,
|
EndOfFreeList,
|
||||||
|
@ -110,13 +104,10 @@ pub struct VRamManager<'a> {
|
||||||
generation: u16,
|
generation: u16,
|
||||||
free_pointer: Option<usize>,
|
free_pointer: Option<usize>,
|
||||||
|
|
||||||
tile_set_to_vram: Vec<Vec<(u16, u16)>>,
|
tile_set_to_vram: Vec<Vec<Option<TileReference>>>,
|
||||||
references: Vec<VRamState>,
|
reference_counts: Vec<(u16, Option<(TileSetReference, u16)>)>,
|
||||||
vram_free_pointer: Option<usize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const END_OF_FREE_LIST_MARKER: u16 = u16::MAX;
|
|
||||||
|
|
||||||
impl<'a> VRamManager<'a> {
|
impl<'a> VRamManager<'a> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -125,8 +116,7 @@ impl<'a> VRamManager<'a> {
|
||||||
free_pointer: None,
|
free_pointer: None,
|
||||||
|
|
||||||
tile_set_to_vram: Default::default(),
|
tile_set_to_vram: Default::default(),
|
||||||
references: vec![VRamState::Free(0)],
|
reference_counts: Default::default(),
|
||||||
vram_free_pointer: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,37 +174,27 @@ impl<'a> VRamManager<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn index_from_reference(reference: TileReference) -> usize {
|
||||||
|
let difference = reference.0.as_ptr() as usize - TILE_RAM_START;
|
||||||
|
difference / (8 * 8 / 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reference_from_index(index: TileIndex) -> TileReference {
|
||||||
|
let ptr = (index.index() * (8 * 8 / 2)) as usize + TILE_RAM_START;
|
||||||
|
TileReference(NonNull::new(ptr as *mut _).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn add_tile(&mut self, tile_set_ref: TileSetReference, tile: u16) -> TileIndex {
|
pub(crate) fn add_tile(&mut self, tile_set_ref: TileSetReference, tile: u16) -> TileIndex {
|
||||||
let tile_ref = TileReference(tile_set_ref.id, tile);
|
|
||||||
let reference = self.tile_set_to_vram[tile_set_ref.id as usize][tile as usize];
|
let reference = self.tile_set_to_vram[tile_set_ref.id as usize][tile as usize];
|
||||||
if reference != Default::default() {
|
|
||||||
if reference.1 == tile_set_ref.generation {
|
if let Some(reference) = reference {
|
||||||
self.references[reference.0 as usize].increase_reference();
|
let index = Self::index_from_reference(reference);
|
||||||
return TileIndex(reference.0 as u16);
|
self.reference_counts[index].0 += 1;
|
||||||
} else {
|
return TileIndex::new(index);
|
||||||
panic!("Tileset unloaded but not cleared from vram");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let index_to_copy_into = if let Some(ptr) = self.vram_free_pointer.take() {
|
let new_reference: NonNull<u32> =
|
||||||
match self.references[ptr] {
|
unsafe { TILE_ALLOCATOR.alloc(TILE_LAYOUT) }.unwrap().cast();
|
||||||
VRamState::Free(next_free) => {
|
|
||||||
if next_free != END_OF_FREE_LIST_MARKER {
|
|
||||||
self.vram_free_pointer = Some(next_free as usize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
VRamState::ReferenceCounted(_, _) => unsafe {
|
|
||||||
debug_unreachable_unchecked("Free pointer must point to free item")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
self.references[ptr] = VRamState::ReferenceCounted(1, tile_ref);
|
|
||||||
ptr
|
|
||||||
} else {
|
|
||||||
self.references
|
|
||||||
.push(VRamState::ReferenceCounted(1, tile_ref));
|
|
||||||
self.references.len() - 1
|
|
||||||
};
|
|
||||||
|
|
||||||
let tile_slice = if let ArenaStorageItem::Data(data, generation) =
|
let tile_slice = if let ArenaStorageItem::Data(data, generation) =
|
||||||
&self.tilesets[tile_set_ref.id as usize]
|
&self.tilesets[tile_set_ref.id as usize]
|
||||||
|
@ -232,40 +212,50 @@ impl<'a> VRamManager<'a> {
|
||||||
|
|
||||||
let tile_size_in_half_words = TileFormat::FourBpp.tile_size() / 2;
|
let tile_size_in_half_words = TileFormat::FourBpp.tile_size() / 2;
|
||||||
|
|
||||||
const TILE_BACKGROUND_ADDRESS: usize = 0x0600_0000;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
dma_copy(
|
dma_copy(
|
||||||
tile_slice.as_ptr() as *const u16,
|
tile_slice.as_ptr() as *const u16,
|
||||||
(TILE_BACKGROUND_ADDRESS as *mut u16)
|
new_reference.as_ptr() as *mut u16,
|
||||||
.add(index_to_copy_into * tile_size_in_half_words),
|
|
||||||
tile_size_in_half_words,
|
tile_size_in_half_words,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tile_set_to_vram[tile_set_ref.id as usize][tile as usize] =
|
let tile_reference = TileReference(new_reference);
|
||||||
(index_to_copy_into as u16, tile_set_ref.generation);
|
|
||||||
|
|
||||||
TileIndex(index_to_copy_into as u16)
|
let index = Self::index_from_reference(tile_reference);
|
||||||
|
|
||||||
|
self.tile_set_to_vram[tile_set_ref.id as usize][tile as usize] = Some(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)));
|
||||||
|
|
||||||
|
TileIndex::new(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn remove_tile(&mut self, tile_index: TileIndex) {
|
pub(crate) fn remove_tile(&mut self, tile_index: TileIndex) {
|
||||||
let index = tile_index.0 as usize;
|
let index = tile_index.index() as usize;
|
||||||
|
assert!(
|
||||||
|
self.reference_counts[index].0 > 0,
|
||||||
|
"Trying to decrease the reference count of {} below 0",
|
||||||
|
index
|
||||||
|
);
|
||||||
|
|
||||||
let (new_count, tile_ref) = self.references[index].decrease_reference();
|
self.reference_counts[index].0 -= 1;
|
||||||
|
|
||||||
if new_count != 0 {
|
if self.reference_counts[index].0 != 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ptr) = self.vram_free_pointer {
|
let tile_reference = Self::reference_from_index(tile_index);
|
||||||
self.references[index] = VRamState::Free(ptr as u16);
|
unsafe {
|
||||||
} else {
|
TILE_ALLOCATOR.dealloc(tile_reference.0.cast().as_ptr(), TILE_LAYOUT);
|
||||||
self.references[index] = VRamState::Free(END_OF_FREE_LIST_MARKER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tile_set_to_vram[tile_ref.0 as usize][tile_ref.1 as usize] = Default::default();
|
let tile_ref = self.reference_counts[index].1.unwrap();
|
||||||
|
self.tile_set_to_vram[tile_ref.0.id as usize][tile_ref.1 as usize] = None;
|
||||||
self.vram_free_pointer = Some(index);
|
self.reference_counts[index].1 = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copies raw palettes to the background palette without any checks.
|
/// Copies raw palettes to the background palette without any checks.
|
||||||
|
|
|
@ -825,7 +825,7 @@ fn main(mut agb: agb::Gba) -> ! {
|
||||||
let mut music_box = sfx::MusicBox::new();
|
let mut music_box = sfx::MusicBox::new();
|
||||||
|
|
||||||
let vblank = agb::interrupt::VBlank::get();
|
let vblank = agb::interrupt::VBlank::get();
|
||||||
let mut current_level = 11;
|
let mut current_level = 0;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if current_level == map_tiles::LEVELS.len() as u32 {
|
if current_level == map_tiles::LEVELS.len() as u32 {
|
||||||
|
|
Loading…
Reference in a new issue