Skip to content

Commit

Permalink
Add an iterator over XFB rows
Browse files Browse the repository at this point in the history
This emits slices of u16, and allows users to not use unsafe for
drawing.
  • Loading branch information
linkmauve committed Dec 15, 2024
1 parent c107b6a commit 49ebfeb
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 34 deletions.
16 changes: 10 additions & 6 deletions luma_core/src/allocate.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
use alloc::alloc::{alloc, Layout};
use alloc::boxed::Box;
use core::pin::Pin;
use core::slice;

const CACHELINE: usize = 32;

/// Allocate a slice aligned to a cacheline, and return it pinned.
pub fn alloc_aligned(size: usize) -> Pin<Box<[u8]>> {
let layout = Layout::from_size_align(size, CACHELINE).unwrap();
let ptr = unsafe { alloc(layout) };
let boxed = unsafe { Box::from_raw(ptr) };
let slice = Box::into_boxed_slice(boxed);
Pin::from(slice)
pub fn alloc_aligned<T: Copy>(size: usize) -> Pin<Box<[T]>> {
let layout = Layout::array::<T>(size)
.unwrap()
.align_to(CACHELINE)
.unwrap();
let ptr = unsafe { alloc(layout) } as *mut T;
let slice = unsafe { slice::from_raw_parts(ptr, size) };
let boxed = Box::from(slice);
Pin::from(boxed)
}

/// Allocate an array aligned to a cacheline, and return it pinned.
Expand Down
36 changes: 27 additions & 9 deletions luma_core/src/vi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,20 @@ use crate::allocate::alloc_aligned;
use crate::io::{read16, write16, write32};
use alloc::boxed::Box;
use core::pin::Pin;
use core::slice::{Chunks, ChunksMut};

/// A struct representing the eXternal FrameBuffer, or XFB. It represents the image that will be
/// sent to the screen, in YUYV format. It must be allocated as contiguous physical memory.
pub struct Xfb {
data: Pin<Box<[u8]>>,
data: Pin<Box<[u16]>>,
width: usize,
height: usize,
}

impl Xfb {
/// Allocate an XFB with the given width and height.
pub fn allocate(width: usize, height: usize) -> Xfb {
let stride = width * 2;
let stride = width;
let data = alloc_aligned(stride * height);
Xfb {
data,
Expand All @@ -37,19 +38,36 @@ impl Xfb {
self.height
}

/// Get the stride of this XFB, given the YUYV format this is always width × 2.
pub fn stride(&self) -> usize {
// YUYV always takes two bytes per pixel.
self.width * 2
/// Get the stride of this XFB. This is always equal to width for now.
pub fn stride_in_u16(&self) -> usize {
self.width
}

/// Get the stride of this XFB in bytes. Given the YUYV format this is always equal to
/// stride_in_u16() × 2.
pub fn stride_in_u8(&self) -> usize {
self.stride_in_u16() * 2
}

/// Get an immutable iterator over the rows of this XFB.
pub fn iter(&self) -> Chunks<u16> {
let stride = self.stride_in_u16();
self.data.chunks(stride)
}

/// Get a mutable iterator over the rows of this XFB.
pub fn iter_mut(&mut self) -> ChunksMut<u16> {
let stride = self.stride_in_u16();
self.data.chunks_mut(stride)
}

/// Return the raw pointer to this XFB.
pub fn as_ptr(&self) -> *const u8 {
pub fn as_ptr(&self) -> *const u16 {
self.data.as_ptr()
}

/// Return the raw mutable pointer to this XFB.
pub fn as_mut_ptr(&mut self) -> *mut u8 {
pub fn as_mut_ptr(&mut self) -> *mut u16 {
self.data.as_mut_ptr()
}
}
Expand Down Expand Up @@ -119,7 +137,7 @@ unsafe fn set_burst_blanking_interval_2(be2: u32, bs2: u32, be4: u32, bs4: u32)
}

unsafe fn set_xfb(addr: u32, xfb: &Xfb, bottom: bool) {
let stride = xfb.stride() as u32;
let stride = xfb.stride_in_u8() as u32;
let xfb = xfb.as_ptr();
let mut xfb = xfb as u32;
let shift;

Check warning on line 143 in luma_core/src/vi.rs

View workflow job for this annotation

GitHub Actions / Lints

unneeded late initialization
Expand Down
36 changes: 17 additions & 19 deletions src/bin/vi-draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ const fn rgba2yuyv(pixel: i32, odd: bool) -> u16 {
}

/// Ported from Weston’s clients/simple-shm.c
fn paint_pixels(mut image: *mut u16, padding: i32, width: i32, height: i32, time: i32) {
fn paint_pixels(xfb: &mut Xfb, padding: i32, time: i32) {
let width = xfb.width() as i32;
let height = xfb.height() as i32;
let mut rows = xfb.iter_mut().skip(padding as usize);

let halfh = padding + (height - padding * 2) / 2;
let halfw = padding + (width - padding * 2) / 2;

Expand All @@ -50,30 +54,24 @@ fn paint_pixels(mut image: *mut u16, padding: i32, width: i32, height: i32, time
or *= or;
ir *= ir;

image = unsafe { image.offset((padding * width) as isize) };
for y in padding..(height - padding) {
let y2 = (y - halfh) * (y - halfh);
let row = rows.next().unwrap();

image = unsafe { image.offset(padding as isize) };
let y2 = (y - halfh) * (y - halfh);
for x in padding..(width - padding) {
let v;

/* squared distance from center */
let r2 = (x - halfw) * (x - halfw) + y2;

if r2 < ir {
v = (r2 / 32 + time / 4) * 0x0080401;
let v = if r2 < ir {
(r2 / 32 + time / 4) * 0x0080401
} else if r2 < or {
v = (y + time / 2) * 0x0080401;
(y + time / 2) * 0x0080401
} else {
v = (x + time) * 0x0080401;
}
(x + time) * 0x0080401
};

unsafe { *image = rgba2yuyv(v, (x & 1) != 0) };
image = unsafe { image.offset(1) };
row[x as usize] = rgba2yuyv(v, (x & 1) != 0);
}

image = unsafe { image.offset(padding as isize) };
}
}

Expand All @@ -83,15 +81,15 @@ fn main() {
let mut vi = Vi::setup(xfb);

// First fill the XFB with white.
let xfb = vi.xfb().as_mut_ptr() as *mut u16;
for i in 0..(640 * 480) {
unsafe { xfb.offset(i).write(0xff80) };
let xfb = vi.xfb();
for row in xfb.iter_mut() {
row.fill(0xff80);
}

// Then draw to it as fast as we can.
let mut i = 0;
loop {
paint_pixels(xfb, 20, 640, 480, i);
paint_pixels(xfb, 20, i);
i += 1;
}
}

0 comments on commit 49ebfeb

Please sign in to comment.