Add support for 32-bit framebuffers.

This modifies the emulator so support 32-bit framebuffers.
You can create such a frame-buffer using one of these methods:

- Add a "bpp 32" line to the "display" element of your skin
- Use the new 'magic' skin option format: e.g. -skin 320x480x32

Note that the result will be hideous since the kernel driver still
thinks the hardware is only 16-bits. This will be addressed in a
later patch to hw/goldfish_fb.c and to the kernel driver
($KERNEL/drivers/video/goldfishfb.c)

Change-Id: I0fc700c4a4cb8521076605324e15ed34e5d01136
diff --git a/android/display-core.c b/android/display-core.c
index 1efb4a2..0b2a869 100644
--- a/android/display-core.c
+++ b/android/display-core.c
@@ -79,14 +79,24 @@
 void
 coredisplay_init(DisplayState* ds)
 {
+    int format;
+
     core_display.ds = ds;
     /* Create and initialize framebuffer instance that will be used for core
      * display.
      */
     ANEW0(core_display.fb);
     core_display.core_fb = NULL;
+
+    /* In the core, there is no skin to parse and the format of ds->surface
+     * is determined by the -android-gui option.
+     */
+    format = QFRAME_BUFFER_RGB565;
+    if (ds->surface->pf.bytes_per_pixel == 4)
+        format = QFRAME_BUFFER_RGBX_8888;
+
     qframebuffer_init(core_display.fb, ds->surface->width, ds->surface->height,
-                      0, QFRAME_BUFFER_RGB565 );
+                      0, format);
     qframebuffer_fifo_add(core_display.fb);
     /* Register core display as the client for the framebuffer, so we can start
      * receiving framebuffer notifications. Note that until UI connects to the
diff --git a/android/display.c b/android/display.c
index d7c261a..8bad585 100644
--- a/android/display.c
+++ b/android/display.c
@@ -88,7 +88,7 @@
     ds->opaque    = qf;
     ds->surface   = qemu_create_displaysurface_from(qf->width,
                                                     qf->height,
-                                                    16,
+                                                    qf->bits_per_pixel,
                                                     qf->pitch,
                                                     qf->pixels);
 
diff --git a/android/main-ui.c b/android/main-ui.c
index 927debb..a48c0fc 100644
--- a/android/main-ui.c
+++ b/android/main-ui.c
@@ -375,8 +375,13 @@
             if(x && isdigit(x[1])) {
                 int width = atoi(name);
                 int height = atoi(x + 1);
-                sprintf(tmp,"display {\n  width %d\n  height %d\n}\n",
-                        width, height);
+                int bpp   = 16;
+                char* y = strchr(x+1, 'x');
+                if (y && isdigit(y[1])) {
+                    bpp = atoi(y+1);
+                }
+                sprintf(tmp,"display {\n  width %d\n  height %d\n bpp %d}\n",
+                        width, height,bpp);
                 aconfig_load(root, strdup(tmp));
                 path = ":";
                 goto found_a_skin;
diff --git a/android/main.c b/android/main.c
index 840c764..00d54d1 100644
--- a/android/main.c
+++ b/android/main.c
@@ -359,14 +359,19 @@
             }
         }
 
-        /* Magically support skins like "320x240" */
+        /* Magically support skins like "320x240" or "320x240x16" */
         if(isdigit(name[0])) {
             char *x = strchr(name, 'x');
             if(x && isdigit(x[1])) {
                 int width = atoi(name);
-                int height = atoi(x + 1);
-                sprintf(tmp,"display {\n  width %d\n  height %d\n}\n",
-                        width, height);
+                int height = atoi(x+1);
+                int bpp   = 16;
+                char* y = strchr(x+1, 'x');
+                if (y && isdigit(y[1])) {
+                    bpp = atoi(y+1);
+                }
+                sprintf(tmp,"display {\n  width %d\n  height %d\n bpp %d}\n",
+                        width, height,bpp);
                 aconfig_load(root, strdup(tmp));
                 path = ":";
                 goto found_a_skin;
diff --git a/android/skin/file.c b/android/skin/file.c
index f7f0be9..5947ad9 100644
--- a/android/skin/file.c
+++ b/android/skin/file.c
@@ -91,6 +91,7 @@
     display->rect.size.w = aconfig_int(node, "width", 0);
     display->rect.size.h = aconfig_int(node, "height", 0);
     display->rotation    = aconfig_unsigned(node, "rotation", SKIN_ROTATION_0);
+    display->bpp         = aconfig_int(node, "bpp", 16);
 
     display->valid = ( display->rect.size.w > 0 && display->rect.size.h > 0 );
 
@@ -101,7 +102,8 @@
                            r.size.w,
                            r.size.h,
                            0,
-                           QFRAME_BUFFER_RGB565 );
+                           display->bpp == 32 ? QFRAME_BUFFER_RGBX_8888
+                                              : QFRAME_BUFFER_RGB565 );
 
         qframebuffer_fifo_add( display->qfbuff );
     }
diff --git a/android/skin/file.h b/android/skin/file.h
index 9f188b9..6f88063 100644
--- a/android/skin/file.h
+++ b/android/skin/file.h
@@ -28,6 +28,7 @@
 typedef struct SkinDisplay {
     SkinRect      rect;      /* display rectangle    */
     SkinRotation  rotation;  /* framebuffer rotation */
+    int           bpp;       /* bits per pixel, 32 or 16 */
     char          valid;
     QFrameBuffer  qfbuff[1];
 } SkinDisplay;
diff --git a/android/skin/window.c b/android/skin/window.c
index edc9028..018c184 100644
--- a/android/skin/window.c
+++ b/android/skin/window.c
@@ -151,10 +151,18 @@
     uint32_t  r = ((pix & 0xf800) << 8) | ((pix & 0xe000) << 3);
     uint32_t  g = ((pix & 0x07e0) << 5) | ((pix & 0x0600) >> 1);
     uint32_t  b = ((pix & 0x001f) << 3) | ((pix & 0x001c) >> 2);
-
     return 0xff000000 | r | g | b;
 }
 
+/* The framebuffer format is R,G,B,X in framebuffer memory, on a
+ * little-endian system, this translates to XBGR after a load.
+ */
+static __inline__ uint32_t  xbgr_to_argb32( uint32_t pix )
+{
+    uint32_t  g  = (pix & 0x0000ff00);
+    uint32_t  rb = (pix & 0xff00ff);
+    return 0xff000000 | (rb << 16) | g | (rb >> 16);
+}
 
 static void
 display_set_onion( ADisplay*  disp, SkinImage*  onion, SkinRotation  rotation, int  blend )
@@ -366,6 +374,184 @@
     }
 }
 
+static void
+display_redraw_rect16( ADisplay* disp, SkinRect* rect, SDL_Surface* surface)
+{
+    int           x  = rect->pos.x - disp->rect.pos.x;
+    int           y  = rect->pos.y - disp->rect.pos.y;
+    int           w  = rect->size.w;
+    int           h  = rect->size.h;
+    int           disp_w    = disp->rect.size.w;
+    int           disp_h    = disp->rect.size.h;
+    int           dst_pitch = surface->pitch;
+    uint8_t*      dst_line  = (uint8_t*)surface->pixels + rect->pos.x*4 + rect->pos.y*dst_pitch;
+    int           src_pitch = disp->datasize.w*2;
+    uint8_t*      src_line  = (uint8_t*)disp->data;
+    int           yy, xx;
+
+    switch ( disp->rotation & 3 )
+    {
+    case ANDROID_ROTATION_0:
+        src_line += x*2 + y*src_pitch;
+
+        for (yy = h; yy > 0; yy--)
+        {
+            uint32_t*  dst = (uint32_t*)dst_line;
+            uint16_t*  src = (uint16_t*)src_line;
+
+            for (xx = 0; xx < w; xx++) {
+                dst[xx] = rgb565_to_argb32(src[xx]);
+            }
+            src_line += src_pitch;
+            dst_line += dst_pitch;
+        }
+        break;
+
+    case ANDROID_ROTATION_90:
+        src_line += y*2 + (disp_w - x - 1)*src_pitch;
+
+        for (yy = h; yy > 0; yy--)
+        {
+            uint32_t*  dst = (uint32_t*)dst_line;
+            uint8_t*   src = src_line;
+
+            for (xx = w; xx > 0; xx--)
+            {
+                dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]);
+                src -= src_pitch;
+                dst += 1;
+            }
+            src_line += 2;
+            dst_line += dst_pitch;
+        }
+        break;
+
+    case ANDROID_ROTATION_180:
+        src_line += (disp_w -1 - x)*2 + (disp_h-1-y)*src_pitch;
+
+        for (yy = h; yy > 0; yy--)
+        {
+            uint16_t*  src = (uint16_t*)src_line;
+            uint32_t*  dst = (uint32_t*)dst_line;
+
+            for (xx = w; xx > 0; xx--) {
+                dst[0] = rgb565_to_argb32(src[0]);
+                src -= 1;
+                dst += 1;
+            }
+
+            src_line -= src_pitch;
+            dst_line += dst_pitch;
+    }
+    break;
+
+    default:  /* ANDROID_ROTATION_270 */
+        src_line += (disp_h-1-y)*2 + x*src_pitch;
+
+        for (yy = h; yy > 0; yy--)
+        {
+            uint32_t*  dst = (uint32_t*)dst_line;
+            uint8_t*   src = src_line;
+
+            for (xx = w; xx > 0; xx--) {
+                dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]);
+                dst   += 1;
+                src   += src_pitch;
+            }
+            src_line -= 2;
+            dst_line += dst_pitch;
+        }
+    }
+}
+
+static void
+display_redraw_rect32( ADisplay* disp, SkinRect* rect,SDL_Surface* surface)
+{
+    int           x  = rect->pos.x - disp->rect.pos.x;
+    int           y  = rect->pos.y - disp->rect.pos.y;
+    int           w  = rect->size.w;
+    int           h  = rect->size.h;
+    int           disp_w    = disp->rect.size.w;
+    int           disp_h    = disp->rect.size.h;
+    int           dst_pitch = surface->pitch;
+    uint8_t*      dst_line  = (uint8_t*)surface->pixels + rect->pos.x*4 + rect->pos.y*dst_pitch;
+    int           src_pitch = disp->datasize.w*4;
+    uint8_t*      src_line  = (uint8_t*)disp->data;
+    int           yy, xx;
+
+    switch ( disp->rotation & 3 )
+    {
+    case ANDROID_ROTATION_0:
+        src_line += x*4 + y*src_pitch;
+
+        for (yy = h; yy > 0; yy--) {
+            uint32_t*  src = (uint32_t*)src_line;
+            uint32_t*  dst = (uint32_t*)dst_line;
+
+            for (xx = 0; xx < w; xx++) {
+                dst[xx] = xbgr_to_argb32(src[xx]);
+            }
+            src_line += src_pitch;
+            dst_line += dst_pitch;
+        }
+        break;
+
+    case ANDROID_ROTATION_90:
+        src_line += y*4 + (disp_w - x - 1)*src_pitch;
+
+        for (yy = h; yy > 0; yy--)
+        {
+            uint32_t*  dst = (uint32_t*)dst_line;
+            uint8_t*   src = src_line;
+
+            for (xx = w; xx > 0; xx--)
+            {
+                dst[0] = xbgr_to_argb32(*(uint32_t*)src);
+                src -= src_pitch;
+                dst += 1;
+            }
+            src_line += 4;
+            dst_line += dst_pitch;
+        }
+        break;
+
+    case ANDROID_ROTATION_180:
+        src_line += (disp_w -1 - x)*4 + (disp_h-1-y)*src_pitch;
+
+        for (yy = h; yy > 0; yy--)
+        {
+            uint32_t*  src = (uint32_t*)src_line;
+            uint32_t*  dst = (uint32_t*)dst_line;
+
+            for (xx = w; xx > 0; xx--) {
+                dst[0] = xbgr_to_argb32(src[0]);
+                src -= 1;
+                dst += 1;
+            }
+
+            src_line -= src_pitch;
+            dst_line += dst_pitch;
+    }
+    break;
+
+    default:  /* ANDROID_ROTATION_270 */
+        src_line += (disp_h-1-y)*4 + x*src_pitch;
+
+        for (yy = h; yy > 0; yy--)
+        {
+            uint32_t*  dst = (uint32_t*)dst_line;
+            uint8_t*   src = src_line;
+
+            for (xx = w; xx > 0; xx--) {
+                dst[0] = xbgr_to_argb32(*(uint32_t*)src);
+                dst   += 1;
+                src   += src_pitch;
+            }
+            src_line -= 4;
+            dst_line += dst_pitch;
+        }
+    }
+}
 
 static void
 display_redraw( ADisplay*  disp, SkinRect*  rect, SDL_Surface*  surface )
@@ -374,21 +560,11 @@
 
     if (skin_rect_intersect( &r, rect, &disp->rect ))
     {
-        int           x  = r.pos.x - disp->rect.pos.x;
-        int           y  = r.pos.y - disp->rect.pos.y;
-        int           w  = r.size.w;
-        int           h  = r.size.h;
-        int           disp_w    = disp->rect.size.w;
-        int           disp_h    = disp->rect.size.h;
-        int           dst_pitch = surface->pitch;
-        uint8_t*      dst_line  = (uint8_t*)surface->pixels + r.pos.x*4 + r.pos.y*dst_pitch;
-        int           src_pitch = disp->datasize.w*2;
-        uint8_t*      src_line  = (uint8_t*)disp->data;
-        int           yy, xx;
 #if 0
         fprintf(stderr, "--- display redraw r.pos(%d,%d) r.size(%d,%d) "
                         "disp.pos(%d,%d) disp.size(%d,%d) datasize(%d,%d) rect.pos(%d,%d) rect.size(%d,%d)\n",
-                        r.pos.x - disp->rect.pos.x, r.pos.y - disp->rect.pos.y, w, h, disp->rect.pos.x, disp->rect.pos.y,
+                        r.pos.x - disp->rect.pos.x, r.pos.y - disp->rect.pos.y,
+                        r.size.w, r.size.h, disp->rect.pos.x, disp->rect.pos.y,
                         disp->rect.size.w, disp->rect.size.h, disp->datasize.w, disp->datasize.h,
                         rect->pos.x, rect->pos.y, rect->size.w, rect->size.h );
 #endif
@@ -396,83 +572,14 @@
 
         if (disp->brightness == LCD_BRIGHTNESS_OFF)
         {
-            lcd_off_argb32( surface->pixels, &r, dst_pitch );
+            lcd_off_argb32( surface->pixels, &r, surface->pitch );
         }
         else
         {
-            switch ( disp->rotation & 3 )
-            {
-            case ANDROID_ROTATION_0:
-                src_line += x*2 + y*src_pitch;
-
-                for (yy = h; yy > 0; yy--)
-                {
-                    uint32_t*  dst = (uint32_t*)dst_line;
-                    uint16_t*  src = (uint16_t*)src_line;
-
-                    for (xx = 0; xx < w; xx++) {
-                        dst[xx] = rgb565_to_argb32(src[xx]);
-                    }
-                    src_line += src_pitch;
-                    dst_line += dst_pitch;
-                }
-                break;
-
-            case ANDROID_ROTATION_90:
-                src_line += y*2 + (disp_w - x - 1)*src_pitch;
-
-                for (yy = h; yy > 0; yy--)
-                {
-                    uint32_t*  dst = (uint32_t*)dst_line;
-                    uint8_t*   src = src_line;
-
-                    for (xx = w; xx > 0; xx--)
-                    {
-                        dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]);
-                        src -= src_pitch;
-                        dst += 1;
-                    }
-                    src_line += 2;
-                    dst_line += dst_pitch;
-                }
-                break;
-
-            case ANDROID_ROTATION_180:
-                src_line += (disp_w -1 - x)*2 + (disp_h-1-y)*src_pitch;
-
-                for (yy = h; yy > 0; yy--)
-                {
-                    uint16_t*  src = (uint16_t*)src_line;
-                    uint32_t*  dst = (uint32_t*)dst_line;
-
-                    for (xx = w; xx > 0; xx--) {
-                        dst[0] = rgb565_to_argb32(src[0]);
-                        src -= 1;
-                        dst += 1;
-                    }
-
-                    src_line -= src_pitch;
-                    dst_line += dst_pitch;
-            }
-            break;
-
-            default:  /* ANDROID_ROTATION_270 */
-                src_line += (disp_h-1-y)*2 + x*src_pitch;
-
-                for (yy = h; yy > 0; yy--)
-                {
-                    uint32_t*  dst = (uint32_t*)dst_line;
-                    uint8_t*   src = src_line;
-
-                    for (xx = w; xx > 0; xx--) {
-                        dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]);
-                        dst   += 1;
-                        src   += src_pitch;
-                    }
-                    src_line -= 2;
-                    dst_line += dst_pitch;
-                }
-            }
+            if (disp->qfbuff->bits_per_pixel == 32)
+                display_redraw_rect32(disp, &r, surface);
+            else
+                display_redraw_rect16(disp, &r, surface);
 #if DOT_MATRIX
             dotmatrix_dither_argb32( surface->pixels, r.pos.x, r.pos.y, r.size.w, r.size.h, surface->pitch );
 #endif
@@ -502,7 +609,7 @@
             }
         }
 
-        SDL_UpdateRect( surface, r.pos.x, r.pos.y, w, h );
+        SDL_UpdateRect( surface, r.pos.x, r.pos.y, r.size.w, r.size.h );
     }
 }
 
diff --git a/framebuffer.c b/framebuffer.c
index 225d60d..a90a1e8 100644
--- a/framebuffer.c
+++ b/framebuffer.c
@@ -37,6 +37,8 @@
     switch (format) {
         case QFRAME_BUFFER_RGB565:
             return width*2;
+        case QFRAME_BUFFER_RGBX_8888:
+            return width*4;
         default:
             return -1;
     }
@@ -49,6 +51,8 @@
     switch (format) {
         case QFRAME_BUFFER_RGB565:
             return 16;
+        case QFRAME_BUFFER_RGBX_8888:
+            return 32;
         default:
             return -1;
     }
@@ -61,6 +65,8 @@
     switch (format) {
         case QFRAME_BUFFER_RGB565:
             return 2;
+        case QFRAME_BUFFER_RGBX_8888:
+            return 4;
         default:
             return -1;
     }
@@ -84,11 +90,11 @@
     if (pitch < 0)
         return -1;
 
-	bits_per_pixel = _get_bits_per_pixel(format);
-	if (bits_per_pixel < 0)
-		return -1;
+    bits_per_pixel = _get_bits_per_pixel(format);
+    if (bits_per_pixel < 0)
+        return -1;
 
-	bytes_per_pixel = _get_bytes_per_pixel(format);
+    bytes_per_pixel = _get_bytes_per_pixel(format);
     if (bytes_per_pixel < 0)
         return -1;
 
diff --git a/framebuffer.h b/framebuffer.h
index 0e502d1..7a69440 100644
--- a/framebuffer.h
+++ b/framebuffer.h
@@ -40,6 +40,7 @@
 typedef enum {
     QFRAME_BUFFER_NONE   = 0,
     QFRAME_BUFFER_RGB565 = 1,
+    QFRAME_BUFFER_RGBX_8888 = 2,
     QFRAME_BUFFER_MAX          /* do not remove */
 } QFrameBufferFormat;