From dff63cb725efafebad9a3ddc666e9ac09633694f Mon Sep 17 00:00:00 2001 From: alloncm Date: Fri, 3 Sep 2021 20:19:25 +0300 Subject: [PATCH] FIx the bug with the missing vertical object lines 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. --- lib_gb/src/ppu/fifo/bg_fetcher.rs | 13 +++- lib_gb/src/ppu/fifo/fifo_ppu.rs | 48 +++++++-------- lib_gb/src/ppu/fifo/sprite_fetcher.rs | 88 +++++++++++++++------------ 3 files changed, 86 insertions(+), 63 deletions(-) diff --git a/lib_gb/src/ppu/fifo/bg_fetcher.rs b/lib_gb/src/ppu/fifo/bg_fetcher.rs index 05fac806..6161b044 100644 --- a/lib_gb/src/ppu/fifo/bg_fetcher.rs +++ b/lib_gb/src/ppu/fifo/bg_fetcher.rs @@ -10,6 +10,7 @@ pub struct BGFetcher{ rendered_window:bool, rendering_window:bool, current_fetching_state:FethcingState, + t_cycles_counter:u8, } impl BGFetcher{ @@ -20,7 +21,8 @@ impl BGFetcher{ fifo:Vec::::with_capacity(8), window_line_counter:0, rendered_window:false, - rendering_window:false + rendering_window:false, + t_cycles_counter:0 } } @@ -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){ @@ -43,6 +47,11 @@ impl BGFetcher{ } pub fn fetch_pixels(&mut self, vram:&VRam, lcd_control:u8, ly_register:u8, window_pos:&Vec2, bg_pos:&Vec2){ + 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{ @@ -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, ly_register:u8, tile_num:u8)->u16{ diff --git a/lib_gb/src/ppu/fifo/fifo_ppu.rs b/lib_gb/src/ppu/fifo/fifo_ppu.rs index 7b2308fe..148a0dbe 100644 --- a/lib_gb/src/ppu/fifo/fifo_ppu.rs +++ b/lib_gb/src/ppu/fifo/fifo_ppu.rs @@ -214,31 +214,31 @@ impl FifoPpu{ 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; + } } } } diff --git a/lib_gb/src/ppu/fifo/sprite_fetcher.rs b/lib_gb/src/ppu/fifo/sprite_fetcher.rs index e311ce66..517a37f9 100644 --- a/lib_gb/src/ppu/fifo/sprite_fetcher.rs +++ b/lib_gb/src/ppu/fifo/sprite_fetcher.rs @@ -12,6 +12,7 @@ pub struct SpriteFetcher{ current_fetching_state:FethcingState, current_oam_entry:u8, + t_cycle_inner_state_counter:u8, } impl SpriteFetcher{ @@ -34,7 +35,8 @@ 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, } } @@ -42,6 +44,7 @@ impl SpriteFetcher{ 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; } @@ -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)