From 9527d32521265f389d6c8c591127b56cc5d107ec Mon Sep 17 00:00:00 2001 From: Corwin Kuiper Date: Sun, 7 Mar 2021 00:47:39 +0000 Subject: [PATCH] allow only one vblank handler --- examples/bitmap3.rs | 7 ++---- examples/bitmap4.rs | 11 ++++----- src/display/mod.rs | 57 ++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 57 insertions(+), 18 deletions(-) diff --git a/examples/bitmap3.rs b/examples/bitmap3.rs index 584d8ccc..ebb13ac0 100644 --- a/examples/bitmap3.rs +++ b/examples/bitmap3.rs @@ -14,6 +14,7 @@ struct Vector2D { fn main(_argc: isize, _argv: *const *const u8) -> isize { let gba = gba::Gba::new(); let bitmap = gba.display.bitmap3(); + let vblank = gba.display.get_vblank(); let mut input = gba::input::ButtonController::new(); let mut pos = Vector2D { @@ -21,12 +22,8 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize { y: display::HEIGHT / 2, }; - gba::interrupt::enable(gba::interrupt::Interrupt::VBlank); - gba::interrupt::enable_interrupts(); - gba::display::enable_VBlank_interrupt(); - loop { - gba::display::wait_for_VBlank(); + vblank.wait_for_VBlank(); input.update(); pos.x += input.x_tri() as i32; diff --git a/examples/bitmap4.rs b/examples/bitmap4.rs index 07996436..7cb2a1e8 100644 --- a/examples/bitmap4.rs +++ b/examples/bitmap4.rs @@ -9,6 +9,7 @@ use gba::display; fn main(_argc: isize, _argv: *const *const u8) -> isize { let gba = gba::Gba::new(); let bitmap = gba.display.bitmap4(); + let vblank = gba.display.get_vblank(); bitmap.set_palette_entry(1, 0x001F); bitmap.set_palette_entry(2, 0x03E0); @@ -17,23 +18,19 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize { display::WIDTH / 2, display::HEIGHT / 2, 1, - display::Page::Front, + display::bitmap4::Page::Front, ); bitmap.draw_point_page( display::WIDTH / 2 + 5, display::HEIGHT / 2, 2, - display::Page::Back, + display::bitmap4::Page::Back, ); - gba::interrupt::enable(gba::interrupt::Interrupt::VBlank); - gba::interrupt::enable_interrupts(); - gba::display::enable_VBlank_interrupt(); - let mut count = 0; loop { - gba::display::wait_for_VBlank(); + vblank.wait_for_VBlank(); count += 1; if count % 6 == 0 { bitmap.flip_page(); diff --git a/src/display/mod.rs b/src/display/mod.rs index 2bbcb8db..3901074f 100644 --- a/src/display/mod.rs +++ b/src/display/mod.rs @@ -1,11 +1,14 @@ -use crate::{memory_mapped::MemoryMapped, single::Single}; +use crate::{ + memory_mapped::MemoryMapped, + single::{Single, SingleToken}, +}; use bitflags::bitflags; use bitmap3::Bitmap3; use bitmap4::Bitmap4; -mod bitmap3; -mod bitmap4; +pub mod bitmap3; +pub mod bitmap4; const DISPLAY_CONTROL: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0000) }; const DISPLAY_STATUS: MemoryMapped = unsafe { MemoryMapped::new(0x0400_0004) }; @@ -42,12 +45,14 @@ pub enum DisplayMode { pub struct Display { in_mode: Single, + vblank: Single, } impl Display { pub(crate) const unsafe fn new() -> Self { Display { in_mode: Single::new(), + vblank: Single::new(), } } @@ -65,6 +70,15 @@ impl Display { .expect("Cannot create new mode as mode already taken"), ) } + pub fn get_vblank(&self) -> VBlank { + unsafe { + VBlank::new( + self.vblank + .take() + .expect("Cannot create another vblank handler"), + ) + } + } } fn set_graphics_mode(mode: DisplayMode) { @@ -85,18 +99,49 @@ pub fn set_graphics_settings(settings: GraphicsSettings) { } #[allow(non_snake_case)] +/// Waits until vblank using a busy wait loop, this should almost never be used. +/// I only say almost because whilst I don't believe there to be a reason to use +/// this I can't rule it out. pub fn busy_wait_for_VBlank() { while VCOUNT.get() >= 160 {} while VCOUNT.get() < 160 {} } +pub struct VBlank<'a> { + _got: SingleToken<'a>, +} + +impl<'a> VBlank<'a> { + unsafe fn new(a: SingleToken<'a>) -> Self { + crate::interrupt::enable_interrupts(); + crate::interrupt::enable(crate::interrupt::Interrupt::VBlank); + enable_VBlank_interrupt(); + VBlank { _got: a } + } + + #[allow(non_snake_case)] + pub fn wait_for_VBlank(&self) { + crate::syscall::wait_for_VBlank(); + } +} + +impl<'a> Drop for VBlank<'a> { + fn drop(&mut self) { + unsafe { + disable_VBlank_interrupt(); + crate::interrupt::disable(crate::interrupt::Interrupt::VBlank); + } + } +} + #[allow(non_snake_case)] -pub fn enable_VBlank_interrupt() { +unsafe fn enable_VBlank_interrupt() { let status = DISPLAY_STATUS.get() | (1 << 3); DISPLAY_STATUS.set(status); } #[allow(non_snake_case)] -pub fn wait_for_VBlank() { - crate::syscall::wait_for_VBlank(); +unsafe fn disable_VBlank_interrupt() { + let status = DISPLAY_STATUS.get() & !(1 << 3); + DISPLAY_STATUS.set(status); }