diff --git a/agb/examples/animated_background.rs b/agb/examples/animated_background.rs index 29c14469..2c2a3392 100644 --- a/agb/examples/animated_background.rs +++ b/agb/examples/animated_background.rs @@ -33,7 +33,7 @@ fn main(mut gba: agb::Gba) -> ! { } } - bg.commit(); + bg.commit(&mut vram); bg.show(); let mut i = 0; diff --git a/agb/examples/chicken.rs b/agb/examples/chicken.rs index 3a9bbe13..d0782e15 100644 --- a/agb/examples/chicken.rs +++ b/agb/examples/chicken.rs @@ -67,7 +67,7 @@ fn main(mut gba: agb::Gba) -> ! { } background.show(); - background.commit(); + background.commit(&mut vram); let object = gba.display.object.get(); diff --git a/agb/examples/dynamic_tiles.rs b/agb/examples/dynamic_tiles.rs index 2cb43832..1d746f9f 100644 --- a/agb/examples/dynamic_tiles.rs +++ b/agb/examples/dynamic_tiles.rs @@ -41,7 +41,7 @@ fn main(mut gba: agb::Gba) -> ! { } } - bg.commit(); + bg.commit(&mut vram); bg.show(); loop { diff --git a/agb/examples/text_render.rs b/agb/examples/text_render.rs index f465a67a..6584e9e7 100644 --- a/agb/examples/text_render.rs +++ b/agb/examples/text_render.rs @@ -44,10 +44,20 @@ fn main(mut gba: agb::Gba) -> ! { writer.commit(); - bg.commit(); + bg.commit(&mut vram); bg.show(); + let mut frame = 0; + loop { + let mut writer = FONT.render_text((4u16, 0u16).into(), 1, 2, &mut bg, &mut vram); + + writeln!(&mut writer, "Frame {}", frame).unwrap(); + writer.commit(); + + frame += 1; + vblank.wait_for_vblank(); + bg.commit(&mut vram); } } diff --git a/agb/src/display/example_logo.rs b/agb/src/display/example_logo.rs index f53b35f1..d39389b8 100644 --- a/agb/src/display/example_logo.rs +++ b/agb/src/display/example_logo.rs @@ -18,7 +18,7 @@ pub fn display_logo(map: &mut RegularMap, vram: &mut VRamManager) { } } - map.commit(); + map.commit(vram); map.show(); } #[cfg(test)] diff --git a/agb/src/display/font.rs b/agb/src/display/font.rs index d6f8605e..a7058b72 100644 --- a/agb/src/display/font.rs +++ b/agb/src/display/font.rs @@ -242,7 +242,7 @@ mod tests { writer.commit(); - bg.commit(); + bg.commit(&mut vram); bg.show(); crate::test_runner::assert_image_output("examples/font/font-test-output.png"); diff --git a/agb/src/display/tiled/infinite_scrolled_map.rs b/agb/src/display/tiled/infinite_scrolled_map.rs index e50d184e..48cc66ba 100644 --- a/agb/src/display/tiled/infinite_scrolled_map.rs +++ b/agb/src/display/tiled/infinite_scrolled_map.rs @@ -206,8 +206,8 @@ impl<'a> InfiniteScrolledMap<'a> { self.map.hide(); } - pub fn commit(&mut self) { - self.map.commit(); + pub fn commit(&mut self, vram: &mut VRamManager) { + self.map.commit(vram); } pub fn clear(&mut self, vram: &mut VRamManager) { diff --git a/agb/src/display/tiled/map.rs b/agb/src/display/tiled/map.rs index 4cfdfd43..9d6c9790 100644 --- a/agb/src/display/tiled/map.rs +++ b/agb/src/display/tiled/map.rs @@ -92,13 +92,15 @@ impl RegularMap { DISPLAY_CONTROL.set(new_mode); } - pub fn commit(&mut self) { + pub fn commit(&mut self, vram: &mut VRamManager) { let new_bg_control_value = (self.priority as u16) | ((self.screenblock as u16) << 8); self.bg_control_register().set(new_bg_control_value); self.bg_h_offset().set(self.x_scroll); self.bg_v_offset().set(self.y_scroll); + vram.gc(); + if !self.tiles_dirty { return; } diff --git a/agb/src/display/tiled/vram_manager.rs b/agb/src/display/tiled/vram_manager.rs index fdb9538b..bedbe801 100644 --- a/agb/src/display/tiled/vram_manager.rs +++ b/agb/src/display/tiled/vram_manager.rs @@ -116,6 +116,10 @@ impl TileReferenceCount { self.reference_count = 0; self.tile_in_tile_set = None; } + + fn current_count(&self) -> u16 { + self.reference_count + } } #[non_exhaustive] @@ -158,6 +162,8 @@ impl DynamicTile<'_> { pub struct VRamManager { tile_set_to_vram: HashMap, reference_counts: Vec, + + indices_to_gc: Vec, } impl VRamManager { @@ -168,6 +174,7 @@ impl VRamManager { Self { tile_set_to_vram, reference_counts: Default::default(), + indices_to_gc: Default::default(), } } @@ -270,18 +277,29 @@ impl VRamManager { return; } - let tile_reference = Self::reference_from_index(tile_index); - unsafe { - TILE_ALLOCATOR.dealloc_no_normalise(tile_reference.0.cast().as_ptr(), TILE_LAYOUT); + self.indices_to_gc.push(tile_index); + } + + pub(crate) fn gc(&mut self) { + for tile_index in self.indices_to_gc.drain(..) { + let index = tile_index.index() as usize; + if self.reference_counts[index].current_count() > 0 { + continue; // it has since been added back + } + + let tile_reference = Self::reference_from_index(tile_index); + unsafe { + TILE_ALLOCATOR.dealloc_no_normalise(tile_reference.0.cast().as_ptr(), TILE_LAYOUT); + } + + let tile_ref = self.reference_counts[index] + .tile_in_tile_set + .as_ref() + .unwrap(); + + self.tile_set_to_vram.remove(tile_ref); + self.reference_counts[index].clear(); } - - let tile_ref = self.reference_counts[index] - .tile_in_tile_set - .as_ref() - .unwrap(); - - self.tile_set_to_vram.remove(tile_ref); - self.reference_counts[index].clear(); } pub fn replace_tile( @@ -330,12 +348,8 @@ impl VRamManager { } fn set_background_palette(&mut self, pal_index: u8, palette: &palette16::Palette16) { - unsafe { - dma_copy16( - palette.colours.as_ptr(), - PALETTE_BACKGROUND.as_ptr().add(16 * pal_index as usize), - palette.colours.len(), - ); + for (colour_index, &colour) in palette.colours.iter().enumerate() { + PALETTE_BACKGROUND.set(colour_index + 16 * pal_index as usize, colour); } } diff --git a/examples/the-hat-chooses-the-wizard/src/main.rs b/examples/the-hat-chooses-the-wizard/src/main.rs index 1a3a0edc..de8f3ea9 100644 --- a/examples/the-hat-chooses-the-wizard/src/main.rs +++ b/examples/the-hat-chooses-the-wizard/src/main.rs @@ -273,8 +273,8 @@ impl<'a, 'b> Map<'a, 'b> { self.background.set_pos(vram, self.position.floor()); self.foreground.set_pos(vram, self.position.floor()); - self.background.commit(); - self.foreground.commit(); + self.background.commit(vram); + self.foreground.commit(vram); } pub fn init_background(&mut self, vram: &mut VRamManager) -> PartialUpdateStatus { @@ -793,7 +793,7 @@ fn main(mut agb: agb::Gba) -> ! { } } - world_display.commit(); + world_display.commit(&mut vram); world_display.show(); splash_screen::show_splash_screen( @@ -835,7 +835,7 @@ fn main(mut agb: agb::Gba) -> ! { &mut vram, ); - world_display.commit(); + world_display.commit(&mut vram); world_display.show(); music_box.before_frame(&mut mixer); diff --git a/examples/the-hat-chooses-the-wizard/src/splash_screen.rs b/examples/the-hat-chooses-the-wizard/src/splash_screen.rs index b39e39f9..64243b9b 100644 --- a/examples/the-hat-chooses-the-wizard/src/splash_screen.rs +++ b/examples/the-hat-chooses-the-wizard/src/splash_screen.rs @@ -76,7 +76,7 @@ pub fn show_splash_screen( } } - map.commit(); + map.commit(vram); vram.set_background_palettes(palette); map.show(); diff --git a/examples/the-purple-night/src/main.rs b/examples/the-purple-night/src/main.rs index ea822c4d..930f7cd9 100644 --- a/examples/the-purple-night/src/main.rs +++ b/examples/the-purple-night/src/main.rs @@ -85,9 +85,9 @@ impl<'a> Level<'a> { foreground.init(vram, start_pos, &mut between_updates); clouds.init(vram, start_pos / 4, &mut between_updates); - backdrop.commit(); - foreground.commit(); - clouds.commit(); + backdrop.commit(vram); + foreground.commit(vram); + clouds.commit(vram); backdrop.show(); foreground.show(); @@ -2081,9 +2081,9 @@ impl<'a> Game<'a> { .commit_with_fudge(this_frame_offset, (0, 0).into()); } - self.level.background.commit(); - self.level.foreground.commit(); - self.level.clouds.commit(); + self.level.background.commit(vram); + self.level.foreground.commit(vram); + self.level.clouds.commit(vram); for i in remove { self.particles.remove(i);