fix(ppu): reimplement the pixel fifo shifter
This commit is contained in:
parent
11398303b5
commit
b251efcc7d
75
src/ppu.rs
75
src/ppu.rs
|
@ -190,8 +190,6 @@ impl Ppu {
|
||||||
|
|
||||||
fn draw(&mut self, _cycle: u32) {
|
fn draw(&mut self, _cycle: u32) {
|
||||||
use FetcherState::*;
|
use FetcherState::*;
|
||||||
let control = &self.control;
|
|
||||||
let pos = &self.pos;
|
|
||||||
|
|
||||||
let iter = &mut self.obj_buffer.iter();
|
let iter = &mut self.obj_buffer.iter();
|
||||||
|
|
||||||
|
@ -298,8 +296,8 @@ impl Ppu {
|
||||||
let x_pos = self.fetcher.x_pos;
|
let x_pos = self.fetcher.x_pos;
|
||||||
|
|
||||||
let addr = self.fetcher.bg_tile_num_addr(
|
let addr = self.fetcher.bg_tile_num_addr(
|
||||||
control,
|
&self.control,
|
||||||
pos,
|
&self.pos,
|
||||||
x_pos,
|
x_pos,
|
||||||
self.window_stat.should_draw(),
|
self.window_stat.should_draw(),
|
||||||
);
|
);
|
||||||
|
@ -312,9 +310,11 @@ impl Ppu {
|
||||||
}
|
}
|
||||||
ToLowByteSleep => self.fetcher.bg.next(TileLowByte),
|
ToLowByteSleep => self.fetcher.bg.next(TileLowByte),
|
||||||
TileLowByte => {
|
TileLowByte => {
|
||||||
let addr =
|
let addr = self.fetcher.bg_byte_low_addr(
|
||||||
self.fetcher
|
&self.control,
|
||||||
.bg_byte_low_addr(control, pos, self.window_stat.should_draw());
|
&self.pos,
|
||||||
|
self.window_stat.should_draw(),
|
||||||
|
);
|
||||||
|
|
||||||
let low = self.read_byte(addr);
|
let low = self.read_byte(addr);
|
||||||
self.fetcher.bg.tile.with_low_byte(low);
|
self.fetcher.bg.tile.with_low_byte(low);
|
||||||
|
@ -323,9 +323,11 @@ impl Ppu {
|
||||||
}
|
}
|
||||||
ToHighByteSleep => self.fetcher.bg.next(TileHighByte),
|
ToHighByteSleep => self.fetcher.bg.next(TileHighByte),
|
||||||
TileHighByte => {
|
TileHighByte => {
|
||||||
let addr =
|
let addr = self.fetcher.bg_byte_low_addr(
|
||||||
self.fetcher
|
&self.control,
|
||||||
.bg_byte_low_addr(control, pos, self.window_stat.should_draw());
|
&self.pos,
|
||||||
|
self.window_stat.should_draw(),
|
||||||
|
);
|
||||||
|
|
||||||
let high = self.read_byte(addr + 1);
|
let high = self.read_byte(addr + 1);
|
||||||
self.fetcher.bg.tile.with_high_byte(high);
|
self.fetcher.bg.tile.with_high_byte(high);
|
||||||
|
@ -348,36 +350,43 @@ impl Ppu {
|
||||||
|
|
||||||
if self.fifo.is_enabled() {
|
if self.fifo.is_enabled() {
|
||||||
// Handle Background Pixel and Sprite FIFO
|
// Handle Background Pixel and Sprite FIFO
|
||||||
if let Some(bg_pixel) = self.fifo.background.pop_front() {
|
let bg_enabled = self.control.bg_win_enabled();
|
||||||
let rgba = match self.fifo.object.pop_front() {
|
// FIXME: Is this the correct behaviour
|
||||||
Some(obj_pixel) => match obj_pixel.shade {
|
let bg_zero_colour = self.monochrome.bg_palette.i0_colour();
|
||||||
Some(obj_shade) => {
|
|
||||||
if let RenderPriority::BackgroundAndWindow = obj_pixel.priority {
|
|
||||||
match bg_pixel.shade {
|
|
||||||
GrayShade::White => obj_shade.into_rgba(),
|
|
||||||
_ => bg_pixel.shade.into_rgba(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
obj_shade.into_rgba()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => bg_pixel.shade.into_rgba(),
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
// Only Background Pixels will be rendered
|
|
||||||
bg_pixel.shade.into_rgba()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
let maybe_rgba = self.fifo.background.pop_front().map(|bg_info| {
|
||||||
|
match self.fifo.object.pop_front() {
|
||||||
|
Some(obj_info) => match obj_info.shade {
|
||||||
|
Some(obj_shade) => match obj_info.priority {
|
||||||
|
RenderPriority::BackgroundAndWindow => match bg_info.shade {
|
||||||
|
GrayShade::White => obj_shade.into_rgba(),
|
||||||
|
_ if bg_enabled => bg_info.shade.into_rgba(),
|
||||||
|
_ => bg_zero_colour.into_rgba(),
|
||||||
|
},
|
||||||
|
RenderPriority::Object => obj_shade.into_rgba(),
|
||||||
|
},
|
||||||
|
None if bg_enabled => bg_info.shade.into_rgba(),
|
||||||
|
None => bg_zero_colour.into_rgba(),
|
||||||
|
},
|
||||||
|
None if bg_enabled => bg_info.shade.into_rgba(),
|
||||||
|
None => bg_zero_colour.into_rgba(),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(rgba) = maybe_rgba.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;
|
||||||
|
|
||||||
// Determine whether we should draw the window next frame
|
// Determine whether we should draw the window next frame
|
||||||
|
if self.pos.line_y == self.pos.window_y {
|
||||||
|
self.window_stat.set_coincidence(true);
|
||||||
|
}
|
||||||
|
|
||||||
if self.window_stat.coincidence()
|
if self.window_stat.coincidence()
|
||||||
&& self.control.window_enabled()
|
&& self.control.window_enabled()
|
||||||
&& self.x_pos >= self.pos.window_x - 7
|
&& self.x_pos >= self.pos.window_x - 7
|
||||||
|
@ -387,10 +396,6 @@ impl Ppu {
|
||||||
self.fifo.background.clear();
|
self.fifo.background.clear();
|
||||||
self.fetcher.x_pos = 0;
|
self.fetcher.x_pos = 0;
|
||||||
} else {
|
} else {
|
||||||
if self.pos.line_y == self.pos.window_y {
|
|
||||||
self.window_stat.set_coincidence(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.window_stat.set_should_draw(false);
|
self.window_stat.set_should_draw(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,8 +79,8 @@ bitfield! {
|
||||||
pub from into TileDataAddress, tile_data_addr, set_tile_data_addr: 4, 4;
|
pub from into TileDataAddress, tile_data_addr, set_tile_data_addr: 4, 4;
|
||||||
pub from into TileMapAddress, bg_tile_map_addr, set_bg_tile_map_addr: 3, 3;
|
pub from into TileMapAddress, bg_tile_map_addr, set_bg_tile_map_addr: 3, 3;
|
||||||
pub from into ObjectSize, obj_size, set_obj_size: 2, 2;
|
pub from into ObjectSize, obj_size, set_obj_size: 2, 2;
|
||||||
obj_enabled, set_obj_enabled: 1;
|
pub obj_enabled, set_obj_enabled: 1;
|
||||||
bg_win_enabled, set_bg_win_enabled: 0;
|
pub bg_win_enabled, set_bg_win_enabled: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Copy for LCDControl {}
|
impl Copy for LCDControl {}
|
||||||
|
@ -384,7 +384,7 @@ impl From<ObjectPaletteId> for u8 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum RenderPriority {
|
pub enum RenderPriority {
|
||||||
Object = 0,
|
Object = 0,
|
||||||
BackgroundAndWindow = 1,
|
BackgroundAndWindow = 1,
|
||||||
|
|
Loading…
Reference in New Issue