From 98b2c93b214333865272d74c6a4f753ce546efda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 4 Dec 2014 15:54:13 +0000 Subject: goldfish_fb: implement basic rotation support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for a rotated display of the android framebuffer. As far as the guest is concerned the location/size of the framebuffer hasn't changed however we change how we copy the data into QEMU's own display buffer depending on the setting of the rotation field. Signed-off-by: Alex Bennée --- hw/display/goldfish_fb.c | 71 ++++++++++++++++++++++++++++++--------- hw/display/goldfish_fb_template.h | 11 +++--- 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/hw/display/goldfish_fb.c b/hw/display/goldfish_fb.c index 136a15dec..f590bc1fd 100644 --- a/hw/display/goldfish_fb.c +++ b/hw/display/goldfish_fb.c @@ -157,7 +157,6 @@ static void goldfish_fb_update_display(void *opaque) struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque; DisplaySurface *ds = qemu_console_surface(s->con); int full_update = 0; - int width, height, pitch; if (!s || !s->con || surface_bits_per_pixel(ds) == 0 || !s->fb_base) return; @@ -178,10 +177,9 @@ static void goldfish_fb_update_display(void *opaque) s->need_update = 0; } - pitch = surface_stride(ds); - width = surface_width(ds); - height = surface_height(ds); - + int dest_width = surface_width(ds); + int dest_height = surface_height(ds); + int dest_pitch = surface_stride(ds); int ymin, ymax; #if STATS @@ -202,19 +200,51 @@ static void goldfish_fb_update_display(void *opaque) if (s->blank) { void *dst_line = surface_data(ds); - memset( dst_line, 0, height*pitch ); + memset( dst_line, 0, dest_height*dest_pitch ); ymin = 0; - ymax = height-1; + ymax = dest_height-1; } else { SysBusDevice *dev = SYS_BUS_DEVICE(opaque); MemoryRegion *address_space = sysbus_address_space(dev); - int src_width = width * 2; - int dest_col_pitch = surface_bytes_per_pixel(ds); - int dest_row_pitch = surface_stride(ds); + int src_width, src_height; + int dest_row_pitch, dest_col_pitch; drawfn fn; + /* The source framebuffer is always read in a linear fashion, + * we achieve rotation by altering the destination + * step-per-pixel. + */ + switch (s->rotation) { + case 0: /* Normal, native landscape view */ + src_width = dest_width; + src_height = dest_height; + dest_row_pitch = surface_stride(ds); + dest_col_pitch = surface_bytes_per_pixel(ds); + break; + case 1: /* 90 degree, portrait view */ + src_width = dest_height; + src_height = dest_width; + dest_row_pitch = -surface_bytes_per_pixel(ds); + dest_col_pitch = surface_stride(ds); + break; + case 2: /* 180 degree, inverted landscape view */ + src_width = dest_width; + src_height = dest_height; + dest_row_pitch = -surface_stride(ds); + dest_col_pitch = -surface_bytes_per_pixel(ds); + break; + case 3: /* 270 degree, mirror portrait view */ + src_width = dest_height; + src_height = dest_width; + dest_row_pitch = surface_bytes_per_pixel(ds); + dest_col_pitch = -surface_stride(ds); + break; + default: + g_assert_not_reached(); + } + switch (surface_bits_per_pixel(ds)) { case 0: return; @@ -239,15 +269,26 @@ static void goldfish_fb_update_display(void *opaque) } ymin = 0; - framebuffer_update_display(ds, address_space, s->fb_base, width, height, - src_width, dest_row_pitch, dest_col_pitch, full_update, - fn, ds, &ymin, &ymax); + framebuffer_update_display(ds, address_space, s->fb_base, + src_width, src_height, + src_width * 2, + dest_row_pitch, dest_col_pitch, + full_update, + fn, ds, &ymin, &ymax); } ymax += 1; if (ymin >= 0) { - trace_goldfish_fb_update_display(ymin, ymax-ymin, 0, width); - dpy_gfx_update(s->con, 0, ymin, width, ymax-ymin); + if (s->rotation % 2) { + /* In portrait mode we are drawing "sideways" so always + * need to update the whole screen */ + trace_goldfish_fb_update_display(0, dest_height, 0, dest_width); + dpy_gfx_update(s->con, 0, 0, dest_width, dest_height); + + } else { + trace_goldfish_fb_update_display(ymin, ymax-ymin, 0, dest_width); + dpy_gfx_update(s->con, 0, ymin, dest_width, ymax-ymin); + } } } diff --git a/hw/display/goldfish_fb_template.h b/hw/display/goldfish_fb_template.h index 8579e68e4..871936d09 100644 --- a/hw/display/goldfish_fb_template.h +++ b/hw/display/goldfish_fb_template.h @@ -26,33 +26,29 @@ #define COPY_PIXEL(to, r, g, b) \ do { \ *to = rgb_to_pixel8(r, g, b); \ - to += 1; \ } while (0) #elif BITS == 15 #define COPY_PIXEL(to, r, g, b) \ do { \ *(uint16_t *)to = rgb_to_pixel15(r, g, b); \ - to += 2; \ } while (0) #elif BITS == 16 #define COPY_PIXEL(to, r, g, b) \ do { \ *(uint16_t *)to = rgb_to_pixel16(r, g, b); \ - to += 2; \ } while (0) #elif BITS == 24 #define COPY_PIXEL(to, r, g, b) \ do { \ uint32_t tmp = rgb_to_pixel24(r, g, b); \ - *(to++) = tmp & 0xff; \ - *(to++) = (tmp >> 8) & 0xff; \ - *(to++) = (tmp >> 16) & 0xff; \ + to[0] = tmp & 0xff; \ + to[1] = (tmp >> 8) & 0xff; \ + to[2] = (tmp >> 16) & 0xff; \ } while (0) #elif BITS == 32 #define COPY_PIXEL(to, r, g, b) \ do { \ *(uint32_t *)to = rgb_to_pixel32(r, g, b); \ - to += 4; \ } while (0) #else #error unknown bit depth @@ -70,6 +66,7 @@ static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s, g = ((rgb565 >> 5) & 0x3f) << 2; b = ((rgb565 >> 0) & 0x1f) << 3; COPY_PIXEL(d, r, g, b); + d += deststep; s += 2; } } -- cgit v1.2.3