fix(ppu): ensure better timings for sprite fetcher
This commit is contained in:
		
							
								
								
									
										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(); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user