diff --git a/luma_core/src/lib.rs b/luma_core/src/lib.rs index 962b0b4..dbcaa54 100644 --- a/luma_core/src/lib.rs +++ b/luma_core/src/lib.rs @@ -80,6 +80,98 @@ impl fmt::Write for DolphinHle { macro_rules! println { ($($arg:tt)*) => {{ use luma_core::DolphinHle; + use core::fmt::Write; write!(DolphinHle, $($arg)*).unwrap(); }}; } + +pub mod framebuffer { + use crate::vi::Xfb; + extern crate alloc; + + #[derive(Copy, Clone)] + pub struct Rgba { + pub r: u8, + pub g: u8, + pub b: u8, + pub a: u8, + } + + #[derive(Copy, Clone, Default)] + #[repr(align(4))] + pub struct Yuv444 { + y: u8, + u: i8, + v: i8, + } + + #[derive(Copy, Clone, Default)] + pub struct Yuv422 { + pub y: u8, + pub uv: u8, + } + + impl Yuv422 { + pub fn as_u16(&self) -> u16 { + u16::from(self.y) << 8 | u16::from(self.uv) + } + pub fn into_u16(self) -> u16 { + u16::from(self.y) << 8 | u16::from(self.uv) + } + } + + pub fn rgba_to_yuv444(rgba: Rgba) -> Yuv444 { + let r = f64::from(rgba.r); + let g = f64::from(rgba.g); + let b = f64::from(rgba.b); + + let y_f64 = (0.299 * r) + (0.587 * g) + (0.114 * b); + let u_f64 = -(0.168736 * r) - (0.331264 * g) + (0.5 * b); + let v_f64 = (0.5 * r) - (0.418688 * g) - (0.081312 * b); + + Yuv444 { + y: y_f64 as u8, + u: u_f64 as i8, + v: v_f64 as i8, + } + } + + pub fn rgba_to_xfb(xfb: &mut Xfb, rgba_framebuf: &mut [Rgba]) { + const XFB_MAX_WIDTH: usize = 640; + let width = xfb.width(); + let height = xfb.height(); + + let mut scanline = [Yuv444::default(); XFB_MAX_WIDTH]; + let mut packed_scanline = [Yuv422::default(); XFB_MAX_WIDTH]; + for y in 0..height { + let rgba_scanline = &rgba_framebuf[y * width..(y + 1) * width]; + + for (scl, rgba) in scanline.iter_mut().zip(rgba_scanline) { + *scl = rgba_to_yuv444(*rgba); + } + + for (pcked_scl_pair, scl_triple) in packed_scanline + .chunks_exact_mut(2) + .zip(scanline.windows(3).step_by(2)) + { + pcked_scl_pair[0].y = 16u8.saturating_add(scl_triple[1].y); + pcked_scl_pair[0].uv = (128f64 + + (0.25 * f64::from(scl_triple[0].u)) + + (0.5 * f64::from(scl_triple[1].u)) + + (0.25 * f64::from(scl_triple[2].u))) + as u8; + + pcked_scl_pair[1].y = 16u8.saturating_add(scanline[1].y); + pcked_scl_pair[1].uv = (128f64 + + (0.25 * f64::from(scl_triple[0].v)) + + (0.5 * f64::from(scl_triple[1].v)) + + (0.25 * f64::from(scl_triple[2].v))) + as u8; + } + if let Some(yuv) = xfb.iter_mut().nth(y) { + let len = yuv.len(); + yuv[..].copy_from_slice(&packed_scanline.map(Yuv422::into_u16)[..len]); + } + } + } +} diff --git a/luma_runtime/src/lib.rs b/luma_runtime/src/lib.rs index a593f93..abc705e 100644 --- a/luma_runtime/src/lib.rs +++ b/luma_runtime/src/lib.rs @@ -69,7 +69,7 @@ impl Termination for () {} /// This function is called on panic. #[cfg_attr(not(test), panic_handler)] -#[no_mangle] +//#[no_mangle] fn panic(info: &PanicInfo) -> ! { println!("{}", info); loop {} @@ -77,5 +77,5 @@ fn panic(info: &PanicInfo) -> ! { /// Error handler personality language item (current no-op, to satisfy clippy). #[cfg_attr(not(test), lang = "eh_personality")] -#[no_mangle] +//#[no_mangle] extern "C" fn rust_eh_personality() {} diff --git a/src/bin/vi-draw.rs b/src/bin/vi-draw.rs index 2ec2666..093b49d 100644 --- a/src/bin/vi-draw.rs +++ b/src/bin/vi-draw.rs @@ -7,7 +7,10 @@ extern crate luma_core; extern crate luma_runtime; -use luma_core::vi::{Vi, Xfb}; +use luma_core::{ + framebuffer::{rgba_to_xfb, Rgba}, + vi::{Vi, Xfb}, +}; // Constants used for the YUV conversion. const YR: i32 = (0.299 * (1 << 16) as f64) as i32; @@ -75,6 +78,7 @@ fn paint_pixels(xfb: &mut Xfb, padding: i32, time: i32) { } } +extern crate alloc; fn main() { // Setup the video interface. let xfb = Xfb::allocate(640, 480); @@ -82,11 +86,12 @@ fn main() { // First fill the XFB with white. let xfb = vi.xfb(); - for row in xfb.iter_mut() { - row.fill(0xff80); - } - - // Then draw to it as fast as we can. + let mut rgba = alloc::vec![Rgba { r: 255, g: 255, b: 255, a: 255}; xfb.width() * xfb.height()]; + rgba_to_xfb(xfb, &mut rgba); + luma_core::println!("GOT PAST RGBA"); + // for row in xfb.iter_mut() { + // row.fill(0xff80); + // } let mut i = 0; loop { paint_pixels(xfb, 20, i);