Skip to content

Commit

Permalink
Added tests for the start up frames
Browse files Browse the repository at this point in the history
  • Loading branch information
TylerBloom committed Sep 12, 2024
1 parent 855cfd7 commit 4f448af
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 7 deletions.
2 changes: 2 additions & 0 deletions spirit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ array-concat = "0.5.2"
# once_cell = "1.19"
tracing = "0.1.40"
heapless = "0.8.0"
serde = { version = "1.0.210", features = ["derive"] }

[dev-dependencies]
postcard = { version = "1.0.10", features = ["alloc"] }
test-log = "0.2.16"
21 changes: 14 additions & 7 deletions spirit/src/ppu.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{array, collections::VecDeque};
use std::{array, collections::VecDeque, fmt::Display};

use heapless::Vec as InlineVec;
use serde::{Deserialize, Serialize};
use tracing::{info_span, trace};

use crate::{
Expand Down Expand Up @@ -43,7 +44,7 @@ use crate::{
#[derive(Debug, Hash)]
pub struct Ppu {
/// Represents the LCD screen. The length of this will always be 144.
pub screen: Vec<[Pixel; 160]>,
pub screen: Vec<Vec<Pixel>>,
/// This FIFO pulls data from the memory map to construct the objects used in a scanline. This
/// process is controlled by the `PpuInner` state machine.
obj_fifo: ObjectFiFo,
Expand All @@ -59,7 +60,7 @@ impl Ppu {
pub(crate) fn new() -> Self {
Self {
inner: PpuInner::default(),
screen: vec![[Pixel::new(); 160]; 144],
screen: vec![vec![Pixel::new(); 160]; 144],
obj_fifo: ObjectFiFo::new(),
bg_fifo: BackgroundFiFo::new(),
}
Expand Down Expand Up @@ -108,7 +109,7 @@ enum StateTransition {
impl PpuInner {
fn tick(
&mut self,
screen: &mut [[Pixel; 160]],
screen: &mut [Vec<Pixel>],
obj: &mut ObjectFiFo,
bg: &mut BackgroundFiFo,
mem: &mut MemoryMap,
Expand Down Expand Up @@ -311,13 +312,19 @@ impl FiFoPixel {
}

/// The final pixel that is available to the end consumer.
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Pixel {
pub r: u8,
pub g: u8,
pub b: u8,
}

impl Display for Pixel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({}, {}, {})", self.r, self.b, self.g)
}
}

impl Pixel {
const WHITE: Self = Self {
r: 0x1F,
Expand Down Expand Up @@ -585,7 +592,7 @@ mod tests {
#[test]
fn test_scan_line_timing() {
let mut mem = MemoryMap::construct();
let mut screen = vec![[Pixel::new(); 160]; 144];
let mut screen = vec![vec![Pixel::new(); 160]; 144];
let mut ppu = PpuInner::default();
let mut state = ppu.state();
let mut counter = 0;
Expand All @@ -603,7 +610,7 @@ mod tests {
#[test]
fn test_frame_render_timing() {
let mut mem = MemoryMap::construct();
let mut screen = vec![[Pixel::new(); 160]; 144];
let mut screen = vec![vec![Pixel::new(); 160]; 144];
let mut ppu = PpuInner::default();
let mut state = ppu.state();
let mut counter = 0;
Expand Down
Binary file added spirit/tests/data/start_up_screens.postcard
Binary file not shown.
57 changes: 57 additions & 0 deletions spirit/tests/start_up.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use std::fmt::Display;

use spirit::{ppu::Pixel, Gameboy};

static START_UP_SCREENS: &[u8] = include_bytes!("data/start_up_screens.postcard");

/*
#[test]
fn generate_frames() {
let mut gb = Gameboy::new(include_bytes!("roms/acid/cgb-acid2.gbc")).start_up();
let mut frames = Vec::new();
while !gb.is_complete() {
gb.frame_step().complete();
frames.push(gb.gb().ppu.screen.clone());
}
let data = postcard::to_allocvec(&frames).unwrap();
std::fs::write("tests/data/start_up_screens.postcard", data).unwrap();
}
*/

#[test]
fn test_startup_frames() {
let states: Vec<Vec<Vec<Pixel>>> = postcard::from_bytes(START_UP_SCREENS).unwrap();
let mut gb = Gameboy::new(include_bytes!("roms/acid/cgb-acid2.gbc")).start_up();
for (frame_num, state) in states.into_iter().enumerate() {
assert_eq!(state.len(), 144);
gb.frame_step().complete();
for (line_num, (known, acutal)) in state.iter().zip(gb.gb().ppu.screen.iter()).enumerate() {
if known != acutal {
println!(
"On frame {frame_num}, line {line_num}, expected scanline: {}",
DisplaySlice(known)
);
println!("Found scanline: {}", DisplaySlice(acutal));
panic!("Mismatched frame #{frame_num}");
}
}
}
assert!(gb.is_complete());
}

struct DisplaySlice<'a, T>(&'a [T]);

impl<'a, T> Display for DisplaySlice<'a, T>
where
T: Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut iter = self.0.iter();
write!(f, "[")?;
if let Some(val) = iter.next() {
write!(f, "{val}");
}
iter.try_for_each(|val| write!(f, ", {val}"))?;
write!(f, "]")
}
}

0 comments on commit 4f448af

Please sign in to comment.