From 97d795c955f8d261a0a5294d49ea06d5a473ed03 Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Sun, 16 Jan 2011 01:42:37 +0100 Subject: 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 --- android/display-core.c | 12 ++- android/display.c | 2 +- android/main-ui.c | 9 +- android/main.c | 13 ++- android/skin/file.c | 4 +- android/skin/file.h | 1 + android/skin/window.c | 283 ++++++++++++++++++++++++++++++++++--------------- framebuffer.c | 14 ++- framebuffer.h | 1 + 9 files changed, 238 insertions(+), 101 deletions(-) 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 @@ coredisplay_fb_done(void* opaque) 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 @@ void android_display_init(DisplayState* ds, QFrameBuffer* qf) 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 @@ void init_skinned_ui(const char *path, const char *name, AndroidOptions* opts) 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 @@ void init_skinned_ui(const char *path, const char *name, AndroidOptions* opts) } } - /* 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 @@ skin_display_init_from( SkinDisplay* display, AConfig* node ) 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 @@ skin_display_init_from( SkinDisplay* display, AConfig* node ) 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 SkinBackground { 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 @@ static __inline__ uint32_t rgb565_to_argb32( uint32_t pix ) 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 @@ lcd_off_argb32( unsigned char* pixels, SkinRect* r, int pitch ) } } +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 @@ display_redraw( ADisplay* disp, SkinRect* rect, SDL_Surface* surface ) 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 @@ display_redraw( ADisplay* disp, SkinRect* rect, SDL_Surface* surface ) 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 @@ display_redraw( ADisplay* disp, SkinRect* rect, SDL_Surface* surface ) } } - 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 @@ _get_pitch( int width, QFrameBufferFormat format ) switch (format) { case QFRAME_BUFFER_RGB565: return width*2; + case QFRAME_BUFFER_RGBX_8888: + return width*4; default: return -1; } @@ -49,6 +51,8 @@ _get_bits_per_pixel(QFrameBufferFormat format) switch (format) { case QFRAME_BUFFER_RGB565: return 16; + case QFRAME_BUFFER_RGBX_8888: + return 32; default: return -1; } @@ -61,6 +65,8 @@ _get_bytes_per_pixel(QFrameBufferFormat format) switch (format) { case QFRAME_BUFFER_RGB565: return 2; + case QFRAME_BUFFER_RGBX_8888: + return 4; default: return -1; } @@ -84,11 +90,11 @@ qframebuffer_init( QFrameBuffer* qfbuff, 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 struct QFrameBuffer QFrameBuffer; typedef enum { QFRAME_BUFFER_NONE = 0, QFRAME_BUFFER_RGB565 = 1, + QFRAME_BUFFER_RGBX_8888 = 2, QFRAME_BUFFER_MAX /* do not remove */ } QFrameBufferFormat; -- cgit v1.1