1use core::cell::Cell;
12use core::future::Future;
13use core::pin::Pin;
14use core::task::{Context, Poll};
15use portable_atomic::{AtomicBool, AtomicUsize, Ordering};
16
17use agb::display::GraphicsDist;
18use agb::interrupt::{add_interrupt_handler, Interrupt, VBlank};
19use embassy_sync::waitqueue::AtomicWaker;
20
21static VBLANK_COUNTER: AtomicUsize = AtomicUsize::new(0);
23
24static VBLANK_WAKER: AtomicWaker = AtomicWaker::new();
26
27static VBLANK_INITIALIZED: AtomicBool = AtomicBool::new(false);
29
30fn init_embassy_vblank() {
32 if VBLANK_INITIALIZED.swap(true, Ordering::SeqCst) {
33 return; }
35
36 let handler = unsafe {
37 add_interrupt_handler(Interrupt::VBlank, |_| {
38 VBLANK_COUNTER.store(VBLANK_COUNTER.load(Ordering::SeqCst) + 1, Ordering::SeqCst);
39 VBLANK_WAKER.wake();
40 })
41 };
42 core::mem::forget(handler);
43}
44
45pub struct AsyncDisplay<'a> {
47 graphics: agb::display::Graphics<'a>,
48 #[allow(dead_code)]
49 vblank: VBlank,
50}
51
52impl<'a> AsyncDisplay<'a> {
53 pub(crate) fn new(graphics_dist: &'a mut GraphicsDist) -> Self {
54 init_embassy_vblank();
55
56 Self {
57 graphics: graphics_dist.get(),
58 vblank: VBlank::get(),
59 }
60 }
61
62 pub async fn wait_for_vblank(&self) {
64 EmbassyVBlankFuture::new().await
65 }
66
67 pub async fn frame(&mut self) -> agb::display::GraphicsFrame<'_> {
69 self.wait_for_vblank().await;
70 self.graphics.frame()
71 }
72
73 pub fn frame_no_wait(&mut self) -> agb::display::GraphicsFrame<'_> {
76 self.graphics.frame()
77 }
78
79 pub fn graphics(&mut self) -> &mut agb::display::Graphics<'a> {
81 &mut self.graphics
82 }
83}
84
85struct EmbassyVBlankFuture {
87 last_count: Cell<usize>,
88}
89
90impl EmbassyVBlankFuture {
91 fn new() -> Self {
92 Self {
93 last_count: Cell::new(VBLANK_COUNTER.load(Ordering::SeqCst)),
94 }
95 }
96}
97
98impl Future for EmbassyVBlankFuture {
99 type Output = ();
100
101 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
102 let current_count = VBLANK_COUNTER.load(Ordering::SeqCst);
103 let last_count = self.last_count.get();
104
105 if current_count > last_count {
106 self.last_count.set(current_count);
108 Poll::Ready(())
109 } else {
110 VBLANK_WAKER.register(cx.waker());
112
113 let current_count = VBLANK_COUNTER.load(Ordering::SeqCst);
115 if current_count > last_count {
116 self.last_count.set(current_count);
117 Poll::Ready(())
118 } else {
119 Poll::Pending
120 }
121 }
122 }
123}
124
125pub struct DmaTransferFuture {
127 _phantom: core::marker::PhantomData<()>,
128}
129
130impl Future for DmaTransferFuture {
131 type Output = ();
132
133 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
134 Poll::Ready(())
137 }
138}