Compare commits

...

3 Commits

Author SHA1 Message Date
Rekai Nyangadzayi Musuka cc0cb0dd8a chore(apu): satisfy clippy
continuous-integration/drone/push Build is passing Details
2021-07-15 22:58:23 -05:00
Rekai Nyangadzayi Musuka fd9a5b51ba chore(ppu): reimplement background/window/sprite priority 2021-07-15 22:29:51 -05:00
Rekai Nyangadzayi Musuka b9a798d0ad chore: update dependencies 2021-07-15 18:09:44 -05:00
5 changed files with 104 additions and 79 deletions

36
Cargo.lock generated
View File

@ -207,9 +207,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.68" version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
dependencies = [ dependencies = [
"jobserver", "jobserver",
] ]
@ -1009,9 +1009,9 @@ checksum = "90953f308a79fe6d62a4643e51f848fbfddcd05975a38e69fdf4ab86a7baf7ca"
[[package]] [[package]]
name = "instant" name = "instant"
version = "0.1.9" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
] ]
@ -1337,7 +1337,7 @@ checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab"
dependencies = [ dependencies = [
"jni-sys", "jni-sys",
"ndk-sys", "ndk-sys",
"num_enum 0.5.1", "num_enum 0.5.2",
"thiserror", "thiserror",
] ]
@ -1376,7 +1376,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d"
dependencies = [ dependencies = [
"darling", "darling",
"proc-macro-crate", "proc-macro-crate 0.1.5",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
@ -1475,12 +1475,12 @@ dependencies = [
[[package]] [[package]]
name = "num_enum" name = "num_enum"
version = "0.5.1" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "226b45a5c2ac4dd696ed30fa6b94b057ad909c7b7fc2e0d0808192bced894066" checksum = "e5adf0198d427ee515335639f275e806ca01acf9f07d7cf14bb36a10532a6169"
dependencies = [ dependencies = [
"derivative", "derivative",
"num_enum_derive 0.5.1", "num_enum_derive 0.5.2",
] ]
[[package]] [[package]]
@ -1489,7 +1489,7 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d" checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate 0.1.5",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
@ -1497,11 +1497,11 @@ dependencies = [
[[package]] [[package]]
name = "num_enum_derive" name = "num_enum_derive"
version = "0.5.1" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c0fd9eba1d5db0994a239e09c1be402d35622277e35468ba891aa5e3188ce7e" checksum = "b1def5a3f69d4707d8a040b12785b98029a39e8c610ae685c7f6265669767482"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate 1.0.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
@ -1660,6 +1660,16 @@ dependencies = [
"toml", "toml",
] ]
[[package]]
name = "proc-macro-crate"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41fdbd1df62156fbc5945f4762632564d7d038153091c3fcf1067f6aef7cff92"
dependencies = [
"thiserror",
"toml",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.27" version = "1.0.27"

View File

@ -6,7 +6,7 @@ use std::collections::VecDeque;
pub struct AudioMPSC; pub struct AudioMPSC;
impl AudioMPSC { impl AudioMPSC {
pub fn new() -> (AudioSender<f32>, AudioReceiver<f32>) { pub fn init() -> (AudioSender<f32>, AudioReceiver<f32>) {
// TODO: Can we provide an upper limit for this? // TODO: Can we provide an upper limit for this?
// The larger this channel is, the more lag there is between the Audio and // The larger this channel is, the more lag there is between the Audio and
// Emulator // Emulator

View File

@ -66,7 +66,7 @@ fn main() -> Result<()> {
(pixels, egui) (pixels, egui)
}; };
let (send, recv) = AudioMPSC::new(); let (send, recv) = AudioMPSC::init();
game_boy.set_audio_src(send); game_boy.set_audio_src(send);
// Initialize Audio // Initialize Audio

View File

@ -8,7 +8,7 @@ use std::convert::TryInto;
pub(crate) use types::PpuMode; pub(crate) use types::PpuMode;
use types::{ use types::{
BackgroundPalette, GrayShade, LCDControl, LCDStatus, ObjectFlags, ObjectPalette, BackgroundPalette, GrayShade, LCDControl, LCDStatus, ObjectFlags, ObjectPalette,
ObjectPaletteId, ObjectSize, Pixels, RenderPriority, TileDataAddress, ObjectPaletteKind, ObjectSize, Pixels, RenderPriority, TileDataAddress,
}; };
mod dma; mod dma;
@ -47,7 +47,7 @@ pub struct Ppu {
pub(crate) dma: DirectMemoryAccess, pub(crate) dma: DirectMemoryAccess,
scan_state: OamScanState, scan_state: OamScanState,
fetch: PixelFetcher, fetch: PixelFetcher,
fifo: FifoRenderer, fifo: PixelFifo,
obj_buffer: ObjectBuffer, obj_buffer: ObjectBuffer,
frame_buf: Box<[u8; GB_WIDTH * GB_HEIGHT * 4]>, frame_buf: Box<[u8; GB_WIDTH * GB_HEIGHT * 4]>,
window_stat: WindowStatus, window_stat: WindowStatus,
@ -282,10 +282,7 @@ impl Ppu {
let tbpp = Pixels::from_bytes(high, low); let tbpp = Pixels::from_bytes(high, low);
let palette = match attr.flags.palette() { let palette_kind = attr.flags.palette();
ObjectPaletteId::Zero => self.monochrome.obj_palette_0,
ObjectPaletteId::One => self.monochrome.obj_palette_1,
};
let end = Pixels::PIXEL_COUNT - self.fifo.obj.len(); let end = Pixels::PIXEL_COUNT - self.fifo.obj.len();
let start = Pixels::PIXEL_COUNT - end; let start = Pixels::PIXEL_COUNT - end;
@ -296,11 +293,11 @@ impl Ppu {
let x = if x_flip { 7 - i } else { i }; let x = if x_flip { 7 - i } else { i };
let priority = attr.flags.priority(); let priority = attr.flags.priority();
let shade = palette.shade(tbpp.shade_id(x)); let shade_id = tbpp.shade_id(x);
let fifo_info = ObjectFifoInfo { let fifo_info = ObjPixelProperty {
shade, shade_id,
palette, palette_kind,
priority, priority,
}; };
@ -368,9 +365,7 @@ impl Ppu {
self.fetch.back.next(SendToFifoTwo); self.fetch.back.next(SendToFifoTwo);
} }
SendToFifoTwo => { SendToFifoTwo => {
let palette = &self.monochrome.bg_palette; if let Ok(()) = self.fetch.send_to_fifo(&mut self.fifo) {
if let Ok(()) = self.fetch.send_to_fifo(&mut self.fifo, palette) {
self.fetch.x_pos += 1; self.fetch.x_pos += 1;
self.fetch.back.next(TileNumber); self.fetch.back.next(TileNumber);
self.fetch.back.tile = Default::default(); self.fetch.back.tile = Default::default();
@ -380,8 +375,6 @@ impl Ppu {
} }
if self.fifo.is_enabled() { if self.fifo.is_enabled() {
use RenderPriority::*;
if self.x_pos == 0 && !self.fifo.back.is_empty() { if self.x_pos == 0 && !self.fifo.back.is_empty() {
let to_discard = self.pos.scroll_x % 8; let to_discard = self.pos.scroll_x % 8;
@ -391,39 +384,12 @@ impl Ppu {
} }
// Handle Background Pixel and Sprite FIFO // Handle Background Pixel and Sprite FIFO
let bg_enabled = self.ctrl.bg_win_enabled(); if let Some(rgba) = self.clock_fifo().map(GrayShade::into_rgba) {
let obj_enabled = self.ctrl.obj_enabled();
let i0_colour = self.monochrome.bg_palette.i0_colour();
// FIXME: Is this the correct behaviour
let rgba_opt = self.fifo.back.pop_front().map(|bg_info| {
let bg_shade = if bg_enabled { bg_info.shade } else { i0_colour };
match self.fifo.obj.pop_front() {
Some(obj_info) => {
if obj_enabled {
match (obj_info.shade, obj_info.priority) {
(Some(obj_shade), BackgroundAndWindow) => match bg_info.shade {
GrayShade::White => obj_shade.into_rgba(),
_ => bg_shade.into_rgba(),
},
(Some(obj_shade), Object) => obj_shade.into_rgba(),
(None, _) => bg_shade.into_rgba(),
}
} else {
bg_shade.into_rgba()
}
}
None => bg_shade.into_rgba(),
}
});
if let Some(rgba) = rgba_opt.as_ref() {
let y = self.pos.line_y as usize; let y = self.pos.line_y as usize;
let x = self.x_pos as usize; let x = self.x_pos as usize;
let i = (GB_WIDTH * 4) * y + (x * 4); let i = (GB_WIDTH * 4) * y + (x * 4);
self.frame_buf[i..(i + rgba.len())].copy_from_slice(rgba); self.frame_buf[i..(i + rgba.len())].copy_from_slice(&rgba);
self.x_pos += 1; self.x_pos += 1;
} }
@ -442,6 +408,49 @@ impl Ppu {
pub fn copy_to_gui(&self, frame: &mut [u8]) { pub fn copy_to_gui(&self, frame: &mut [u8]) {
frame.copy_from_slice(self.frame_buf.as_ref()); frame.copy_from_slice(self.frame_buf.as_ref());
} }
fn clock_fifo(&mut self) -> Option<GrayShade> {
use ObjectPaletteKind::*;
use RenderPriority::*;
let obj_palette_0 = &self.monochrome.obj_palette_0;
let obj_palette_1 = &self.monochrome.obj_palette_1;
match self.fifo.back.pop_front() {
Some(bg_pixel) => match self.fifo.obj.pop_front() {
Some(obj_pixel) if self.ctrl.obj_enabled() => match obj_pixel.priority {
Object | BackgroundAndWindow if obj_pixel.shade_id == 0 => {
Some(self.bg_pixel(bg_pixel.shade_id))
}
BackgroundAndWindow if bg_pixel.shade_id != 0 => {
Some(self.bg_pixel(bg_pixel.shade_id))
}
Object | BackgroundAndWindow => {
let maybe_sprite = match obj_pixel.palette_kind {
Zero => obj_palette_0.shade(obj_pixel.shade_id),
One => obj_palette_1.shade(obj_pixel.shade_id),
};
let sprite = maybe_sprite
.expect("Sprite w/ a colour id of 0 has already been handled");
Some(sprite)
}
},
_ => Some(self.bg_pixel(bg_pixel.shade_id)),
},
None => None,
}
}
fn bg_pixel(&self, shade_id: u8) -> GrayShade {
let bg_palette = &self.monochrome.bg_palette;
if self.ctrl.bg_win_enabled() {
bg_palette.shade(shade_id)
} else {
bg_palette.shade(0)
}
}
} }
impl Default for Ppu { impl Default for Ppu {
@ -721,7 +730,7 @@ impl PixelFetcher {
tile_data_addr + (offset * 2) tile_data_addr + (offset * 2)
} }
fn send_to_fifo(&self, fifo: &mut FifoRenderer, palette: &BackgroundPalette) -> Result<(), ()> { fn send_to_fifo(&self, fifo: &mut PixelFifo) -> Result<(), ()> {
if !fifo.back.is_empty() { if !fifo.back.is_empty() {
return Err(()); return Err(());
} }
@ -735,9 +744,9 @@ impl PixelFetcher {
let tbpp = Pixels::from_bytes(high, low); let tbpp = Pixels::from_bytes(high, low);
for x in 0..Pixels::PIXEL_COUNT { for x in 0..Pixels::PIXEL_COUNT {
let shade = palette.shade(tbpp.shade_id(x)); let shade_id = tbpp.shade_id(x);
let fifo_info = BackgroundFifoInfo { shade }; let fifo_info = BgPixelProperty { shade_id };
fifo.back.push_back(fifo_info); fifo.back.push_back(fifo_info);
} }
@ -897,27 +906,27 @@ impl Default for FetcherState {
} }
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
struct BackgroundFifoInfo { struct BgPixelProperty {
shade: GrayShade, shade_id: u8,
} }
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
struct ObjectFifoInfo { struct ObjPixelProperty {
shade: Option<GrayShade>, shade_id: u8,
palette: ObjectPalette, palette_kind: ObjectPaletteKind,
priority: RenderPriority, priority: RenderPriority,
} }
// FIXME: Fifo Registers have a known size. Are heap allocations // FIXME: Fifo Registers have a known size. Are heap allocations
// really necessary here? // really necessary here?
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct FifoRenderer { struct PixelFifo {
back: VecDeque<BackgroundFifoInfo>, back: VecDeque<BgPixelProperty>,
obj: VecDeque<ObjectFifoInfo>, obj: VecDeque<ObjPixelProperty>,
enabled: bool, enabled: bool,
} }
impl FifoRenderer { impl PixelFifo {
fn is_enabled(&self) -> bool { fn is_enabled(&self) -> bool {
self.enabled self.enabled
} }
@ -931,7 +940,7 @@ impl FifoRenderer {
} }
} }
impl Default for FifoRenderer { impl Default for PixelFifo {
fn default() -> Self { fn default() -> Self {
Self { Self {
back: VecDeque::with_capacity(8), back: VecDeque::with_capacity(8),

View File

@ -332,7 +332,7 @@ bitfield! {
pub from into RenderPriority, priority, set_priority: 7, 7; pub from into RenderPriority, priority, set_priority: 7, 7;
pub y_flip, set_y_flip: 6; pub y_flip, set_y_flip: 6;
pub x_flip, set_x_flip: 5; pub x_flip, set_x_flip: 5;
pub from into ObjectPaletteId, palette, set_palette: 4, 4; pub from into ObjectPaletteKind, palette, set_palette: 4, 4;
} }
impl Eq for ObjectFlags {} impl Eq for ObjectFlags {}
@ -368,23 +368,29 @@ impl Default for ObjectFlags {
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum ObjectPaletteId { pub enum ObjectPaletteKind {
Zero = 0, Zero = 0,
One = 1, One = 1,
} }
impl From<u8> for ObjectPaletteId { impl Default for ObjectPaletteKind {
fn default() -> Self {
Self::Zero
}
}
impl From<u8> for ObjectPaletteKind {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte & 0b01 { match byte & 0b01 {
0b00 => ObjectPaletteId::Zero, 0b00 => ObjectPaletteKind::Zero,
0b01 => ObjectPaletteId::One, 0b01 => ObjectPaletteKind::One,
_ => unreachable!("{:#04X} is not a valid value for BgPaletteNumber", byte), _ => unreachable!("{:#04X} is not a valid value for BgPaletteNumber", byte),
} }
} }
} }
impl From<ObjectPaletteId> for u8 { impl From<ObjectPaletteKind> for u8 {
fn from(palette_num: ObjectPaletteId) -> Self { fn from(palette_num: ObjectPaletteKind) -> Self {
palette_num as u8 palette_num as u8
} }
} }