Skip to content

Commit 70e7d3c

Browse files
committed
Don't use a critical-section Mutex to hold mode info.
Locking the mutex costs too much - it mades the video lose sync. Not helped by the fact the acquire function is stored in flash and is not inlined. Store the mode info as two atomic values instead.
1 parent e104619 commit 70e7d3c

File tree

1 file changed

+32
-20
lines changed

1 file changed

+32
-20
lines changed

src/vga/mod.rs

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@ mod rgb;
4242

4343
use crate::hal::{self, pac::interrupt, pio::PIOExt};
4444
use core::{
45-
cell::{RefCell, UnsafeCell},
45+
cell::UnsafeCell,
4646
ptr::addr_of_mut,
4747
sync::atomic::{AtomicBool, AtomicU16, AtomicU32, Ordering},
4848
};
4949
use defmt::{debug, trace};
5050
use neotron_common_bios::video::{Attr, GlyphAttr, TextBackgroundColour, TextForegroundColour};
5151

52-
use portable_atomic::AtomicUsize;
52+
use core::sync::atomic::{AtomicU8, AtomicUsize};
5353
pub use rgb::{RGBColour, RGBPair};
5454

5555
// -----------------------------------------------------------------------------
@@ -71,22 +71,23 @@ pub struct ModeInfo {
7171
/// Holds a video mode and a pointer, but as an atomic value suitable for use in
7272
/// a `static`.
7373
pub struct VideoMode {
74-
inner: critical_section::Mutex<RefCell<ModeInfo>>,
74+
raw_mode: AtomicU8,
75+
raw_ptr: AtomicUsize,
7576
}
7677

7778
unsafe impl Sync for VideoMode {}
7879

7980
impl VideoMode {
8081
/// Construct a new [`NewModeWrapper`] with the given mode.
8182
const fn new() -> VideoMode {
83+
let mode = neotron_common_bios::video::Mode::new(
84+
neotron_common_bios::video::Timing::T640x480,
85+
neotron_common_bios::video::Format::Text8x16,
86+
);
87+
let ptr = 0;
8288
VideoMode {
83-
inner: critical_section::Mutex::new(RefCell::new(ModeInfo {
84-
mode: neotron_common_bios::video::Mode::new(
85-
neotron_common_bios::video::Timing::T640x480,
86-
neotron_common_bios::video::Format::Text8x16,
87-
),
88-
ptr: core::ptr::null_mut(),
89-
})),
89+
raw_mode: AtomicU8::new(mode.as_u8()),
90+
raw_ptr: AtomicUsize::new(ptr),
9091
}
9192
}
9293

@@ -95,17 +96,19 @@ impl VideoMode {
9596
if modeinfo.ptr.is_null() {
9697
modeinfo.ptr = GLYPH_ATTR_ARRAY.as_ptr() as *mut u32;
9798
}
98-
critical_section::with(|cs| {
99-
self.inner.replace(cs, modeinfo);
100-
})
99+
self.raw_mode
100+
.store(modeinfo.mode.as_u8(), Ordering::Relaxed);
101+
self.raw_ptr.store(modeinfo.ptr as usize, Ordering::Relaxed);
101102
}
102103

103104
/// Get the current video mode.
104105
pub fn get_mode(&self) -> ModeInfo {
105-
let mut modeinfo = critical_section::with(|cs| {
106-
let info = self.inner.borrow_ref(cs);
107-
*info
108-
});
106+
let raw_mode = self.raw_mode.load(Ordering::Relaxed);
107+
let raw_ptr = self.raw_ptr.load(Ordering::Relaxed);
108+
let mut modeinfo = ModeInfo {
109+
mode: unsafe { neotron_common_bios::video::Mode::from_u8(raw_mode) },
110+
ptr: raw_ptr as *mut u32,
111+
};
109112
if modeinfo.ptr.is_null() {
110113
modeinfo.ptr = GLYPH_ATTR_ARRAY.as_ptr() as *mut u32;
111114
}
@@ -176,10 +179,19 @@ impl RenderEngine {
176179
self.frame_count += 1;
177180

178181
// Update video mode only on first line of video
179-
let modeinfo = VIDEO_MODE.get_mode();
180-
self.current_video_ptr = modeinfo.ptr;
181-
self.current_video_mode = modeinfo.mode;
182+
loop {
183+
let modeinfo = VIDEO_MODE.get_mode();
184+
self.current_video_ptr = modeinfo.ptr;
185+
self.current_video_mode = modeinfo.mode;
186+
let modeinfo2 = VIDEO_MODE.get_mode();
187+
// make sure we get these two as a pair and they can't update one without the other
188+
if modeinfo.mode == modeinfo2.mode {
189+
break;
190+
}
191+
}
192+
// Tell the ISR to now generate our newly chosen timing
182193
CURRENT_TIMING_MODE.store(self.current_video_mode.timing() as usize, Ordering::Relaxed);
194+
// set up our text console to be the right size
183195
self.num_text_cols = self.current_video_mode.text_width().unwrap_or(0) as usize;
184196
self.num_text_rows = self.current_video_mode.text_height().unwrap_or(0) as usize;
185197
}

0 commit comments

Comments
 (0)