Skip to content

Optimize the drawing efficiency of u8g2_DrawBitmap: Reduce the cost of pixel-by-pixel drawing through run-length encoding #2752

@dszser

Description

@dszser

I used a monochrome screen to draw a 200*180 bitmap and noticed that the screen refresh was quite laggy. Later, when I looked at the source code, I found that u8g2_DrawBitmap was drawing pixel by pixel. So, I optimized it using run-length encoding.

void u8g2_DrawHorizontalBitmap_RLE(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t len, const uint8_t *b)
{
  uint8_t mask;
  uint8_t color = u8g2->draw_color;
  uint8_t ncolor = (color == 0 ? 1 : 0);
  u8g2_uint_t run_x = x;          // The starting x-coordinate of the current continuous segment
  u8g2_uint_t run_len = 0;        // The length of consecutive identical pixels
  uint8_t cur_draw_type = 0;      // Current pixel type: 0 = Transparent, 1 = Target color, 2 = Inverse color
 
#ifdef U8G2_WITH_INTERSECTION
  if ( u8g2_IsIntersection(u8g2, x, y, x+len, y+1) == 0 ) 
    return;
#endif /* U8G2_WITH_INTERSECTION */
  
  mask = 128;
  while(len > 0)
  {
    uint8_t pixel_draw_type = 0; 
    if ( *b & mask ) {
      pixel_draw_type = 1;
    } else {
      if ( u8g2->bitmap_transparency == 0 ) {
        pixel_draw_type = 2;
      } else {
        pixel_draw_type = 0;
      }
    }
 
    // Determine whether the current pixel is of the same type as the previous segment.
    if (pixel_draw_type == cur_draw_type) {
      run_len++;
    } else {
      // Type inconsistency → First draw the consecutive pixels of the previous section, then reset the statistics
      if (run_len > 0 && cur_draw_type != 0) {
        u8g2->draw_color = (cur_draw_type == 1) ? color : ncolor;
        u8g2_DrawHVLine(u8g2, run_x, y, run_len, 0);
      }
      // Reset the  statistics
      cur_draw_type = pixel_draw_type;
      run_x = x;
      run_len = 1; // The current pixel serves as the first pixel of the new segment.
    }
 
    //  Move to the next pixel
    x++;
    mask >>= 1;
    if ( mask == 0 )
    {
      mask = 128;
      b++;
    }
    len--;
  }
 
  // Process the last continuous group of pixels that have not been drawn.
  if (run_len > 0 && cur_draw_type != 0) {
    u8g2->draw_color = (cur_draw_type == 1) ? color : ncolor;
    u8g2_DrawHVLine(u8g2, run_x, y, run_len, 0);
  }
  u8g2->draw_color = color;
}

Replace u8g2_DrawHorizontalBitmap

void u8g2_DrawBitmap(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t cnt, u8g2_uint_t h, const uint8_t *bitmap)
{
  u8g2_uint_t w;
  w = cnt;
  w *= 8;
#ifdef U8G2_WITH_INTERSECTION
  if ( u8g2_IsIntersection(u8g2, x, y, x+w, y+h) == 0 ) 
    return;
#endif /* U8G2_WITH_INTERSECTION */
  
  while( h > 0 )
  {
    //u8g2_DrawHorizontalBitmap(u8g2, x, y, w, bitmap);
    //  RLE Optimize 
    u8g2_DrawHorizontalBitmap_RLE(u8g2, x, y, w, bitmap);
    bitmap += cnt;
    y++;
    h--;
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions