fix(ppu): ensure better timings for sprite fetcher
This commit is contained in:
parent
db1b40fe2d
commit
4f4c867a63
141
src/ppu.rs
141
src/ppu.rs
|
@ -168,45 +168,45 @@ 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;
|
||||||
|
|
||||||
// By only running on odd cycles, we can ensure that we draw every two T cycles
|
let line_y = self.pos.line_y;
|
||||||
if cycle % 2 != 0 {
|
let window_y = self.pos.window_y;
|
||||||
let control = &self.control;
|
let is_window = self.control.window_enabled() && window_y <= line_y;
|
||||||
let pos = &self.pos;
|
|
||||||
|
|
||||||
let line_y = self.pos.line_y;
|
// Determine whether we need to enable sprite fetching
|
||||||
let window_y = self.pos.window_y;
|
let mut obj_attr = None;
|
||||||
let is_window = self.control.window_enabled() && window_y <= line_y;
|
|
||||||
|
|
||||||
// Determine whether we need to enable sprite fetching
|
for i in 0..self.obj_buffer.len() {
|
||||||
let mut obj_attr = None;
|
if let Some(attr) = self.obj_buffer.get(i) {
|
||||||
for i in 0..self.obj_buffer.len() {
|
if attr.x <= (self.x_pos + 8) {
|
||||||
if let Some(attr) = self.obj_buffer.get(i) {
|
// self.fetcher.obj.resume(); TODO: Try running only when there's a sprite
|
||||||
if attr.x <= (self.x_pos + 8) {
|
self.fetcher.bg.reset();
|
||||||
// self.fetcher.obj.resume(); TODO: Try running only when there's a sprite
|
self.fetcher.bg.pause();
|
||||||
self.fetcher.bg.reset();
|
self.fifo.pause();
|
||||||
self.fetcher.bg.pause();
|
|
||||||
self.fifo.pause();
|
|
||||||
|
|
||||||
obj_attr = Some(attr);
|
obj_attr = Some(attr);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(attr) = obj_attr {
|
if let Some(attr) = obj_attr {
|
||||||
// Run the Object Fetcher
|
match self.fetcher.obj.state {
|
||||||
let obj_size = match self.control.obj_size() {
|
TileNumber => {
|
||||||
ObjectSize::EightByEight => 8,
|
if cycle % 2 != 0 {
|
||||||
ObjectSize::EightBySixteen => 16,
|
|
||||||
};
|
|
||||||
|
|
||||||
match self.fetcher.obj.state {
|
|
||||||
TileNumber => {
|
|
||||||
self.fetcher.obj.tile.with_id(attr.tile_index);
|
self.fetcher.obj.tile.with_id(attr.tile_index);
|
||||||
|
|
||||||
self.fetcher.obj.next(TileDataLow);
|
self.fetcher.obj.next(TileDataLow);
|
||||||
}
|
}
|
||||||
TileDataLow => {
|
}
|
||||||
|
TileDataLow => {
|
||||||
|
if cycle % 2 != 0 {
|
||||||
|
let obj_size = match self.control.obj_size() {
|
||||||
|
ObjectSize::EightByEight => 8,
|
||||||
|
ObjectSize::EightBySixteen => 16,
|
||||||
|
};
|
||||||
|
|
||||||
let addr = PixelFetcher::get_obj_low_addr(attr, &self.pos, obj_size);
|
let addr = PixelFetcher::get_obj_low_addr(attr, &self.pos, obj_size);
|
||||||
|
|
||||||
let byte = self.read_byte(addr);
|
let byte = self.read_byte(addr);
|
||||||
|
@ -214,7 +214,14 @@ impl Ppu {
|
||||||
|
|
||||||
self.fetcher.obj.next(TileDataHigh);
|
self.fetcher.obj.next(TileDataHigh);
|
||||||
}
|
}
|
||||||
TileDataHigh => {
|
}
|
||||||
|
TileDataHigh => {
|
||||||
|
if cycle % 2 != 0 {
|
||||||
|
let obj_size = match self.control.obj_size() {
|
||||||
|
ObjectSize::EightByEight => 8,
|
||||||
|
ObjectSize::EightBySixteen => 16,
|
||||||
|
};
|
||||||
|
|
||||||
let addr = PixelFetcher::get_obj_low_addr(attr, &self.pos, obj_size);
|
let addr = PixelFetcher::get_obj_low_addr(attr, &self.pos, obj_size);
|
||||||
|
|
||||||
let byte = self.read_byte(addr + 1);
|
let byte = self.read_byte(addr + 1);
|
||||||
|
@ -222,55 +229,57 @@ impl Ppu {
|
||||||
|
|
||||||
self.fetcher.obj.next(SendToFifo);
|
self.fetcher.obj.next(SendToFifo);
|
||||||
}
|
}
|
||||||
SendToFifo => {
|
}
|
||||||
self.fetcher.obj.fifo_count += 1;
|
SendToFifo => {
|
||||||
|
self.fetcher.obj.fifo_count += 1;
|
||||||
|
|
||||||
if self.fetcher.obj.fifo_count == 1 {
|
if self.fetcher.obj.fifo_count == 1 {
|
||||||
// Load into fifo
|
// Load into Fifo
|
||||||
let tile_bytes =
|
let tile_bytes = self.fetcher.obj.tile.low.zip(self.fetcher.obj.tile.high);
|
||||||
self.fetcher.obj.tile.low.zip(self.fetcher.obj.tile.high);
|
|
||||||
|
|
||||||
if let Some(bytes) = tile_bytes {
|
if let Some(bytes) = tile_bytes {
|
||||||
let low = bytes.0;
|
let low = bytes.0;
|
||||||
let high = bytes.1;
|
let high = bytes.1;
|
||||||
|
|
||||||
let pixel = TwoBitsPerPixel::from_bytes(high, low);
|
let pixel = TwoBitsPerPixel::from_bytes(high, low);
|
||||||
|
|
||||||
let palette = match attr.flags.palette() {
|
let palette = match attr.flags.palette() {
|
||||||
ObjectPaletteId::Palette0 => self.monochrome.obj_palette_0,
|
ObjectPaletteId::Palette0 => self.monochrome.obj_palette_0,
|
||||||
ObjectPaletteId::Palette1 => self.monochrome.obj_palette_1,
|
ObjectPaletteId::Palette1 => self.monochrome.obj_palette_1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let num_to_add = 8 - self.fifo.object.len();
|
||||||
|
|
||||||
|
for i in 0..num_to_add {
|
||||||
|
let bit = 7 - i;
|
||||||
|
|
||||||
|
let priority = attr.flags.priority();
|
||||||
|
|
||||||
|
let shade = palette.colour(pixel.pixel(bit));
|
||||||
|
|
||||||
|
let fifo_pixel = ObjectFifoPixel {
|
||||||
|
shade,
|
||||||
|
palette,
|
||||||
|
priority,
|
||||||
};
|
};
|
||||||
|
|
||||||
let num_to_add = 8 - self.fifo.object.len();
|
self.fifo.object.push_back(fifo_pixel);
|
||||||
|
|
||||||
for i in 0..num_to_add {
|
|
||||||
let bit = 7 - i;
|
|
||||||
|
|
||||||
let priority = attr.flags.priority();
|
|
||||||
|
|
||||||
let shade = palette.colour(pixel.pixel(bit));
|
|
||||||
|
|
||||||
let fifo_pixel = ObjectFifoPixel {
|
|
||||||
shade,
|
|
||||||
palette,
|
|
||||||
priority,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.fifo.object.push_back(fifo_pixel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if self.fetcher.obj.fifo_count == 2 {
|
|
||||||
self.fetcher.bg.resume();
|
self.fetcher.bg.resume();
|
||||||
self.fifo.resume();
|
self.fifo.resume();
|
||||||
|
|
||||||
self.fetcher.obj.reset();
|
|
||||||
} else {
|
|
||||||
panic!("Rekai Musuka <rekai@musuka.dev> is a bad programmer");
|
|
||||||
}
|
}
|
||||||
|
} else if self.fetcher.obj.fifo_count == 2 {
|
||||||
|
self.fetcher.obj.reset();
|
||||||
|
} else {
|
||||||
|
panic!("Object FIFO Logic Error has occurred :angry:");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// By only running on odd cycles, we can ensure that we draw every two T cycles
|
||||||
|
if cycle % 2 != 0 {
|
||||||
if self.fetcher.bg.is_enabled() {
|
if self.fetcher.bg.is_enabled() {
|
||||||
match self.fetcher.bg.state {
|
match self.fetcher.bg.state {
|
||||||
TileNumber => {
|
TileNumber => {
|
||||||
|
@ -316,8 +325,6 @@ impl Ppu {
|
||||||
self.fetcher.bg.next(TileNumber);
|
self.fetcher.bg.next(TileNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
self.fetcher.bg.resume();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,8 +346,6 @@ impl Ppu {
|
||||||
|
|
||||||
self.x_pos += 1;
|
self.x_pos += 1;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
self.fifo.resume();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue