From fec401597834a22bf9d8554bcbe38278bf9734f1 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Sat, 23 Apr 2022 14:30:46 +0100 Subject: [PATCH] Remove hash map lookup for every pixel rendered --- agb/src/display/font.rs | 78 ++++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/agb/src/display/font.rs b/agb/src/display/font.rs index badafc56..c5a71ace 100644 --- a/agb/src/display/font.rs +++ b/agb/src/display/font.rs @@ -86,7 +86,7 @@ pub struct TextRenderer<'a> { bg: &'a mut RegularMap, background_colour: u8, foreground_colour: u8, - tiles: HashMap<(usize, usize), DynamicTile<'a>>, + tiles: HashMap<(i32, i32), DynamicTile<'a>>, } impl<'a> Write for TextRenderer<'a> { @@ -96,23 +96,6 @@ impl<'a> Write for TextRenderer<'a> { let foreground_colour = self.foreground_colour; let background_colour = self.background_colour; - let mut render_pixel = |x: u16, y: u16| { - let tile_x = (x / 8) as usize; - let tile_y = (y / 8) as usize; - let inner_x = x % 8; - let inner_y = y % 8; - - let colour = foreground_colour as u32; - - let index = (inner_x + inner_y * 8) as usize; - - let tile = tiles - .entry((tile_x, tile_y)) - .or_insert_with(|| vram_manager.new_dynamic_tile().fill_with(background_colour)); - - tile.tile_data[index / 8] |= colour << ((index % 8) * 4); - }; - for c in text.chars() { if c == '\n' { self.current_y_pos += self.font.line_height; @@ -126,15 +109,56 @@ impl<'a> Write for TextRenderer<'a> { let y_start = self.current_y_pos + self.font.ascent - letter.height as i32 - letter.ymin as i32; - for letter_y in 0..(letter.height as i32) { - for letter_x in 0..(letter.width as i32) { - let x = x_start + letter_x; - let y = y_start + letter_y; + let x_tile_start = x_start / 8; + let y_tile_start = y_start / 8; - let px = letter.data[(letter_x + letter_y * letter.width as i32) as usize]; + let letter_offset_x = x_start.rem_euclid(8); + let letter_offset_y = y_start.rem_euclid(8); - if px > 100 { - render_pixel(x as u16, y as u16); + let x_tiles = div_ceil(letter.width as i32 + letter_offset_x, 8); + let y_tiles = div_ceil(letter.height as i32 + letter_offset_y, 8); + + for letter_y_tile in 0..(y_tiles + 1) { + let letter_y_start = 0.max(letter_offset_y - 8 * letter_y_tile) + 8 * letter_y_tile; + let letter_y_end = + (letter_offset_y + letter.height as i32).min((letter_y_tile + 1) * 8); + + let tile_y = y_tile_start + letter_y_tile; + + for letter_x_tile in 0..(x_tiles + 1) { + let letter_x_start = + 0.max(letter_offset_x - 8 * letter_x_tile) + 8 * letter_x_tile; + let letter_x_end = + (letter_offset_x + letter.width as i32).min((letter_x_tile + 1) * 8); + + let tile_x = x_tile_start + letter_x_tile; + + let mut masks = [0u32; 8]; + let mut zero = true; + + for letter_y in letter_y_start..letter_y_end { + let y = letter_y - letter_offset_y; + + for letter_x in letter_x_start..letter_x_end { + let x = letter_x - letter_offset_x; + let px = letter.data[(x + y * letter.width as i32) as usize]; + + if px > 100 { + masks[(letter_y & 7) as usize] |= + (foreground_colour as u32) << ((letter_x & 7) * 4); + zero = false; + } + } + } + + if !zero { + let tile = tiles.entry((tile_x, tile_y)).or_insert_with(|| { + vram_manager.new_dynamic_tile().fill_with(background_colour) + }); + + for (i, tile_data_line) in tile.tile_data.iter_mut().enumerate() { + *tile_data_line |= masks[i]; + } } } } @@ -146,6 +170,10 @@ impl<'a> Write for TextRenderer<'a> { } } +fn div_ceil(quotient: i32, divisor: i32) -> i32 { + (quotient + divisor - 1) / divisor +} + impl<'a> TextRenderer<'a> { pub fn commit(mut self) { let tiles = core::mem::take(&mut self.tiles);