Page 5 of 5

Re: Display functions optimization

PostPosted: Sat Jan 24, 2015 8:44 am
by Myndale
Doing a screen boundary check per-pixel would have a huge effect on performance but it doesn't actually need to be done. All that needs to be done is clipping the destination rectangle to the screen at the start of the routine and then adjusting the initial screen and bitmap address/masks accordingly.

Fortunately we're in a long weekend here in Australia so gimme another day or two and I'll give you something you can drop into the library. :)

Re: Display functions optimization

PostPosted: Sat Jan 24, 2015 9:19 am
by rodot
Awesome Myndale, thanks ! :)

Re: Display functions optimization

PostPosted: Sat Jan 24, 2015 12:58 pm
by rodot
The following does gray with alternating vertical lines (not as good as the alternative checker pattern), but still works pretty well:
Code: Select all
        if(gb.frameCount & 0x01) { //odd frames
          if (pixels & 0x80) ptr[0] |= mask;
          if (pixels & 0x40) ptr[1] &= mask;
          if (pixels & 0x20) ptr[2] |= mask;
          if (pixels & 0x10) ptr[3] &= mask;
          if (pixels & 0x08) ptr[4] |= mask;
          if (pixels & 0x04) ptr[5] &= mask;
          if (pixels & 0x02) ptr[6] |= mask;
          if (pixels & 0x01) ptr[7] &= mask;
        } else {
          if (pixels & 0x80) ptr[0] &= mask;
          if (pixels & 0x40) ptr[1] |= mask;
          if (pixels & 0x20) ptr[2] &= mask;
          if (pixels & 0x10) ptr[3] |= mask;
          if (pixels & 0x08) ptr[4] &= mask;
          if (pixels & 0x04) ptr[5] |= mask;
          if (pixels & 0x02) ptr[6] &= mask;
          if (pixels & 0x01) ptr[7] |= mask;
        }


This would allow to add the GRAY color to the library.

Re: Display functions optimization

PostPosted: Sat Jan 24, 2015 4:24 pm
by Skyrunner65
rodot wrote:This would allow to add the GRAY color to the library.


:mrgreen: Please add this. It would make the production of sprites so much easier and with detail.

Re: Display functions optimization

PostPosted: Sun Jan 25, 2015 9:48 am
by rodot
The GRAY color is added to the beta branch of the library, although the new bitmap optimized routines are not committed yet.

Re: Display functions optimization

PostPosted: Mon Jan 26, 2015 5:26 pm
by cyberic
fillRect is now slower than drawBitmap...
Can't we just draw a black sprite?

Re: Display functions optimization

PostPosted: Tue Jan 27, 2015 1:52 am
by Myndale
Here's a drop-in replacement for drawBitmap that supports clipping and all colors including grayscale (if you enable it). I've tested it with Crabator and it seems to work fine:

Code: Select all
void Display::drawBitmap(int8_t x, int8_t y, const uint8_t *bitmap) {
   int8_t w = pgm_read_byte(bitmap);
   int8_t h = pgm_read_byte(bitmap + 1);
   bitmap = bitmap + 2; //add an offset to the pointer to start after the width and height
#if (ENABLE_BITMAPS > 0)
/*   original code
    int8_t i, j, byteWidth = (w + 7) / 8;
    for (j = 0; j < h; j++) {
        for (i = 0; i < w; i++) {
            if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (B10000000 >> (i % 8))) {
                drawPixel(x + i, y + j);
            }
        }
    }
  */
  uint8_t * buffer = getBuffer();
  const uint8_t col = color;
  const uint8_t bw = (w+7) / 8;
 
  // clip
  if (x >= LCDWIDTH)
    return;
  if (x + w <= 0)
    return;
  if (y >= LCDHEIGHT)
    return;
  if (y + h <= 0)
    return;
  if (y < 0)
    h += y, bitmap -= bw * y, y = 0;
  if (y + h > LCDHEIGHT)
    h = LCDHEIGHT - y; 
  uint8_t x1 = max(0, x);
  uint8_t x2 = min(LCDWIDTH, x + w);
 
#ifdef ENABLE_GREYSCALE
   uint8_t g = y ^ frameCount;
#endif 

  // draw
  uint8_t first_bitmap_mask = 0x80 >> ((x1 - x) & 7);
  const uint8_t * bitmap_line = bitmap + (x1 - x) / 8;
  uint8_t screen_mask = 0x01 << (y % 8);
  uint8_t * screen_row = buffer + (y / 8) * LCDWIDTH + x1; 
  for (uint8_t dy=0; dy<h; dy++, bitmap_line+=bw)
  {
    const uint8_t * bitmap_ptr = bitmap_line;   
    uint8_t bitmap_mask = first_bitmap_mask;   
    uint8_t pixels = pgm_read_byte(bitmap_ptr);
    uint8_t * dst = screen_row;
   
    if (col == BLACK)
      for (uint8_t sx=x1; sx<x2; sx++, dst++)
      {
        if (pixels & bitmap_mask)
          *dst |= screen_mask;
        bitmap_mask >>= 1;
        if (!bitmap_mask)
        {
          bitmap_mask = 0x80;
          pixels = pgm_read_byte(++bitmap_ptr);
        }
      }
    else if (col == WHITE)
    {
      uint8_t inv_screen_mask = ~screen_mask;
      for (uint8_t sx=x1; sx<x2; sx++, dst++)
      {
        if (pixels & bitmap_mask)
          *dst &= inv_screen_mask;
        bitmap_mask >>= 1;
        if (!bitmap_mask)
        {
          bitmap_mask = 0x80;
          pixels = pgm_read_byte(++bitmap_ptr);
        }
      }
    }
#ifdef ENABLE_GREYSCALE
    else if (col == GRAY)
    {
      uint8_t inv_screen_mask = ~screen_mask;
      for (uint8_t sx=x1; sx<x2; sx++, dst++)
      {
        if (pixels & bitmap_mask)
        {
         if ((sx^g) & 1)
            *dst |= screen_mask;
          else
           *dst &= inv_screen_mask;
        }
        bitmap_mask >>= 1;
        if (!bitmap_mask)
        {
          bitmap_mask = 0x80;
          pixels = pgm_read_byte(++bitmap_ptr);
        }
      }
       g ^= 1;
    }
#endif
   else // invert
      for (uint8_t sx=x1; sx<x2; sx++, dst++)
      {
        if (pixels & bitmap_mask)
          *dst ^= screen_mask;
        bitmap_mask >>= 1;
        if (!bitmap_mask)
        {
          bitmap_mask = 0x80;
          pixels = pgm_read_byte(++bitmap_ptr);
        }
      }
   
    screen_mask <<= 1;
    if (!screen_mask)
    {
      screen_mask = 1;
      screen_row += LCDWIDTH;
    }
  }
#else
   drawRect(x, y, w, h);
#endif
}


If you want greyscale then you'll need to define ENABLE_GREYSCALE (or just comment those lines back in), you'll also need to provide a way of passing in the frameCount variable.

As is usually the case with optimization this code tries to strike a balance between speed and code size. It currently adds about 400 bytes to the size of the function and runs my test blt code in around 1500ms.

Re: Display functions optimization

PostPosted: Tue Jan 27, 2015 2:12 am
by erico
:O

Re: Display functions optimization

PostPosted: Wed Jan 28, 2015 11:30 am
by rodot
Thanks a lot Myndale, I just commited it to the beta branch and give your credit in the changelog. Along with this update I did a fix of the horizontal bitmap flip (there was an offset), and added examples for drawBitmap and setColor.