summaryrefslogtreecommitdiffstats
path: root/hw/display/pxa2xx_lcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/display/pxa2xx_lcd.c')
-rw-r--r--hw/display/pxa2xx_lcd.c520
1 files changed, 450 insertions, 70 deletions
diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c
index dfff994962..2887ce496b 100644
--- a/hw/display/pxa2xx_lcd.c
+++ b/hw/display/pxa2xx_lcd.c
@@ -45,7 +45,6 @@ struct PXA2xxLCDState {
int invalidated;
QemuConsole *con;
- drawfn *line_fn[2];
int dest_width;
int xres, yres;
int pal_for;
@@ -188,6 +187,435 @@ typedef struct QEMU_PACKED {
#define LDCMD_SOFINT (1 << 22)
#define LDCMD_PAL (1 << 26)
+/* Size of a pixel in the QEMU UI output surface, in bytes */
+#define DEST_PIXEL_WIDTH 4
+
+/* Line drawing code to handle the various possible guest pixel formats */
+
+# define SKIP_PIXEL(to) do { to += deststep; } while (0)
+# define COPY_PIXEL(to, from) \
+ do { \
+ *(uint32_t *) to = from; \
+ SKIP_PIXEL(to); \
+ } while (0)
+
+#ifdef HOST_WORDS_BIGENDIAN
+# define SWAP_WORDS 1
+#endif
+
+#define FN_2(x) FN(x + 1) FN(x)
+#define FN_4(x) FN_2(x + 2) FN_2(x)
+
+static void pxa2xx_draw_line2(void *opaque, uint8_t *dest, const uint8_t *src,
+ int width, int deststep)
+{
+ uint32_t *palette = opaque;
+ uint32_t data;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]);
+#ifdef SWAP_WORDS
+ FN_4(12)
+ FN_4(8)
+ FN_4(4)
+ FN_4(0)
+#else
+ FN_4(0)
+ FN_4(4)
+ FN_4(8)
+ FN_4(12)
+#endif
+#undef FN
+ width -= 16;
+ src += 4;
+ }
+}
+
+static void pxa2xx_draw_line4(void *opaque, uint8_t *dest, const uint8_t *src,
+ int width, int deststep)
+{
+ uint32_t *palette = opaque;
+ uint32_t data;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]);
+#ifdef SWAP_WORDS
+ FN_2(6)
+ FN_2(4)
+ FN_2(2)
+ FN_2(0)
+#else
+ FN_2(0)
+ FN_2(2)
+ FN_2(4)
+ FN_2(6)
+#endif
+#undef FN
+ width -= 8;
+ src += 4;
+ }
+}
+
+static void pxa2xx_draw_line8(void *opaque, uint8_t *dest, const uint8_t *src,
+ int width, int deststep)
+{
+ uint32_t *palette = opaque;
+ uint32_t data;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#define FN(x) COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]);
+#ifdef SWAP_WORDS
+ FN(24)
+ FN(16)
+ FN(8)
+ FN(0)
+#else
+ FN(0)
+ FN(8)
+ FN(16)
+ FN(24)
+#endif
+#undef FN
+ width -= 4;
+ src += 4;
+ }
+}
+
+static void pxa2xx_draw_line16(void *opaque, uint8_t *dest, const uint8_t *src,
+ int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x3f) << 2;
+ data >>= 6;
+ r = (data & 0x1f) << 3;
+ data >>= 5;
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ b = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x3f) << 2;
+ data >>= 6;
+ r = (data & 0x1f) << 3;
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ width -= 2;
+ src += 4;
+ }
+}
+
+static void pxa2xx_draw_line16t(void *opaque, uint8_t *dest, const uint8_t *src,
+ int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x1f) << 3;
+ data >>= 5;
+ r = (data & 0x1f) << 3;
+ data >>= 5;
+ if (data & 1) {
+ SKIP_PIXEL(dest);
+ } else {
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ }
+ data >>= 1;
+ b = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x1f) << 3;
+ data >>= 5;
+ r = (data & 0x1f) << 3;
+ data >>= 5;
+ if (data & 1) {
+ SKIP_PIXEL(dest);
+ } else {
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ }
+ width -= 2;
+ src += 4;
+ }
+}
+
+static void pxa2xx_draw_line18(void *opaque, uint8_t *dest, const uint8_t *src,
+ int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = (data & 0x3f) << 2;
+ data >>= 6;
+ g = (data & 0x3f) << 2;
+ data >>= 6;
+ r = (data & 0x3f) << 2;
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ width -= 1;
+ src += 4;
+ }
+}
+
+/* The wicked packed format */
+static void pxa2xx_draw_line18p(void *opaque, uint8_t *dest, const uint8_t *src,
+ int width, int deststep)
+{
+ uint32_t data[3];
+ unsigned int r, g, b;
+ while (width > 0) {
+ data[0] = *(uint32_t *) src;
+ src += 4;
+ data[1] = *(uint32_t *) src;
+ src += 4;
+ data[2] = *(uint32_t *) src;
+ src += 4;
+#ifdef SWAP_WORDS
+ data[0] = bswap32(data[0]);
+ data[1] = bswap32(data[1]);
+ data[2] = bswap32(data[2]);
+#endif
+ b = (data[0] & 0x3f) << 2;
+ data[0] >>= 6;
+ g = (data[0] & 0x3f) << 2;
+ data[0] >>= 6;
+ r = (data[0] & 0x3f) << 2;
+ data[0] >>= 12;
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ b = (data[0] & 0x3f) << 2;
+ data[0] >>= 6;
+ g = ((data[1] & 0xf) << 4) | (data[0] << 2);
+ data[1] >>= 4;
+ r = (data[1] & 0x3f) << 2;
+ data[1] >>= 12;
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ b = (data[1] & 0x3f) << 2;
+ data[1] >>= 6;
+ g = (data[1] & 0x3f) << 2;
+ data[1] >>= 6;
+ r = ((data[2] & 0x3) << 6) | (data[1] << 2);
+ data[2] >>= 8;
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ b = (data[2] & 0x3f) << 2;
+ data[2] >>= 6;
+ g = (data[2] & 0x3f) << 2;
+ data[2] >>= 6;
+ r = data[2] << 2;
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ width -= 4;
+ }
+}
+
+static void pxa2xx_draw_line19(void *opaque, uint8_t *dest, const uint8_t *src,
+ int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = (data & 0x3f) << 2;
+ data >>= 6;
+ g = (data & 0x3f) << 2;
+ data >>= 6;
+ r = (data & 0x3f) << 2;
+ data >>= 6;
+ if (data & 1) {
+ SKIP_PIXEL(dest);
+ } else {
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ }
+ width -= 1;
+ src += 4;
+ }
+}
+
+/* The wicked packed format */
+static void pxa2xx_draw_line19p(void *opaque, uint8_t *dest, const uint8_t *src,
+ int width, int deststep)
+{
+ uint32_t data[3];
+ unsigned int r, g, b;
+ while (width > 0) {
+ data[0] = *(uint32_t *) src;
+ src += 4;
+ data[1] = *(uint32_t *) src;
+ src += 4;
+ data[2] = *(uint32_t *) src;
+ src += 4;
+# ifdef SWAP_WORDS
+ data[0] = bswap32(data[0]);
+ data[1] = bswap32(data[1]);
+ data[2] = bswap32(data[2]);
+# endif
+ b = (data[0] & 0x3f) << 2;
+ data[0] >>= 6;
+ g = (data[0] & 0x3f) << 2;
+ data[0] >>= 6;
+ r = (data[0] & 0x3f) << 2;
+ data[0] >>= 6;
+ if (data[0] & 1) {
+ SKIP_PIXEL(dest);
+ } else {
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ }
+ data[0] >>= 6;
+ b = (data[0] & 0x3f) << 2;
+ data[0] >>= 6;
+ g = ((data[1] & 0xf) << 4) | (data[0] << 2);
+ data[1] >>= 4;
+ r = (data[1] & 0x3f) << 2;
+ data[1] >>= 6;
+ if (data[1] & 1) {
+ SKIP_PIXEL(dest);
+ } else {
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ }
+ data[1] >>= 6;
+ b = (data[1] & 0x3f) << 2;
+ data[1] >>= 6;
+ g = (data[1] & 0x3f) << 2;
+ data[1] >>= 6;
+ r = ((data[2] & 0x3) << 6) | (data[1] << 2);
+ data[2] >>= 2;
+ if (data[2] & 1) {
+ SKIP_PIXEL(dest);
+ } else {
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ }
+ data[2] >>= 6;
+ b = (data[2] & 0x3f) << 2;
+ data[2] >>= 6;
+ g = (data[2] & 0x3f) << 2;
+ data[2] >>= 6;
+ r = data[2] << 2;
+ data[2] >>= 6;
+ if (data[2] & 1) {
+ SKIP_PIXEL(dest);
+ } else {
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ }
+ width -= 4;
+ }
+}
+
+static void pxa2xx_draw_line24(void *opaque, uint8_t *dest, const uint8_t *src,
+ int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = data & 0xff;
+ data >>= 8;
+ g = data & 0xff;
+ data >>= 8;
+ r = data & 0xff;
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ width -= 1;
+ src += 4;
+ }
+}
+
+static void pxa2xx_draw_line24t(void *opaque, uint8_t *dest, const uint8_t *src,
+ int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = (data & 0x7f) << 1;
+ data >>= 7;
+ g = data & 0xff;
+ data >>= 8;
+ r = data & 0xff;
+ data >>= 8;
+ if (data & 1) {
+ SKIP_PIXEL(dest);
+ } else {
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ }
+ width -= 1;
+ src += 4;
+ }
+}
+
+static void pxa2xx_draw_line25(void *opaque, uint8_t *dest, const uint8_t *src,
+ int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = data & 0xff;
+ data >>= 8;
+ g = data & 0xff;
+ data >>= 8;
+ r = data & 0xff;
+ data >>= 8;
+ if (data & 1) {
+ SKIP_PIXEL(dest);
+ } else {
+ COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
+ }
+ width -= 1;
+ src += 4;
+ }
+}
+
+/* Overlay planes disabled, no transparency */
+static drawfn pxa2xx_draw_fn_32[16] = {
+ [0 ... 0xf] = NULL,
+ [pxa_lcdc_2bpp] = pxa2xx_draw_line2,
+ [pxa_lcdc_4bpp] = pxa2xx_draw_line4,
+ [pxa_lcdc_8bpp] = pxa2xx_draw_line8,
+ [pxa_lcdc_16bpp] = pxa2xx_draw_line16,
+ [pxa_lcdc_18bpp] = pxa2xx_draw_line18,
+ [pxa_lcdc_18pbpp] = pxa2xx_draw_line18p,
+ [pxa_lcdc_24bpp] = pxa2xx_draw_line24,
+};
+
+/* Overlay planes enabled, transparency used */
+static drawfn pxa2xx_draw_fn_32t[16] = {
+ [0 ... 0xf] = NULL,
+ [pxa_lcdc_4bpp] = pxa2xx_draw_line4,
+ [pxa_lcdc_8bpp] = pxa2xx_draw_line8,
+ [pxa_lcdc_16bpp] = pxa2xx_draw_line16t,
+ [pxa_lcdc_19bpp] = pxa2xx_draw_line19,
+ [pxa_lcdc_19pbpp] = pxa2xx_draw_line19p,
+ [pxa_lcdc_24bpp] = pxa2xx_draw_line24t,
+ [pxa_lcdc_25bpp] = pxa2xx_draw_line25,
+};
+
+#undef COPY_PIXEL
+#undef SKIP_PIXEL
+
+#ifdef SWAP_WORDS
+# undef SWAP_WORDS
+#endif
+
/* Route internal interrupt lines to the global IC */
static void pxa2xx_lcdc_int_update(PXA2xxLCDState *s)
{
@@ -674,14 +1102,21 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
}
}
+static inline drawfn pxa2xx_drawfn(PXA2xxLCDState *s)
+{
+ if (s->transp) {
+ return pxa2xx_draw_fn_32t[s->bpp];
+ } else {
+ return pxa2xx_draw_fn_32[s->bpp];
+ }
+}
+
static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
hwaddr addr, int *miny, int *maxy)
{
DisplaySurface *surface = qemu_console_surface(s->con);
int src_width, dest_width;
- drawfn fn = NULL;
- if (s->dest_width)
- fn = s->line_fn[s->transp][s->bpp];
+ drawfn fn = pxa2xx_drawfn(s);
if (!fn)
return;
@@ -693,14 +1128,14 @@ static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
else if (s->bpp > pxa_lcdc_8bpp)
src_width *= 2;
- dest_width = s->xres * s->dest_width;
+ dest_width = s->xres * DEST_PIXEL_WIDTH;
*miny = 0;
if (s->invalidated) {
framebuffer_update_memory_section(&s->fbsection, s->sysmem,
addr, s->yres, src_width);
}
framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, dest_width, s->dest_width,
+ src_width, dest_width, DEST_PIXEL_WIDTH,
s->invalidated,
fn, s->dma_ch[0].palette, miny, maxy);
}
@@ -710,9 +1145,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
{
DisplaySurface *surface = qemu_console_surface(s->con);
int src_width, dest_width;
- drawfn fn = NULL;
- if (s->dest_width)
- fn = s->line_fn[s->transp][s->bpp];
+ drawfn fn = pxa2xx_drawfn(s);
if (!fn)
return;
@@ -724,14 +1157,14 @@ static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
else if (s->bpp > pxa_lcdc_8bpp)
src_width *= 2;
- dest_width = s->yres * s->dest_width;
+ dest_width = s->yres * DEST_PIXEL_WIDTH;
*miny = 0;
if (s->invalidated) {
framebuffer_update_memory_section(&s->fbsection, s->sysmem,
addr, s->yres, src_width);
}
framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, s->dest_width, -dest_width,
+ src_width, DEST_PIXEL_WIDTH, -dest_width,
s->invalidated,
fn, s->dma_ch[0].palette,
miny, maxy);
@@ -742,10 +1175,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
{
DisplaySurface *surface = qemu_console_surface(s->con);
int src_width, dest_width;
- drawfn fn = NULL;
- if (s->dest_width) {
- fn = s->line_fn[s->transp][s->bpp];
- }
+ drawfn fn = pxa2xx_drawfn(s);
if (!fn) {
return;
}
@@ -759,14 +1189,14 @@ static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
src_width *= 2;
}
- dest_width = s->xres * s->dest_width;
+ dest_width = s->xres * DEST_PIXEL_WIDTH;
*miny = 0;
if (s->invalidated) {
framebuffer_update_memory_section(&s->fbsection, s->sysmem,
addr, s->yres, src_width);
}
framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, -dest_width, -s->dest_width,
+ src_width, -dest_width, -DEST_PIXEL_WIDTH,
s->invalidated,
fn, s->dma_ch[0].palette, miny, maxy);
}
@@ -776,10 +1206,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
{
DisplaySurface *surface = qemu_console_surface(s->con);
int src_width, dest_width;
- drawfn fn = NULL;
- if (s->dest_width) {
- fn = s->line_fn[s->transp][s->bpp];
- }
+ drawfn fn = pxa2xx_drawfn(s);
if (!fn) {
return;
}
@@ -793,14 +1220,14 @@ static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
src_width *= 2;
}
- dest_width = s->yres * s->dest_width;
+ dest_width = s->yres * DEST_PIXEL_WIDTH;
*miny = 0;
if (s->invalidated) {
framebuffer_update_memory_section(&s->fbsection, s->sysmem,
addr, s->yres, src_width);
}
framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, -s->dest_width, dest_width,
+ src_width, -DEST_PIXEL_WIDTH, dest_width,
s->invalidated,
fn, s->dma_ch[0].palette,
miny, maxy);
@@ -990,17 +1417,6 @@ static const VMStateDescription vmstate_pxa2xx_lcdc = {
}
};
-#define BITS 8
-#include "pxa2xx_template.h"
-#define BITS 15
-#include "pxa2xx_template.h"
-#define BITS 16
-#include "pxa2xx_template.h"
-#define BITS 24
-#include "pxa2xx_template.h"
-#define BITS 32
-#include "pxa2xx_template.h"
-
static const GraphicHwOps pxa2xx_ops = {
.invalidate = pxa2xx_invalidate_display,
.gfx_update = pxa2xx_update_display,
@@ -1010,7 +1426,6 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
hwaddr base, qemu_irq irq)
{
PXA2xxLCDState *s;
- DisplaySurface *surface;
s = (PXA2xxLCDState *) g_malloc0(sizeof(PXA2xxLCDState));
s->invalidated = 1;
@@ -1024,41 +1439,6 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
memory_region_add_subregion(sysmem, base, &s->iomem);
s->con = graphic_console_init(NULL, 0, &pxa2xx_ops, s);
- surface = qemu_console_surface(s->con);
-
- switch (surface_bits_per_pixel(surface)) {
- case 0:
- s->dest_width = 0;
- break;
- case 8:
- s->line_fn[0] = pxa2xx_draw_fn_8;
- s->line_fn[1] = pxa2xx_draw_fn_8t;
- s->dest_width = 1;
- break;
- case 15:
- s->line_fn[0] = pxa2xx_draw_fn_15;
- s->line_fn[1] = pxa2xx_draw_fn_15t;
- s->dest_width = 2;
- break;
- case 16:
- s->line_fn[0] = pxa2xx_draw_fn_16;
- s->line_fn[1] = pxa2xx_draw_fn_16t;
- s->dest_width = 2;
- break;
- case 24:
- s->line_fn[0] = pxa2xx_draw_fn_24;
- s->line_fn[1] = pxa2xx_draw_fn_24t;
- s->dest_width = 3;
- break;
- case 32:
- s->line_fn[0] = pxa2xx_draw_fn_32;
- s->line_fn[1] = pxa2xx_draw_fn_32t;
- s->dest_width = 4;
- break;
- default:
- fprintf(stderr, "%s: Bad color depth\n", __func__);
- exit(1);
- }
vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s);