VIGS: software backend implementation
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Thu, 11 Apr 2013 07:07:27 +0000 (11:07 +0400)
committerStanislav Vorobiov <s.vorobiov@samsung.com>
Mon, 15 Apr 2013 11:24:19 +0000 (15:24 +0400)
Makefile.target
hw/vigs_backend.h
hw/vigs_device.c
hw/vigs_sw_backend.c [new file with mode: 0644]
vl.c

index 201724c..6d75543 100755 (executable)
@@ -325,6 +325,7 @@ obj-y += vigs_id_gen.o
 obj-y += vigs_vector.o
 obj-y += vigs_ref.o
 obj-y += vigs_gl_backend.o
+obj-y += vigs_sw_backend.o
 # GL GLX backend
 ifdef CONFIG_LINUX
 obj-y += vigs_gl_backend_glx.o
index 4e984ae..3b9df93 100644 (file)
@@ -27,5 +27,6 @@ void vigs_backend_init(struct vigs_backend *backend,
 void vigs_backend_cleanup(struct vigs_backend *backend);
 
 struct vigs_backend *vigs_gl_backend_create(void *display);
+struct vigs_backend *vigs_sw_backend_create(void);
 
 #endif
index e63c19f..079c057 100644 (file)
@@ -69,6 +69,8 @@ typedef struct VIGSState
 
 #define TYPE_VIGS_DEVICE "vigs"
 
+extern const char *vigs_backend;
+
 static void vigs_hw_update(void *opaque)
 {
     VIGSState *s = opaque;
@@ -227,7 +229,11 @@ static int vigs_device_init(PCIDevice *dev)
     pci_register_bar(&s->dev.pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_bar);
     pci_register_bar(&s->dev.pci_dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io_bar);
 
-    backend = vigs_gl_backend_create(s->display);
+    if (!strcmp(vigs_backend, "gl")) {
+        backend = vigs_gl_backend_create(s->display);
+    } else if (!strcmp(vigs_backend, "sw")) {
+        backend = vigs_sw_backend_create();
+    }
 
     if (!backend) {
         goto fail;
diff --git a/hw/vigs_sw_backend.c b/hw/vigs_sw_backend.c
new file mode 100644 (file)
index 0000000..4b3659c
--- /dev/null
@@ -0,0 +1,336 @@
+#include "vigs_surface.h"
+#include "vigs_id_gen.h"
+#include "vigs_log.h"
+#include "vigs_utils.h"
+#include "vigs_ref.h"
+#include "vigs_backend.h"
+#include "winsys.h"
+#include "vigs_vector.h"
+
+typedef struct VigsWinsysSWSurface {
+    struct winsys_surface base;
+    struct vigs_ref ref;
+} VigsWinsysSWSurface;
+
+typedef struct VigsSWSurface
+{
+    struct vigs_surface base;
+    uint8_t *data;
+} VigsSWSurface;
+
+static void vigs_winsys_sw_surface_acquire(struct winsys_surface *sfc)
+{
+    VigsWinsysSWSurface *vigs_sfc = (VigsWinsysSWSurface *)sfc;
+    vigs_ref_acquire(&vigs_sfc->ref);
+}
+
+static void vigs_winsys_sw_surface_release(struct winsys_surface *sfc)
+{
+    VigsWinsysSWSurface *vigs_sfc = (VigsWinsysSWSurface *)sfc;
+    vigs_ref_release(&vigs_sfc->ref);
+}
+
+static void vigs_winsys_sw_surface_destroy(struct vigs_ref *ref)
+{
+    VigsWinsysSWSurface *vigs_sfc = container_of(ref, VigsWinsysSWSurface, ref);
+
+    vigs_ref_cleanup(&vigs_sfc->ref);
+    g_free(vigs_sfc);
+}
+
+static void vigs_sw_surface_update(struct vigs_surface *sfc,
+                                   vigsp_offset vram_offset,
+                                   uint8_t *data)
+{
+    VigsSWSurface *sw_sfc = (VigsSWSurface *)sfc;
+
+    VIGS_LOG_TRACE("update surface %d: VRAM offset=%d, addr=%p",
+                   sfc->id, vram_offset, data);
+
+    assert(data && vram_offset >= 0);
+
+    if (vram_offset == sfc->vram_offset) {
+        return;
+    }
+
+    memcpy(data, sw_sfc->data, sfc->stride * sfc->height);
+
+    if (sfc->vram_offset < 0) {
+        g_free(sw_sfc->data);
+        sw_sfc->data = NULL;
+    }
+
+    sfc->vram_offset = vram_offset;
+    sw_sfc->data = sfc->data = data;
+}
+
+static void vigs_sw_surface_set_data(struct vigs_surface *sfc,
+                                     vigsp_offset vram_offset,
+                                     uint8_t *data)
+{
+    VigsSWSurface *sw_sfc = (VigsSWSurface *)sfc;
+
+    VIGS_LOG_TRACE("set data of surface %d: VRAM offset=%d, addr=%p",
+                   sfc->id, vram_offset, data);
+
+    assert(data && vram_offset >= 0);
+
+    if (sfc->vram_offset < 0) {
+        g_free(sw_sfc->data);
+        sw_sfc->data = NULL;
+    }
+    sfc->vram_offset = vram_offset;
+    sw_sfc->data = sfc->data = data;
+}
+
+static void vigs_sw_surface_read_pixels(struct vigs_surface *sfc,
+                                        uint32_t x,
+                                        uint32_t y,
+                                        uint32_t width,
+                                        uint32_t height,
+                                        uint32_t stride,
+                                        uint8_t *pixels)
+{
+    VigsSWSurface *sw_sfc = (VigsSWSurface *)sfc;
+    const unsigned bpp = vigs_format_bpp(sfc->format);
+    unsigned line;
+    const uint8_t *copy_from;
+
+    VIGS_LOG_TRACE("read %dx%d region from (%d, %d) of surface %d (stride=%d)",
+                   width, height, x, y, sfc->id, stride);
+
+    if (pixels == sw_sfc->data) {
+        return;
+    }
+
+    copy_from = sw_sfc->data + y * sfc->stride + x * bpp;
+
+    for (line = 0; line < height; ++line) {
+        memcpy(pixels, copy_from, width * bpp);
+        pixels += stride;
+        copy_from += sfc->stride;
+    }
+}
+
+static void vigs_sw_surface_copy(struct vigs_surface *dst,
+                                 struct vigs_surface *src,
+                                 const struct vigsp_copy *entries,
+                                 uint32_t num_entries)
+{
+    VigsSWSurface *sw_dst = (VigsSWSurface *)dst;
+    VigsSWSurface *sw_src = (VigsSWSurface *)src;
+    const unsigned dst_stride = dst->stride;
+    const unsigned src_stride = src->stride;
+    const unsigned bpp = vigs_format_bpp(dst->format);
+    uint8_t *dst_data;
+    const uint8_t *src_data;
+    unsigned i, line;
+
+    VIGS_LOG_TRACE("copy %d regions of surface %d to surface %d",
+                    num_entries, src->id, dst->id);
+
+    if (dst->format != src->format) {
+        VIGS_LOG_ERROR("Source and destination formats differ");
+        return;
+    }
+
+    for (i = 0; i < num_entries; ++i) {
+        /* In case we're copying overlapping regions of the same image */
+        if (entries[i].from.y < entries[i].to.y) {
+            dst_data = sw_dst->data +
+                       (entries[i].to.y + entries[i].size.h - 1) * dst_stride +
+                       entries[i].to.x * bpp;
+            src_data = sw_src->data +
+                       (entries[i].from.y + entries[i].size.h - 1) * src_stride +
+                       entries[i].from.x * bpp;
+
+            for (line = entries[i].size.h; line; --line) {
+                memcpy(dst_data, src_data, entries[i].size.w * bpp);
+                dst_data -= dst_stride;
+                src_data -= src_stride;
+            }
+        } else {
+            dst_data = sw_dst->data + entries[i].to.y * dst_stride +
+                       entries[i].to.x * bpp;
+            src_data = sw_src->data + entries[i].from.y * src_stride +
+                       entries[i].from.x * bpp;
+
+            for (line = 0; line < entries[i].size.h; ++line) {
+                memmove(dst_data, src_data, entries[i].size.w * bpp);
+                dst_data += dst_stride;
+                src_data += src_stride;
+            }
+        }
+    }
+}
+
+static void vigs_sw_surface_solid_fill(struct vigs_surface *sfc,
+                                       vigsp_color color,
+                                       const struct vigsp_rect *entries,
+                                       uint32_t num_entries)
+{
+    VigsSWSurface *sw_sfc = (VigsSWSurface *)sfc;
+    const unsigned bpp = vigs_format_bpp(sfc->format);
+    const unsigned stride = sfc->stride;
+    uint8_t *first_line, *line_data;
+    unsigned i, entry;
+
+    VIGS_LOG_TRACE("fill %d regions of surface %d with color 0x%x",
+                    num_entries, sfc->id, color);
+
+    switch (sfc->format) {
+    case vigsp_surface_bgra8888:
+        break;
+    case vigsp_surface_bgrx8888:
+        color |= 0xff << 24;
+        break;
+    default:
+        hw_error("Unknown color format %d\n", sfc->format);
+        break;
+    }
+
+    for (entry = 0; entry < num_entries; ++entry) {
+        first_line = sw_sfc->data + entries[entry].pos.y * stride;
+        line_data = first_line;
+        i = entries[entry].pos.x;
+        switch (bpp) {
+        case 4:
+            for (; i < (entries[entry].pos.x + entries[entry].size.w); ++i) {
+                ((uint32_t *)line_data)[i] = color;
+            }
+            break;
+        case 2:
+            for (; i < (entries[entry].pos.x + entries[entry].size.w); ++i) {
+                ((uint16_t *)line_data)[i] = color;
+            }
+            break;
+        default:
+            memset(&line_data[i], color, entries[entry].size.w);
+            break;
+        }
+
+        line_data += stride;
+        for (i = 1; i < entries[entry].size.h; ++i) {
+            memcpy(&line_data[entries[entry].pos.x * bpp],
+                   &first_line[entries[entry].pos.x * bpp],
+                   entries[entry].size.w * bpp);
+            line_data += stride;
+        }
+    }
+}
+
+static void vigs_sw_surface_put_image(struct vigs_surface *sfc,
+                                      const void *src,
+                                      uint32_t src_stride,
+                                      const struct vigsp_rect *rect)
+{
+    VigsSWSurface *sw_sfc = (VigsSWSurface *)sfc;
+    const unsigned bpp = vigs_format_bpp(sfc->format);
+    unsigned line;
+    uint8_t *sfc_data;
+
+    VIGS_LOG_TRACE("image %dx%d put at (%d, %d) of surface %d",
+        rect->size.w, rect->size.h, rect->pos.x, rect->pos.y, sfc->id);
+
+    sfc_data = sw_sfc->data + sfc->stride * rect->pos.y + rect->pos.x * bpp;
+    for (line = 0; line < rect->size.h; ++line) {
+        memcpy(sfc_data, src, rect->size.w * bpp);
+        sfc_data += sfc->stride;
+        src += src_stride;
+    }
+}
+
+static void vigs_sw_surface_destroy(struct vigs_surface *sfc)
+{
+    VigsSWSurface *sw_sfc = (VigsSWSurface *)sfc;
+
+    VIGS_LOG_TRACE("surface %d destroyed", sfc->id);
+
+    if (sfc->vram_offset < 0) {
+        g_free(sw_sfc->data);
+        sw_sfc->data = NULL;
+    }
+    vigs_surface_cleanup(&sw_sfc->base);
+    g_free(sw_sfc);
+}
+
+static VigsWinsysSWSurface *vigs_winsys_sw_surface_create(uint32_t width,
+                                                          uint32_t height)
+{
+    VigsWinsysSWSurface *ws_sfc;
+
+    ws_sfc = g_new0(VigsWinsysSWSurface, 1);
+
+    ws_sfc->base.width = width;
+    ws_sfc->base.height = height;
+    ws_sfc->base.acquire = &vigs_winsys_sw_surface_acquire;
+    ws_sfc->base.release = &vigs_winsys_sw_surface_release;
+
+    vigs_ref_init(&ws_sfc->ref, &vigs_winsys_sw_surface_destroy);
+
+    return ws_sfc;
+}
+
+static struct vigs_surface *vigs_sw_backend_create_surface(struct vigs_backend *backend,
+                                                           uint32_t width,
+                                                           uint32_t height,
+                                                           uint32_t stride,
+                                                           vigsp_surface_format format,
+                                                           vigsp_offset vram_offset,
+                                                           uint8_t *data)
+{
+    VigsSWSurface *sw_sfc = NULL;
+    VigsWinsysSWSurface *ws_sfc;
+
+    sw_sfc = g_new0(VigsSWSurface, 1);
+    sw_sfc->base.update = &vigs_sw_surface_update;
+    sw_sfc->base.set_data = &vigs_sw_surface_set_data;
+    sw_sfc->base.read_pixels = &vigs_sw_surface_read_pixels;
+    sw_sfc->base.copy = &vigs_sw_surface_copy;
+    sw_sfc->base.solid_fill = &vigs_sw_surface_solid_fill;
+    sw_sfc->base.put_image = &vigs_sw_surface_put_image;
+    sw_sfc->base.destroy = &vigs_sw_surface_destroy;
+    ws_sfc = vigs_winsys_sw_surface_create(width, height);
+    vigs_surface_init(&sw_sfc->base,
+                      &ws_sfc->base,
+                      backend,
+                      vigs_id_gen(),
+                      stride,
+                      format,
+                      vram_offset,
+                      data);
+
+    if (vram_offset < 0) {
+        sw_sfc->data = g_malloc(height * stride);
+    } else {
+        sw_sfc->data = sw_sfc->base.data;
+    }
+
+    assert(sw_sfc->data);
+    ws_sfc->base.release(&ws_sfc->base);
+
+    VIGS_LOG_TRACE("surface %d created: %dx%d stride=%d, format=%d, offset=%d",
+        sw_sfc->base.id, width, height, stride, format, vram_offset);
+
+    return &sw_sfc->base;
+}
+
+static void vigs_sw_backend_destroy(struct vigs_backend *sw_backend)
+{
+    vigs_backend_cleanup(sw_backend);
+    g_free(sw_backend);
+    VIGS_LOG_DEBUG("VIGS software backend destroyed");
+}
+
+struct vigs_backend *vigs_sw_backend_create(void)
+{
+    struct vigs_backend *sw_backend;
+
+    sw_backend = g_new0(struct vigs_backend, 1);
+    vigs_backend_init(sw_backend, NULL);
+    sw_backend->destroy = &vigs_sw_backend_destroy;
+    sw_backend->create_surface = &vigs_sw_backend_create_surface;
+    VIGS_LOG_DEBUG("VIGS software backend created");
+
+    return sw_backend;
+}
diff --git a/vl.c b/vl.c
index 6f42742..371bf8f 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -203,7 +203,7 @@ extern int enable_gl;
 extern int enable_yagl;
 const char *yagl_backend = NULL;
 int enable_vigs = 0;
-const char *vigs_backend = NULL;
+char *vigs_backend = NULL;
 #endif
 
 static const char *data_dir;
@@ -3157,7 +3157,7 @@ int main(int argc, char **argv, char **envp)
                 break;
            case QEMU_OPTION_vigs_backend:
 #if defined(CONFIG_VIGS) && !defined(CONFIG_DARWIN)
-                vigs_backend = optarg;
+                vigs_backend = g_strdup(optarg);
 #else
                 fprintf(stderr, "VIGS support is disabled,"
                     " ignoring -vigs-backend\n");
@@ -3465,10 +3465,10 @@ int main(int argc, char **argv, char **envp)
 
     if (enable_vigs) {
         if (!vigs_backend) {
-            vigs_backend = "gl";
+            vigs_backend = g_strdup("gl");
         }
 
-        if (strcmp(vigs_backend, "gl") != 0) {
+        if (strcmp(vigs_backend, "gl") != 0 && strcmp(vigs_backend, "sw") != 0) {
             fprintf (stderr, "Error: Bad VIGS backend - %s!\n", vigs_backend);
             exit(1);
         }