diff --git a/src/devices/graphical_debug/debug.rs b/src/devices/graphical_debug/debug.rs index f452dd3fa2..549e0b7eb3 100644 --- a/src/devices/graphical_debug/debug.rs +++ b/src/devices/graphical_debug/debug.rs @@ -38,8 +38,7 @@ impl DebugDisplay { self.scroll(d_y * 16); unsafe { - self.display - .sync(0, 0, self.display.width, self.display.height); + self.display.sync_screen(); } self.y = new_y; @@ -65,7 +64,12 @@ impl DebugDisplay { /// Draw a character fn char(&mut self, x: usize, y: usize, character: char, color: u32) { if x + 8 <= self.display.width && y + 16 <= self.display.height { - let mut dst = unsafe { self.display.data_mut().add(y * self.display.stride + x) }; + let phys_y = (self.display.offset_y + y) % self.display.height; + let mut dst = unsafe { + self.display + .data_mut() + .add(phys_y * self.display.stride + x) + }; let font_i = 16 * (character as usize); if font_i + 16 <= FONT.len() { @@ -78,7 +82,13 @@ impl DebugDisplay { } } } - dst = unsafe { dst.add(self.display.stride) }; + + let next_phys_y = (phys_y + row + 1) % self.display.height; + dst = unsafe { + self.display + .data_mut() + .add(next_phys_y * self.display.stride + x) + }; } } } @@ -86,12 +96,17 @@ impl DebugDisplay { /// Scroll the screen fn scroll(&mut self, lines: usize) { - let offset = cmp::min(self.display.height, lines) * self.display.stride; - let size = (self.display.stride * self.display.height) - offset; - unsafe { - let ptr = self.display.data_mut(); - ptr::copy(ptr.add(offset), ptr, size); - ptr::write_bytes(ptr.add(size), 0, offset); + let lines = cmp::min(self.h * 16, lines); // clamp + self.display.offset_y = (self.display.offset_y + lines) % self.display.height; + + // clear the new lines + let start_y = (self.display.offset_y + self.h * 16 - lines) % self.display.height; + for row in 0..lines { + let y = (start_y + row) % self.display.height; + unsafe { + let ptr = self.display.data_mut().add(y * self.display.stride); + ptr::write_bytes(ptr, 0, self.display.stride); + } } } } diff --git a/src/devices/graphical_debug/display.rs b/src/devices/graphical_debug/display.rs index 0cd5792042..99f2eadea9 100644 --- a/src/devices/graphical_debug/display.rs +++ b/src/devices/graphical_debug/display.rs @@ -8,6 +8,7 @@ pub(super) struct Display { pub(super) stride: usize, onscreen_ptr: *mut u32, offscreen: Option>, + pub(super) offset_y: usize, } unsafe impl Send for Display {} @@ -28,6 +29,7 @@ impl Display { stride, onscreen_ptr, offscreen: None, + offset_y: 0, } } @@ -47,16 +49,41 @@ impl Display { /// Sync from offscreen to onscreen, unsafe because it trusts provided x, y, w, h pub(super) unsafe fn sync(&mut self, x: usize, y: usize, w: usize, mut h: usize) { if let Some(offscreen) = &self.offscreen { - let mut offset = y * self.stride + x; + let mut y = y; while h > 0 { + let src_y = (self.offset_y + y) % self.height; + let src_offset = src_y * self.stride + x; + let dst_offset = y * self.stride + x; + ptr::copy( - offscreen.as_ptr().add(offset), - self.onscreen_ptr.add(offset), + offscreen.as_ptr().add(src_offset), + self.onscreen_ptr.add(dst_offset), w, ); - offset += self.stride; + + y += 1; h -= 1; } } } + + // sync the whole screen (faster) + pub(super) unsafe fn sync_screen(&mut self) { + if let Some(offscreen) = &self.offscreen { + let stride_bytes = self.stride; + let first_part_len = (self.height - self.offset_y) * stride_bytes; + let second_part_len = self.offset_y * stride_bytes; + + ptr::copy( + offscreen.as_ptr().add(self.offset_y * stride_bytes), + self.onscreen_ptr, + first_part_len, + ); + ptr::copy( + offscreen.as_ptr(), + self.onscreen_ptr.add(first_part_len), + second_part_len, + ); + } + } }