You are browsing as a guest. Sign up (or log in) to start making projects!

4h 53m 39s logged

No More GPU Crisis

Hello everyone! It seems that, yet again, time has slipped away from me! Let’s dive back in!

STATistics

When the chip swaps rendering modes, depending on whether the STAT register enables that specific interrupt, it will trigger a STAT interrupt (priority level 2). I had to set up a loop to shift modes so that each mode can easily be fully handled (see screenshot). This was just a matter of finding out how long each mode and line lasted, relatively simple.

Render Engines

After this, I had to start adding rendering features. There are three components to the rendering:

  • Background
  • Window
  • Sprites
    The first, and easiest part, was the background. Which tiles compose the background is dictated by a series of bytes after either 0x9800 or 0x9c00, which have references to tiles in memory. Pretty simple.
    fn render_to_buffer(&mut self) {
        for row in 0..144 {
            for column in 0..160 {
                self.gpu.set_pixel(
                    row,
                    column,
                    self.bgp_palette_lookup(self.pixel_value(column, row)),
                );
            }
        }
    }

    fn pixel_value(&self, screen_x: u8, screen_y: u8) -> TilePixelValue {
        let map_y = self.read_byte(0xff42).wrapping_add(screen_y);
        let map_x = self.read_byte(0xff43).wrapping_add(screen_x);
        let tile_map_index = (map_y / 8) as u16 * 32 + (map_x / 8) as u16;
        let tile_map_base = if (self.read_byte(0xff40) >> 3) & 0x1 != 0 {
            0x9c00
        } else {
            0x9800
        };

        let tile: &Tile = &self.index_to_tile(self.read_byte(tile_map_base + tile_map_index));
        tile[(map_y % 8) as usize][(map_x % 8) as usize]
    }

    fn index_to_tile(&self, index: u8) -> Tile {
        let unsigned = (self.read_byte(0xff40) >> 4) & 0x1 != 0;
        if unsigned {
            return self.gpu.tile_set[index as usize];
        }
        let signed_index = (256 + (index as i8 as i16)) as usize;
        self.gpu.tile_set[signed_index]
    }

    fn bgp_palette_lookup(&self, value: TilePixelValue) -> PixelValue {
        let index = value as u8;
        match (self.read_byte(0xff47) >> (index * 2)) & 0b11 {
            0 => PixelValue::White,
            1 => PixelValue::LightGray,
            2 => PixelValue::DarkGray,
            3 => PixelValue::Black,
            _ => panic!("Unknown shade"),
        }
    }

The next step is the window, then the sprites. Sprites will be hard due to their varied size. See y’all next time!

0
4

Comments 0

No comments yet. Be the first!