Skip to content

Commit

Permalink
FIx the bug with the missing vertical object lines
Browse files Browse the repository at this point in the history
The bug would ocour only for objects drawn with odd scx register.
Since the state machine of the sprite fetcher worked in steps
of 2 t_cycles it would miss some lines.
Moved the state machine to work for every t_cycle and not
for the even ones.
  • Loading branch information
alloncm committed Sep 3, 2021
1 parent 1926087 commit dff63cb
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 63 deletions.
13 changes: 12 additions & 1 deletion lib_gb/src/ppu/fifo/bg_fetcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub struct BGFetcher{
rendered_window:bool,
rendering_window:bool,
current_fetching_state:FethcingState,
t_cycles_counter:u8,
}

impl BGFetcher{
Expand All @@ -20,7 +21,8 @@ impl BGFetcher{
fifo:Vec::<u8>::with_capacity(8),
window_line_counter:0,
rendered_window:false,
rendering_window:false
rendering_window:false,
t_cycles_counter:0
}
}

Expand All @@ -30,10 +32,12 @@ impl BGFetcher{
self.current_fetching_state = FethcingState::TileNumber;
self.rendered_window = false;
self.rendering_window = false;
self.t_cycles_counter = 0;
}

pub fn pause(&mut self){
self.current_fetching_state = FethcingState::TileNumber;
self.t_cycles_counter = 0;
}

pub fn try_increment_window_counter(&mut self){
Expand All @@ -43,6 +47,11 @@ impl BGFetcher{
}

pub fn fetch_pixels(&mut self, vram:&VRam, lcd_control:u8, ly_register:u8, window_pos:&Vec2<u8>, bg_pos:&Vec2<u8>){
if self.t_cycles_counter % 2 == 0{
self.t_cycles_counter = (self.t_cycles_counter + 1) % 8;
return;
}

let last_rendering_status = self.rendering_window;
self.rendering_window = self.is_redering_wnd(lcd_control, window_pos, ly_register);
if self.rendering_window{
Expand Down Expand Up @@ -105,6 +114,8 @@ impl BGFetcher{
}
}
}

self.t_cycles_counter = (self.t_cycles_counter + 1) % 8;
}

fn get_tila_data_address(&self, lcd_control:u8, bg_pos:&Vec2<u8>, ly_register:u8, tile_num:u8)->u16{
Expand Down
48 changes: 24 additions & 24 deletions lib_gb/src/ppu/fifo/fifo_ppu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,31 +214,31 @@ impl<GFX:GfxDevice> FifoPpu<GFX>{
self.t_cycles_passed += 2;
}
PpuState::PixelTransfer=>{
if self.pixel_x_pos < 160{
if self.lcd_control & BIT_1_MASK != 0{
self.sprite_fetcher.fetch_pixels(&self.vram, self.lcd_control, self.ly_register, self.pixel_x_pos);
}
if self.sprite_fetcher.rendering{
self.bg_fetcher.pause();
}
else{
self.bg_fetcher.fetch_pixels(&self.vram, self.lcd_control, self.ly_register, &self.window_pos, &self.bg_pos);
for _ in 0..2{
self.try_push_to_lcd();
if self.pixel_x_pos == 160 {
self.state = PpuState::Hblank;
if self.h_blank_interrupt_request{
self.trigger_stat_interrupt = true;
}
self.bg_fetcher.try_increment_window_counter();
self.bg_fetcher.reset();
self.sprite_fetcher.reset();
for _ in 0..2{
if self.pixel_x_pos < 160{
if self.lcd_control & BIT_1_MASK != 0{
self.sprite_fetcher.fetch_pixels(&self.vram, self.lcd_control, self.ly_register, self.pixel_x_pos);
}
if self.sprite_fetcher.rendering{
self.bg_fetcher.pause();
}
else{
self.bg_fetcher.fetch_pixels(&self.vram, self.lcd_control, self.ly_register, &self.window_pos, &self.bg_pos);
self.try_push_to_lcd();
if self.pixel_x_pos == 160 {
self.state = PpuState::Hblank;
if self.h_blank_interrupt_request{
self.trigger_stat_interrupt = true;
}
self.bg_fetcher.try_increment_window_counter();
self.bg_fetcher.reset();
self.sprite_fetcher.reset();

// If im on the first iteration and finished the 160 pixels break;
// In this case the number of t_cycles should be eneven but it will break
// my code way too much for now so Im leaving this as it is... (maybe in the future)
break;
}
// If im on the first iteration and finished the 160 pixels break;
// In this case the number of t_cycles should be eneven but it will break
// my code way too much for now so Im leaving this as it is... (maybe in the future)
break;
}
}
}
}
Expand Down
88 changes: 50 additions & 38 deletions lib_gb/src/ppu/fifo/sprite_fetcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub struct SpriteFetcher{

current_fetching_state:FethcingState,
current_oam_entry:u8,
t_cycle_inner_state_counter:u8,
}

impl SpriteFetcher{
Expand All @@ -34,14 +35,16 @@ impl SpriteFetcher{
oam_entries_len:0,
oam_entries,
fifo:Vec::<(u8,u8)>::with_capacity(8),
rendering:false
rendering:false,
t_cycle_inner_state_counter:0,
}
}

pub fn reset(&mut self){
self.current_oam_entry = 0;
self.oam_entries_len = 0;
self.current_fetching_state = FethcingState::TileNumber;
self.t_cycle_inner_state_counter = 0;
self.fifo.clear();
self.rendering = false;
}
Expand All @@ -67,54 +70,63 @@ impl SpriteFetcher{
self.rendering = false;
}
FethcingState::LowTileData(tile_num)=>{
let oam_attribute = &self.oam_entries[self.current_oam_entry as usize];
let current_tile_data_address = Self::get_current_tile_data_address(ly_register, oam_attribute, sprite_size, tile_num);
let low_data = vram.read_current_bank(current_tile_data_address);
self.current_fetching_state = FethcingState::HighTileData(tile_num, low_data);
if self.t_cycle_inner_state_counter % 2 != 0{
let oam_attribute = &self.oam_entries[self.current_oam_entry as usize];
let current_tile_data_address = Self::get_current_tile_data_address(ly_register, oam_attribute, sprite_size, tile_num);
let low_data = vram.read_current_bank(current_tile_data_address);
self.current_fetching_state = FethcingState::HighTileData(tile_num, low_data);
}
}
FethcingState::HighTileData(tile_num, low_data)=>{
let oam_attribute = &self.oam_entries[self.current_oam_entry as usize];
let current_tile_data_address = Self::get_current_tile_data_address(ly_register, oam_attribute, sprite_size, tile_num);
let high_data = vram.read_current_bank(current_tile_data_address + 1);
self.current_fetching_state = FethcingState::Push(low_data, high_data);
if self.t_cycle_inner_state_counter % 2 != 0{
let oam_attribute = &self.oam_entries[self.current_oam_entry as usize];
let current_tile_data_address = Self::get_current_tile_data_address(ly_register, oam_attribute, sprite_size, tile_num);
let high_data = vram.read_current_bank(current_tile_data_address + 1);
self.current_fetching_state = FethcingState::Push(low_data, high_data);
}
}
FethcingState::Push(low_data, high_data)=>{
let oam_attribute = &self.oam_entries[self.current_oam_entry as usize];
let start_x = self.fifo.len();

let skip_x = 8 - (oam_attribute.x - current_x_pos) as usize;

if oam_attribute.flip_x{
for i in (0 + skip_x)..8{
let mask = 1 << i;
let mut pixel = (low_data & mask) >> i;
pixel |= ((high_data & mask) >> i) << 1;
if i + skip_x >= start_x {
self.fifo.push((pixel, self.current_oam_entry));
}
else if self.fifo[i + skip_x].0 == 0{
self.fifo[i+ skip_x] = (pixel, self.current_oam_entry);
if self.t_cycle_inner_state_counter % 2 != 0{

let oam_attribute = &self.oam_entries[self.current_oam_entry as usize];
let start_x = self.fifo.len();

let skip_x = 8 - (oam_attribute.x - current_x_pos) as usize;

if oam_attribute.flip_x{
for i in (0 + skip_x)..8{
let mask = 1 << i;
let mut pixel = (low_data & mask) >> i;
pixel |= ((high_data & mask) >> i) << 1;
if i + skip_x >= start_x {
self.fifo.push((pixel, self.current_oam_entry));
}
else if self.fifo[i + skip_x].0 == 0{
self.fifo[i+ skip_x] = (pixel, self.current_oam_entry);
}
}
}
}
else{
for i in (0..(8 - skip_x)).rev(){
let mask = 1 << i;
let mut pixel = (low_data & mask) >> i;
pixel |= ((high_data & mask) >> i) << 1;
if 7 - skip_x - i >= start_x {
self.fifo.push((pixel, self.current_oam_entry));
}
else if self.fifo[7 - skip_x - i].0 == 0{
self.fifo[7 - skip_x - i] = (pixel, self.current_oam_entry);
else{
for i in (0..(8 - skip_x)).rev(){
let mask = 1 << i;
let mut pixel = (low_data & mask) >> i;
pixel |= ((high_data & mask) >> i) << 1;
if 7 - skip_x - i >= start_x {
self.fifo.push((pixel, self.current_oam_entry));
}
else if self.fifo[7 - skip_x - i].0 == 0{
self.fifo[7 - skip_x - i] = (pixel, self.current_oam_entry);
}
}
}
}

self.current_fetching_state = FethcingState::TileNumber;
self.current_oam_entry += 1;
self.current_fetching_state = FethcingState::TileNumber;
self.current_oam_entry += 1;
}
}
}

self.t_cycle_inner_state_counter = (self.t_cycle_inner_state_counter + 1) % 8;
}

// Receiving the tile_num since in case of extended sprite this could change (the first bit is reset)
Expand Down

0 comments on commit dff63cb

Please sign in to comment.