aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Bennée <alex.bennee@linaro.org>2014-12-04 15:54:13 +0000
committerAlex Bennée <alex.bennee@linaro.org>2014-12-19 12:29:36 +0000
commit98b2c93b214333865272d74c6a4f753ce546efda (patch)
treee33eb06ff0fc002719d8aae3b3fd5fac8c150206
parent83447f2cf7bc883b2aeeadd5db71d9d249929309 (diff)
goldfish_fb: implement basic rotation support
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 <alex.bennee@linaro.org>
-rw-r--r--hw/display/goldfish_fb.c71
-rw-r--r--hw/display/goldfish_fb_template.h11
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;
}
}