Compare commits
No commits in common. "cc0cb0dd8af5b80d70e2b9743760cc8c076e359a" and "a1eadc0bc446c581ebed009ce7dd2cf35235a20c" have entirely different histories.
cc0cb0dd8a
...
a1eadc0bc4
|
@ -207,9 +207,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.69"
|
version = "1.0.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
|
checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
]
|
]
|
||||||
|
@ -1009,9 +1009,9 @@ checksum = "90953f308a79fe6d62a4643e51f848fbfddcd05975a38e69fdf4ab86a7baf7ca"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.10"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d"
|
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
|
||||||
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.2",
|
"num_enum 0.5.1",
|
||||||
"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 0.1.5",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
|
@ -1475,12 +1475,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_enum"
|
name = "num_enum"
|
||||||
version = "0.5.2"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5adf0198d427ee515335639f275e806ca01acf9f07d7cf14bb36a10532a6169"
|
checksum = "226b45a5c2ac4dd696ed30fa6b94b057ad909c7b7fc2e0d0808192bced894066"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derivative",
|
"derivative",
|
||||||
"num_enum_derive 0.5.2",
|
"num_enum_derive 0.5.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[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 0.1.5",
|
"proc-macro-crate",
|
||||||
"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.2"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1def5a3f69d4707d8a040b12785b98029a39e8c610ae685c7f6265669767482"
|
checksum = "1c0fd9eba1d5db0994a239e09c1be402d35622277e35468ba891aa5e3188ce7e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate 1.0.0",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
|
@ -1660,16 +1660,6 @@ 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"
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::collections::VecDeque;
|
||||||
pub struct AudioMPSC;
|
pub struct AudioMPSC;
|
||||||
|
|
||||||
impl AudioMPSC {
|
impl AudioMPSC {
|
||||||
pub fn init() -> (AudioSender<f32>, AudioReceiver<f32>) {
|
pub fn new() -> (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
|
||||||
|
|
|
@ -66,7 +66,7 @@ fn main() -> Result<()> {
|
||||||
(pixels, egui)
|
(pixels, egui)
|
||||||
};
|
};
|
||||||
|
|
||||||
let (send, recv) = AudioMPSC::init();
|
let (send, recv) = AudioMPSC::new();
|
||||||
game_boy.set_audio_src(send);
|
game_boy.set_audio_src(send);
|
||||||
|
|
||||||
// Initialize Audio
|
// Initialize Audio
|
||||||
|
|
123
src/ppu.rs
123
src/ppu.rs
|
@ -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,
|
||||||
ObjectPaletteKind, ObjectSize, Pixels, RenderPriority, TileDataAddress,
|
ObjectPaletteId, 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: PixelFifo,
|
fifo: FifoRenderer,
|
||||||
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,7 +282,10 @@ impl Ppu {
|
||||||
|
|
||||||
let tbpp = Pixels::from_bytes(high, low);
|
let tbpp = Pixels::from_bytes(high, low);
|
||||||
|
|
||||||
let palette_kind = attr.flags.palette();
|
let palette = match 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;
|
||||||
|
@ -293,11 +296,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_id = tbpp.shade_id(x);
|
let shade = palette.shade(tbpp.shade_id(x));
|
||||||
|
|
||||||
let fifo_info = ObjPixelProperty {
|
let fifo_info = ObjectFifoInfo {
|
||||||
shade_id,
|
shade,
|
||||||
palette_kind,
|
palette,
|
||||||
priority,
|
priority,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -365,7 +368,9 @@ impl Ppu {
|
||||||
self.fetch.back.next(SendToFifoTwo);
|
self.fetch.back.next(SendToFifoTwo);
|
||||||
}
|
}
|
||||||
SendToFifoTwo => {
|
SendToFifoTwo => {
|
||||||
if let Ok(()) = self.fetch.send_to_fifo(&mut self.fifo) {
|
let palette = &self.monochrome.bg_palette;
|
||||||
|
|
||||||
|
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();
|
||||||
|
@ -375,6 +380,8 @@ 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;
|
||||||
|
|
||||||
|
@ -384,12 +391,39 @@ impl Ppu {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Background Pixel and Sprite FIFO
|
// Handle Background Pixel and Sprite FIFO
|
||||||
if let Some(rgba) = self.clock_fifo().map(GrayShade::into_rgba) {
|
let bg_enabled = self.ctrl.bg_win_enabled();
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
@ -408,49 +442,6 @@ 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 {
|
||||||
|
@ -730,7 +721,7 @@ impl PixelFetcher {
|
||||||
tile_data_addr + (offset * 2)
|
tile_data_addr + (offset * 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_to_fifo(&self, fifo: &mut PixelFifo) -> Result<(), ()> {
|
fn send_to_fifo(&self, fifo: &mut FifoRenderer, palette: &BackgroundPalette) -> Result<(), ()> {
|
||||||
if !fifo.back.is_empty() {
|
if !fifo.back.is_empty() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
@ -744,9 +735,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_id = tbpp.shade_id(x);
|
let shade = palette.shade(tbpp.shade_id(x));
|
||||||
|
|
||||||
let fifo_info = BgPixelProperty { shade_id };
|
let fifo_info = BackgroundFifoInfo { shade };
|
||||||
fifo.back.push_back(fifo_info);
|
fifo.back.push_back(fifo_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -906,27 +897,27 @@ impl Default for FetcherState {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
struct BgPixelProperty {
|
struct BackgroundFifoInfo {
|
||||||
shade_id: u8,
|
shade: GrayShade,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
struct ObjPixelProperty {
|
struct ObjectFifoInfo {
|
||||||
shade_id: u8,
|
shade: Option<GrayShade>,
|
||||||
palette_kind: ObjectPaletteKind,
|
palette: ObjectPalette,
|
||||||
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 PixelFifo {
|
struct FifoRenderer {
|
||||||
back: VecDeque<BgPixelProperty>,
|
back: VecDeque<BackgroundFifoInfo>,
|
||||||
obj: VecDeque<ObjPixelProperty>,
|
obj: VecDeque<ObjectFifoInfo>,
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PixelFifo {
|
impl FifoRenderer {
|
||||||
fn is_enabled(&self) -> bool {
|
fn is_enabled(&self) -> bool {
|
||||||
self.enabled
|
self.enabled
|
||||||
}
|
}
|
||||||
|
@ -940,7 +931,7 @@ impl PixelFifo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PixelFifo {
|
impl Default for FifoRenderer {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
back: VecDeque::with_capacity(8),
|
back: VecDeque::with_capacity(8),
|
||||||
|
|
|
@ -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 ObjectPaletteKind, palette, set_palette: 4, 4;
|
pub from into ObjectPaletteId, palette, set_palette: 4, 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for ObjectFlags {}
|
impl Eq for ObjectFlags {}
|
||||||
|
@ -368,29 +368,23 @@ impl Default for ObjectFlags {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum ObjectPaletteKind {
|
pub enum ObjectPaletteId {
|
||||||
Zero = 0,
|
Zero = 0,
|
||||||
One = 1,
|
One = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ObjectPaletteKind {
|
impl From<u8> for ObjectPaletteId {
|
||||||
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 => ObjectPaletteKind::Zero,
|
0b00 => ObjectPaletteId::Zero,
|
||||||
0b01 => ObjectPaletteKind::One,
|
0b01 => ObjectPaletteId::One,
|
||||||
_ => unreachable!("{:#04X} is not a valid value for BgPaletteNumber", byte),
|
_ => unreachable!("{:#04X} is not a valid value for BgPaletteNumber", byte),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ObjectPaletteKind> for u8 {
|
impl From<ObjectPaletteId> for u8 {
|
||||||
fn from(palette_num: ObjectPaletteKind) -> Self {
|
fn from(palette_num: ObjectPaletteId) -> Self {
|
||||||
palette_num as u8
|
palette_num as u8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue