diff mbox

[v2,7/9] fbdev: move to pixman

Message ID 1347527989-3986-8-git-send-email-kraxel@redhat.com
State New
Headers show

Commit Message

Gerd Hoffmann Sept. 13, 2012, 9:19 a.m. UTC
Stop reinventing the wheel.  Use the pixman library for raster ops.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 configure  |   12 ++++
 ui/fbdev.c |  172 +++++++++++++++++++++++++++++++++++------------------------
 2 files changed, 114 insertions(+), 70 deletions(-)
diff mbox

Patch

diff --git a/configure b/configure
index 0e095dc..634a5bd 100755
--- a/configure
+++ b/configure
@@ -149,6 +149,7 @@  docs=""
 fdt=""
 nptl=""
 sdl=""
+pixman=""
 fbdev="no"
 virtfs=""
 vnc="yes"
@@ -2151,6 +2152,17 @@  else
     exit 1
 fi
 
+if $pkg_config pixman-1 > /dev/null 2>&1
+then
+    pixman="yes"
+    pixman_cflags=`$pkg_config --cflags pixman-1 2>/dev/null`
+    pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null`
+    QEMU_CFLAGS="$QEMU_CFLAGS $pixman_cflags"
+    libs_softmmu="$libs_softmmu $pixman_libs"
+else
+    fbdev="no"
+fi
+
 ##########################################
 # libcap probe
 
diff --git a/ui/fbdev.c b/ui/fbdev.c
index c552810..07fa693 100644
--- a/ui/fbdev.c
+++ b/ui/fbdev.c
@@ -23,11 +23,12 @@ 
 #include <linux/vt.h>
 #include <linux/fb.h>
 
+#include <pixman.h>
+
 #include "qemu-common.h"
 #include "console.h"
 #include "keymaps.h"
 #include "sysemu.h"
-#include "pflib.h"
 
 /*
  * must be last so we get the linux input layer
@@ -70,19 +71,82 @@  static bool                       key_down[KEY_CNT];
 #define FB_ACQ_REQ   3
 static int fb_switch_state;
 
-/* qdev windup */
+/* qemu windup */
 static DisplayChangeListener      *dcl;
-static QemuPfConv                 *conv;
-static PixelFormat                fbpf;
 static int                        resize_screen;
 static int                        redraw_screen;
 static int                        cx, cy, cw, ch;
 static Notifier                   exit_notifier;
+static pixman_image_t             *surface;
+static pixman_image_t             *framebuffer;
+static pixman_transform_t         transform;
+static pixman_region16_t          dirty;
 
 /* fwd decls */
 static int fbdev_activate_vt(int tty, int vtno, bool wait);
 
 /* -------------------------------------------------------------------- */
+/* pixman helpers                                                       */
+
+static int pixman_shifts_to_type(int rshift, int gshift, int bshift)
+{
+    int type = PIXMAN_TYPE_OTHER;
+
+    if (rshift > gshift && gshift > bshift) {
+        if (bshift == 0) {
+            type = PIXMAN_TYPE_ARGB;
+        } else {
+#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0, 21, 8)
+            type = PIXMAN_TYPE_RGBA;
+#endif
+        }
+    } else if (rshift < gshift && gshift < bshift) {
+        if (rshift == 0) {
+            type = PIXMAN_TYPE_ABGR;
+        } else {
+            type = PIXMAN_TYPE_BGRA;
+        }
+    }
+    return type;
+}
+
+static pixman_image_t *pixman_from_displaystate(DisplayState *ds)
+{
+    PixelFormat *pf = &ds->surface->pf;
+    pixman_format_code_t format;
+    pixman_image_t *image;
+    int type;
+
+    type = pixman_shifts_to_type(pf->rshift, pf->gshift, pf->bshift);
+    format = PIXMAN_FORMAT(pf->bits_per_pixel, type,
+                           pf->abits, pf->rbits, pf->gbits, pf->bbits);
+    image = pixman_image_create_bits(format, ds_get_width(ds),
+                                     ds_get_height(ds),
+                                     (void *)ds_get_data(ds),
+                                     ds_get_linesize(ds));
+    return image;
+}
+
+static pixman_image_t *pixman_from_framebuffer(void)
+{
+    pixman_format_code_t format;
+    pixman_image_t *image;
+    int type;
+
+    type = pixman_shifts_to_type(fb_var.red.offset,
+                                 fb_var.green.offset,
+                                 fb_var.blue.offset);
+    format = PIXMAN_FORMAT(fb_var.bits_per_pixel, type,
+                           fb_var.transp.length,
+                           fb_var.red.length,
+                           fb_var.green.length,
+                           fb_var.blue.length);
+    image = pixman_image_create_bits(format, fb_var.xres, fb_var.yres,
+                                     (void *)fb_mem, fb_fix.line_length);
+    return image;
+}
+
+/* -------------------------------------------------------------------- */
 /* mouse                                                                */
 
 static void read_mouse(void *opaque)
@@ -529,6 +593,17 @@  static void fbdev_cleanup(void)
 {
     trace_fbdev_cleanup();
 
+    /* release pixman stuff */
+    pixman_region_fini(&dirty);
+    if (framebuffer) {
+        pixman_image_unref(framebuffer);
+        framebuffer = NULL;
+    }
+    if (surface) {
+        pixman_image_unref(surface);
+        surface = NULL;
+    }
+
     /* restore console */
     if (fb_mem != NULL) {
         munmap(fb_mem, fb_fix.smem_len+fb_mem_offset);
@@ -681,36 +756,8 @@  static int fbdev_init(const char *device)
     start_mediumraw(tty);
     qemu_set_fd_handler(tty, read_mediumraw, NULL, NULL);
 
-    /* create PixelFormat from fbdev structs */
-    fbpf.bits_per_pixel  = fb_var.bits_per_pixel;
-    fbpf.bytes_per_pixel = (fb_var.bits_per_pixel+7)/8;
-    fbpf.depth           = fb_var.bits_per_pixel == 32
-        ? 24 : fb_var.bits_per_pixel;
-    fbpf.rshift          = fb_var.red.offset;
-    fbpf.rbits           = fb_var.red.length;
-    fbpf.gshift          = fb_var.green.offset;
-    fbpf.gbits           = fb_var.green.length;
-    fbpf.bshift          = fb_var.blue.offset;
-    fbpf.bbits           = fb_var.blue.length;
-    fbpf.ashift          = fb_var.transp.offset;
-    fbpf.abits           = fb_var.transp.length;
-
-    if (fbpf.rbits) {
-        fbpf.rmax   = (1 << fbpf.rbits) - 1;
-        fbpf.rmask  = fbpf.rmax << fbpf.rshift;
-    }
-    if (fbpf.gbits) {
-        fbpf.gmax   = (1 << fbpf.gbits) - 1;
-        fbpf.gmask  = fbpf.gmax << fbpf.gshift;
-    }
-    if (fbpf.bbits) {
-        fbpf.bmax   = (1 << fbpf.bbits) - 1;
-        fbpf.bmask  = fbpf.bmax << fbpf.bshift;
-    }
-    if (fbpf.abits) {
-        fbpf.amax   = (1 << fbpf.abits) - 1;
-        fbpf.amask  = fbpf.amax << fbpf.ashift;
-    }
+    framebuffer = pixman_from_framebuffer();
+    pixman_region_init(&dirty);
     return 0;
 
 err_early:
@@ -807,36 +854,15 @@  static int fbdev_switch_init(void)
 /* -------------------------------------------------------------------- */
 /* rendering                                                            */
 
-static void fbdev_render(DisplayState *ds, int x, int y, int w, int h)
+static void fbdev_render(DisplayState *ds)
 {
-    uint8_t *dst;
-    uint8_t *src;
-    int line;
+    assert(surface);
 
-    if (!conv) {
-        return;
-    }
-
-    src = ds_get_data(ds) + y * ds_get_linesize(ds)
-        + x * ds_get_bytes_per_pixel(ds);
-    dst = fb_mem + y * fb_fix.line_length
-        + x * fbpf.bytes_per_pixel;
-
-    dst += cy * fb_fix.line_length;
-    dst += cx * fbpf.bytes_per_pixel;
-
-    if (h > fb_var.yres - y) {
-        h = fb_var.yres - y;
-    }
-    if (w > fb_var.xres - x) {
-        w = fb_var.xres - x;
-    }
-
-    for (line = y; line < y+h; line++) {
-        qemu_pf_conv_run(conv, dst, src, w);
-        dst += fb_fix.line_length;
-        src += ds_get_linesize(ds);
-    }
+    pixman_image_set_clip_region(surface, &dirty);
+    pixman_image_composite(PIXMAN_OP_SRC, surface, NULL, framebuffer,
+                           0, 0, 0, 0, 0, 0, fb_var.xres, fb_var.yres);
+    pixman_region_fini(&dirty);
+    pixman_region_init(&dirty);
 }
 
 /* -------------------------------------------------------------------- */
@@ -860,14 +886,16 @@  static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
         if (ds_get_height(ds) < fb_var.yres) {
             cy = (fb_var.yres - ds_get_height(ds)) / 2;
         }
-
-        if (conv) {
-            qemu_pf_conv_put(conv);
-        }
-        conv = qemu_pf_conv_get(&fbpf, &ds->surface->pf);
-        if (conv == NULL) {
-            fprintf(stderr, "fbdev: unsupported PixelFormat conversion\n");
+        if (surface) {
+            pixman_image_unref(surface);
         }
+        surface = pixman_from_displaystate(ds);
+
+        pixman_transform_init_identity(&transform);
+        pixman_transform_translate(&transform, NULL,
+                                   pixman_int_to_fixed(-cx),
+                                   pixman_int_to_fixed(-cy));
+        pixman_image_set_transform(surface, &transform);
     }
 
     if (redraw_screen) {
@@ -877,7 +905,7 @@  static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
         x = 0; y = 0; w = ds_get_width(ds); h = ds_get_height(ds);
     }
 
-    fbdev_render(ds, x, y, w, h);
+    pixman_region_union_rect(&dirty, &dirty, x, y, w, h);
 }
 
 static void fbdev_resize(DisplayState *ds)
@@ -904,6 +932,10 @@  static void fbdev_refresh(DisplayState *ds)
     if (redraw_screen) {
         fbdev_update(ds, 0, 0, 0, 0);
     }
+
+    if (pixman_region_not_empty(&dirty)) {
+        fbdev_render(ds);
+    }
 }
 
 static void fbdev_exit_notifier(Notifier *notifier, void *data)