fbsplash: Add support for 24 and 32 bit color depth
authorNuno Lucas <ntlucas@gmail.com>
Mon, 28 Mar 2011 13:30:59 +0000 (15:30 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Mon, 28 Mar 2011 13:30:59 +0000 (15:30 +0200)
function                                             old     new   delta
fb_drawprogressbar                                   372     447     +75
fb_pixel_value                                         -      50     +50
fb_write_pixel                                         -      47     +47
fbsplash_main                                        889     920     +31
fb_drawfullrectangle                                 101     131     +30
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 3/0 up/down: 233/0)             Total: 233 bytes

Signed-off-by: Nuno Lucas <ntlucas@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
miscutils/fbsplash.c

index 1509923..770e700 100644 (file)
 /* If you want logging messages on /tmp/fbsplash.log... */
 #define DEBUG 0
 
-#define BYTES_PER_PIXEL 2
-
-typedef unsigned short DATA;
-
 struct globals {
 #if DEBUG
        bool bdebug_messages;   // enable/disable logging
@@ -41,6 +37,7 @@ struct globals {
        const char *image_filename;
        struct fb_var_screeninfo scr_var;
        struct fb_fix_screeninfo scr_fix;
+       unsigned bytes_per_pixel;
 };
 #define G (*ptr_to_globals)
 #define INIT_G() do { \
@@ -67,7 +64,7 @@ struct globals {
 
 
 /**
- *     Open and initialize the framebuffer device
+ * Open and initialize the framebuffer device
  * \param *strfb_device pointer to framebuffer device
  */
 static void fb_open(const char *strfb_device)
@@ -78,62 +75,98 @@ static void fb_open(const char *strfb_device)
        xioctl(fbfd, FBIOGET_VSCREENINFO, &G.scr_var);
        xioctl(fbfd, FBIOGET_FSCREENINFO, &G.scr_fix);
 
-       if (G.scr_var.bits_per_pixel != 16)
-               bb_error_msg_and_die("only 16 bpp is supported");
+       if (G.scr_var.bits_per_pixel < 16 || G.scr_var.bits_per_pixel > 32)
+               bb_error_msg_and_die("unsupported %u bpp", (int)G.scr_var.bits_per_pixel);
+       G.bytes_per_pixel = (G.scr_var.bits_per_pixel + 7) >> 3;
 
        // map the device in memory
        G.addr = mmap(NULL,
-                       G.scr_var.xres * G.scr_var.yres_virtual
-                       * BYTES_PER_PIXEL /*(G.scr_var.bits_per_pixel / 8)*/,
+                       G.scr_var.xres * G.scr_var.yres * G.bytes_per_pixel,
                        PROT_WRITE, MAP_SHARED, fbfd, 0);
        if (G.addr == MAP_FAILED)
                bb_perror_msg_and_die("mmap");
 
        // point to the start of the visible screen
-       G.addr += G.scr_var.yoffset * G.scr_fix.line_length + G.scr_var.xoffset * BYTES_PER_PIXEL;
+       G.addr += G.scr_var.yoffset * G.scr_fix.line_length + G.scr_var.xoffset * G.bytes_per_pixel;
        close(fbfd);
 }
 
 
 /**
- *     Draw hollow rectangle on framebuffer
+ * Return pixel value of the passed RGB color
+ */
+static unsigned fb_pixel_value(unsigned r, unsigned g, unsigned b)
+{
+       if (G.bytes_per_pixel == 2) {
+               r >>= 3;  // 5-bit red
+               g >>= 2;  // 6-bit green
+               b >>= 3;  // 5-bit blue
+               return b + (g << 5) + (r << (5+6));
+       }
+       // RGB 888
+       return b + (g << 8) + (r << 16);
+}
+
+/**
+ * Draw pixel on framebuffer
+ */
+static void fb_write_pixel(unsigned char *addr, unsigned pixel)
+{
+       switch (G.bytes_per_pixel) {
+       case 2:
+               *(uint16_t *)addr = pixel;
+               break;
+       case 4:
+               *(uint32_t *)addr = pixel;
+               break;
+       default: // 24 bits per pixel
+               addr[0] = pixel;
+               addr[1] = pixel >> 8;
+               addr[2] = pixel >> 16;
+       }
+}
+
+
+/**
+ * Draw hollow rectangle on framebuffer
  */
 static void fb_drawrectangle(void)
 {
        int cnt;
-       DATA thispix;
-       DATA *ptr1, *ptr2;
+       unsigned thispix;
+       unsigned char *ptr1, *ptr2;
        unsigned char nred = G.nbar_colr/2;
        unsigned char ngreen =  G.nbar_colg/2;
        unsigned char nblue = G.nbar_colb/2;
 
-       nred   >>= 3;  // 5-bit red
-       ngreen >>= 2;  // 6-bit green
-       nblue  >>= 3;  // 5-bit blue
-       thispix = nblue + (ngreen << 5) + (nred << (5+6));
+       thispix = fb_pixel_value(nred, ngreen, nblue);
 
        // horizontal lines
-       ptr1 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL);
-       ptr2 = (DATA*)(G.addr + ((G.nbar_posy + G.nbar_height - 1) * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL);
+       ptr1 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel;
+       ptr2 = G.addr + ((G.nbar_posy + G.nbar_height - 1) * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel;
        cnt = G.nbar_width - 1;
        do {
-               *ptr1++ = thispix;
-               *ptr2++ = thispix;
+               fb_write_pixel(ptr1, thispix);
+               fb_write_pixel(ptr2, thispix);
+               ptr1 += G.bytes_per_pixel;
+               ptr2 += G.bytes_per_pixel;
        } while (--cnt >= 0);
 
        // vertical lines
-       ptr1 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL);
-       ptr2 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx + G.nbar_width - 1) * BYTES_PER_PIXEL);
+       ptr1 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel;
+       ptr2 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx + G.nbar_width - 1) * G.bytes_per_pixel;
        cnt = G.nbar_height - 1;
        do {
-               *ptr1 = thispix; ptr1 += G.scr_var.xres;
-               *ptr2 = thispix; ptr2 += G.scr_var.xres;
+               fb_write_pixel(ptr1, thispix);
+               fb_write_pixel(ptr2, thispix);
+               ptr1 += G.scr_var.xres * G.bytes_per_pixel;
+               ptr2 += G.scr_var.xres * G.bytes_per_pixel;
        } while (--cnt >= 0);
 }
 
 
 /**
- *     Draw filled rectangle on framebuffer
+ * Draw filled rectangle on framebuffer
  * \param nx1pos,ny1pos upper left position
  * \param nx2pos,ny2pos down right position
  * \param nred,ngreen,nblue rgb color
@@ -142,21 +175,19 @@ static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos,
        unsigned char nred, unsigned char ngreen, unsigned char nblue)
 {
        int cnt1, cnt2, nypos;
-       DATA thispix;
-       DATA *ptr;
+       unsigned thispix;
+       unsigned char *ptr;
 
-       nred   >>= 3;  // 5-bit red
-       ngreen >>= 2;  // 6-bit green
-       nblue  >>= 3;  // 5-bit blue
-       thispix = nblue + (ngreen << 5) + (nred << (5+6));
+       thispix = fb_pixel_value(nred, ngreen, nblue);
 
        cnt1 = ny2pos - ny1pos;
        nypos = ny1pos;
        do {
-               ptr = (DATA*)(G.addr + (nypos * G.scr_var.xres + nx1pos) * BYTES_PER_PIXEL);
+               ptr = G.addr + (nypos * G.scr_var.xres + nx1pos) * G.bytes_per_pixel;
                cnt2 = nx2pos - nx1pos;
                do {
-                       *ptr++ = thispix;
+                       fb_write_pixel(ptr, thispix);
+                       ptr += G.bytes_per_pixel;
                } while (--cnt2 >= 0);
 
                nypos++;
@@ -165,7 +196,7 @@ static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos,
 
 
 /**
- *     Draw a progress bar on framebuffer
+ * Draw a progress bar on framebuffer
  * \param percent percentage of loading
  */
 static void fb_drawprogressbar(unsigned percent)
@@ -215,7 +246,7 @@ static void fb_drawprogressbar(unsigned percent)
 
 
 /**
- *     Draw image from PPM file
+ * Draw image from PPM file
  */
 static void fb_drawimage(void)
 {
@@ -276,18 +307,16 @@ static void fb_drawimage(void)
                height = G.scr_var.yres;
        for (j = 0; j < height; j++) {
                unsigned char *pixel;
-               DATA *src;
+               unsigned char *src;
 
                if (fread(pixline, 1, line_size, theme_file) != line_size)
                        bb_error_msg_and_die("bad PPM file '%s'", G.image_filename);
                pixel = pixline;
-               src = (DATA *)(G.addr + j * G.scr_fix.line_length);
+               src = G.addr + j * G.scr_fix.line_length;
                for (i = 0; i < width; i++) {
-                       unsigned thispix;
-                       thispix = (((unsigned)pixel[0] << 8) & 0xf800)
-                               | (((unsigned)pixel[1] << 3) & 0x07e0)
-                               | (((unsigned)pixel[2] >> 3));
-                       *src++ = thispix;
+                       unsigned thispix = fb_pixel_value(pixel[0], pixel[1], pixel[2]);
+                       fb_write_pixel(src, thispix);
+                       src += G.bytes_per_pixel;
                        pixel += 3;
                }
        }
@@ -297,7 +326,7 @@ static void fb_drawimage(void)
 
 
 /**
- *     Parse configuration file
+ * Parse configuration file
  * \param *cfg_filename name of the configuration file
  */
 static void init(const char *cfg_filename)