VIGS: Implemented plane support 55/16655/1
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Mon, 10 Feb 2014 16:50:35 +0000 (20:50 +0400)
committerStanislav Vorobiov <s.vorobiov@samsung.com>
Thu, 20 Feb 2014 08:45:55 +0000 (12:45 +0400)
We now support up to 2 hardware planes
with z-ordering and scaling. This patch also
adds surface scanout flag support. Surface scanout
flag is used as a hint that helps the host to decide
how to process the surface - either upload it to texture
or continously scanout data out of surface's VRAM

Change-Id: Ia5ac6014cfd0b49f80c4593763ee86966cf23c2a

hw/vigs/vigs_backend.h
hw/vigs/vigs_comm.c
hw/vigs/vigs_comm.h
hw/vigs/vigs_gl_backend.c
hw/vigs/vigs_plane.h [new file with mode: 0644]
hw/vigs/vigs_protocol.h
hw/vigs/vigs_server.c
hw/vigs/vigs_server.h
hw/vigs/vigs_surface.c
hw/vigs/vigs_surface.h
hw/vigs/vigs_sw_backend.c

index c918c7d..126cc5d 100644 (file)
 
 struct winsys_info;
 struct vigs_surface;
+struct vigs_plane;
 
-typedef void (*vigs_read_pixels_cb)(void */*user_data*/,
-                                    uint8_t */*pixels*/,
-                                    uint32_t /*width*/,
-                                    uint32_t /*height*/,
-                                    uint32_t /*stride*/,
-                                    vigsp_surface_format /*format*/);
+typedef uint8_t *(*vigs_composite_start_cb)(void */*user_data*/,
+                                            uint32_t /*width*/,
+                                            uint32_t /*height*/,
+                                            uint32_t /*stride*/,
+                                            vigsp_surface_format /*format*/);
+
+typedef void (*vigs_composite_end_cb)(void */*user_data*/,
+                                      bool /*was_started*/);
 
 struct vigs_backend
 {
@@ -55,10 +58,11 @@ struct vigs_backend
                                            vigsp_surface_format /*format*/,
                                            vigsp_surface_id /*id*/);
 
-    void (*read_pixels)(struct vigs_surface */*surface*/,
-                        uint8_t */*pixels*/,
-                        vigs_read_pixels_cb /*cb*/,
-                        void */*user_data*/);
+    void (*composite)(struct vigs_surface */*surface*/,
+                      const struct vigs_plane */*planes*/,
+                      vigs_composite_start_cb /*start_cb*/,
+                      vigs_composite_end_cb /*end_cb*/,
+                      void */*user_data*/);
 
     void (*batch_end)(struct vigs_backend */*backend*/);
 
index 54577fe..6e08517 100644 (file)
@@ -74,12 +74,14 @@ static void vigs_comm_dispatch_set_root_surface(struct vigs_comm_ops *ops,
                                                 struct vigsp_cmd_set_root_surface_request *request,
                                                 vigsp_fence_seq fence_seq)
 {
-    VIGS_LOG_TRACE("id = %u, offset = %u",
+    VIGS_LOG_TRACE("id = %u, scanout = %d, offset = %u",
                    request->id,
+                   request->scanout,
                    request->offset);
 
     ops->set_root_surface(user_data,
                           request->id,
+                          request->scanout,
                           request->offset,
                           fence_seq);
 }
@@ -189,6 +191,28 @@ static void vigs_comm_dispatch_solid_fill(struct vigs_comm_batch_ops *ops,
                     request->num_entries);
 }
 
+static void vigs_comm_dispatch_set_plane(struct vigs_comm_batch_ops *ops,
+                                         void *user_data,
+                                         struct vigsp_cmd_set_plane_request *request)
+{
+    VIGS_LOG_TRACE("plane = %u, sfc_id = %u, src_rect = {%u, %u, %u, %u}, dst_x = %d, dst_y = %d, dst_size = {%u, %u}, z_pos = %d",
+                   request->plane,
+                   request->sfc_id,
+                   request->src_rect.pos.x,
+                   request->src_rect.pos.y,
+                   request->src_rect.size.w,
+                   request->src_rect.size.h,
+                   request->dst_x,
+                   request->dst_y,
+                   request->dst_size.w,
+                   request->dst_size.h,
+                   request->z_pos);
+
+    ops->set_plane(user_data, request->plane, request->sfc_id,
+                   &request->src_rect, request->dst_x, request->dst_y,
+                   &request->dst_size, request->z_pos);
+}
+
 /*
  * @}
  */
@@ -210,11 +234,13 @@ static const vigs_dispatch_func vigs_dispatch_table[] =
     VIGS_DISPATCH_ENTRY(vigsp_cmd_copy,
                         vigs_comm_dispatch_copy),
     VIGS_DISPATCH_ENTRY(vigsp_cmd_solid_fill,
-                        vigs_comm_dispatch_solid_fill)
+                        vigs_comm_dispatch_solid_fill),
+    VIGS_DISPATCH_ENTRY(vigsp_cmd_set_plane,
+                        vigs_comm_dispatch_set_plane)
 };
 
 #define VIGS_MIN_BATCH_CMD_ID vigsp_cmd_create_surface
-#define VIGS_MAX_BATCH_CMD_ID vigsp_cmd_solid_fill
+#define VIGS_MAX_BATCH_CMD_ID vigsp_cmd_set_plane
 
 struct vigs_comm *vigs_comm_create(uint8_t *ram_ptr)
 {
index 40514e7..b07c71b 100644 (file)
@@ -42,6 +42,7 @@ struct vigs_comm_ops
 
     void (*set_root_surface)(void */*user_data*/,
                              vigsp_surface_id /*id*/,
+                             bool /*scanout*/,
                              vigsp_offset /*offset*/,
                              vigsp_fence_seq /*fence_seq*/);
 
@@ -86,6 +87,15 @@ struct vigs_comm_batch_ops
                        const struct vigsp_rect */*entries*/,
                        uint32_t /*num_entries*/);
 
+    void (*set_plane)(void */*user_data*/,
+                      vigsp_u32 /*plane*/,
+                      vigsp_surface_id /*sfc_id*/,
+                      const struct vigsp_rect */*src_rect*/,
+                      int /*dst_x*/,
+                      int /*dst_y*/,
+                      const struct vigsp_size */*dst_size*/,
+                      int /*z_pos*/);
+
     void (*end)(void */*user_data*/, vigsp_fence_seq /*fence_seq*/);
 };
 
index 2cf7a94..1824bf2 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "vigs_gl_backend.h"
 #include "vigs_surface.h"
+#include "vigs_plane.h"
 #include "vigs_log.h"
 #include "vigs_utils.h"
 #include "vigs_ref.h"
@@ -43,9 +44,9 @@ struct vigs_gl_backend_read_pixels_work_item
 
     struct vigs_gl_backend *backend;
 
-    vigs_read_pixels_cb cb;
+    vigs_composite_start_cb start_cb;
+    vigs_composite_end_cb end_cb;
     void *user_data;
-    uint8_t *pixels;
     uint32_t width;
     uint32_t height;
     uint32_t stride;
@@ -886,18 +887,23 @@ static void vigs_gl_backend_read_pixels_work(struct work_queue_item *wq_item)
 {
     struct vigs_gl_backend_read_pixels_work_item *item = (struct vigs_gl_backend_read_pixels_work_item*)wq_item;
     struct vigs_gl_backend *backend = item->backend;
+    uint8_t *dst = NULL;
 
     VIGS_LOG_TRACE("enter");
 
     if (backend->read_pixels_make_current(backend, true)) {
-        uint8_t *pixels;
+        uint8_t *src;
 
         backend->BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, backend->pbo);
 
-        pixels = backend->MapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
+        src = backend->MapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
 
-        if (pixels) {
-            memcpy(item->pixels, pixels, item->stride * item->height);
+        if (src) {
+            dst = item->start_cb(item->user_data,
+                                 item->width, item->height,
+                                 item->stride, item->format);
+
+            memcpy(dst, src, item->stride * item->height);
 
             if (!backend->UnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB)) {
                 VIGS_LOG_CRITICAL("glUnmapBuffer failed");
@@ -911,24 +917,209 @@ static void vigs_gl_backend_read_pixels_work(struct work_queue_item *wq_item)
         backend->read_pixels_make_current(backend, false);
     }
 
-    item->cb(item->user_data,
-             item->pixels, item->width, item->height,
-             item->stride, item->format);
+    item->end_cb(item->user_data, (dst != NULL));
 
     g_free(item);
 }
 
-static void vigs_gl_backend_read_pixels(struct vigs_surface *surface,
-                                        uint8_t *pixels,
-                                        vigs_read_pixels_cb cb,
-                                        void *user_data)
+static void vigs_gl_backend_composite(struct vigs_surface *surface,
+                                      const struct vigs_plane *planes,
+                                      vigs_composite_start_cb start_cb,
+                                      vigs_composite_end_cb end_cb,
+                                      void *user_data)
 {
     struct vigs_gl_backend *gl_backend = (struct vigs_gl_backend*)surface->backend;
+    struct vigs_gl_surface *gl_root_sfc = (struct vigs_gl_surface*)surface;
+    struct vigs_winsys_gl_surface *ws_root_sfc = get_ws_sfc(gl_root_sfc);
+    uint32_t i;
+    GLfloat *vert_coords;
+    GLfloat *tex_coords;
+    const struct vigs_plane *sorted_planes[VIGS_MAX_PLANES];
     uint32_t size = surface->stride * surface->ws_sfc->height;
     struct vigs_gl_backend_read_pixels_work_item *item;
 
     VIGS_LOG_TRACE("enter");
 
+    if (!surface->ptr) {
+        if (!ws_root_sfc->tex) {
+            VIGS_LOG_WARN("compositing garbage (root surface) ???");
+        }
+
+        if (!vigs_winsys_gl_surface_create_texture(ws_root_sfc, &ws_root_sfc->tex)) {
+            goto out;
+        }
+    }
+
+    if (!vigs_winsys_gl_surface_create_texture(ws_root_sfc, &gl_root_sfc->tmp_tex)) {
+        goto out;
+    }
+
+    for (i = 0; i < VIGS_MAX_PLANES; ++i) {
+        struct vigs_gl_surface *gl_sfc;
+        struct vigs_winsys_gl_surface *ws_sfc;
+
+        if (!planes[i].sfc) {
+            continue;
+        }
+
+        gl_sfc = (struct vigs_gl_surface*)planes[i].sfc;
+        ws_sfc = get_ws_sfc(gl_sfc);
+
+        if (!ws_sfc->tex) {
+            VIGS_LOG_WARN("compositing garbage (plane %u) ???", i);
+        }
+
+        if (!vigs_winsys_gl_surface_create_texture(ws_sfc, &ws_sfc->tex)) {
+            goto out;
+        }
+    }
+
+    if (!vigs_gl_surface_create_framebuffer(gl_root_sfc)) {
+        goto out;
+    }
+
+    vigs_vector_resize(&gl_backend->v1, 0);
+    vigs_vector_resize(&gl_backend->v2, 0);
+
+    vert_coords = vigs_vector_append(&gl_backend->v1,
+                                     (8 * sizeof(GLfloat)));
+    tex_coords = vigs_vector_append(&gl_backend->v2,
+                                    (8 * sizeof(GLfloat)));
+
+    if (surface->ptr) {
+        /*
+         * Root surface is scanout, upload it to texture.
+         * Slow path.
+         */
+
+        gl_backend->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+        gl_backend->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+        gl_backend->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+        gl_backend->PixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+
+        gl_backend->BindTexture(GL_TEXTURE_2D, gl_root_sfc->tmp_tex);
+
+        gl_backend->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
+                                  ws_root_sfc->base.base.width,
+                                  ws_root_sfc->base.base.height,
+                                  ws_root_sfc->tex_format,
+                                  ws_root_sfc->tex_type,
+                                  surface->ptr);
+    }
+
+    gl_backend->BindFramebuffer(GL_FRAMEBUFFER, gl_root_sfc->fb);
+
+    vigs_gl_surface_setup_framebuffer(gl_root_sfc);
+
+    gl_backend->Enable(GL_TEXTURE_2D);
+
+    gl_backend->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                     GL_TEXTURE_2D, gl_root_sfc->tmp_tex, 0);
+
+    gl_backend->EnableClientState(GL_VERTEX_ARRAY);
+    gl_backend->EnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+    gl_backend->Color4f(1.0f, 1.0f, 1.0f, 1.0f);
+
+    if (!surface->ptr) {
+        /*
+         * If root surface is not scanout then we must render
+         * it.
+         */
+
+        vert_coords[0] = 0;
+        vert_coords[1] = ws_root_sfc->base.base.height;
+        vert_coords[2] = ws_root_sfc->base.base.width;
+        vert_coords[3] = ws_root_sfc->base.base.height;
+        vert_coords[4] = ws_root_sfc->base.base.width;
+        vert_coords[5] = 0;
+        vert_coords[6] = 0;
+        vert_coords[7] = 0;
+
+        tex_coords[0] = 0;
+        tex_coords[1] = 0;
+        tex_coords[2] = 1;
+        tex_coords[3] = 0;
+        tex_coords[4] = 1;
+        tex_coords[5] = 1;
+        tex_coords[6] = 0;
+        tex_coords[7] = 1;
+
+        gl_backend->BindTexture(GL_TEXTURE_2D, ws_root_sfc->tex);
+
+        gl_backend->VertexPointer(2, GL_FLOAT, 0, vert_coords);
+        gl_backend->TexCoordPointer(2, GL_FLOAT, 0, tex_coords);
+
+        gl_backend->DrawArrays(GL_QUADS, 0, 4);
+    }
+
+    /*
+     * Sort planes, only 2 of them now, don't bother...
+     */
+
+    assert(VIGS_MAX_PLANES == 2);
+
+    if (planes[0].z_pos <= planes[1].z_pos) {
+        sorted_planes[0] = &planes[0];
+        sorted_planes[1] = &planes[1];
+    } else {
+        sorted_planes[0] = &planes[1];
+        sorted_planes[1] = &planes[0];
+    }
+
+    /*
+     * Now render planes, respect z-order.
+     */
+
+    for (i = 0; i < VIGS_MAX_PLANES; ++i) {
+        const struct vigs_plane *plane = sorted_planes[i];
+        struct vigs_gl_surface *gl_sfc;
+        struct vigs_winsys_gl_surface *ws_sfc;
+        GLfloat src_w, src_h;
+
+        if (!plane->sfc) {
+            continue;
+        }
+
+        gl_sfc = (struct vigs_gl_surface*)plane->sfc;
+        ws_sfc = get_ws_sfc(gl_sfc);
+
+        src_w = ws_sfc->base.base.width;
+        src_h = ws_sfc->base.base.height;
+
+        vert_coords[0] = plane->dst_x;
+        vert_coords[1] = plane->dst_y;
+        vert_coords[2] = plane->dst_x + (int)plane->dst_size.w;
+        vert_coords[3] = plane->dst_y;
+        vert_coords[4] = plane->dst_x + (int)plane->dst_size.w;
+        vert_coords[5] = plane->dst_y + (int)plane->dst_size.h;
+        vert_coords[6] = plane->dst_x;
+        vert_coords[7] = plane->dst_y + (int)plane->dst_size.h;
+
+        tex_coords[0] = (GLfloat)plane->src_rect.pos.x / src_w;
+        tex_coords[1] = (GLfloat)(src_h - plane->src_rect.pos.y) / src_h;
+        tex_coords[2] = (GLfloat)(plane->src_rect.pos.x + plane->src_rect.size.w) / src_w;
+        tex_coords[3] = (GLfloat)(src_h - plane->src_rect.pos.y) / src_h;
+        tex_coords[4] = (GLfloat)(plane->src_rect.pos.x + plane->src_rect.size.w) / src_w;
+        tex_coords[5] = (GLfloat)(src_h - (plane->src_rect.pos.y + plane->src_rect.size.h)) / src_h;
+        tex_coords[6] = (GLfloat)plane->src_rect.pos.x / src_w;
+        tex_coords[7] = (GLfloat)(src_h - (plane->src_rect.pos.y + plane->src_rect.size.h)) / src_h;
+
+        gl_backend->BindTexture(GL_TEXTURE_2D, ws_sfc->tex);
+
+        gl_backend->VertexPointer(2, GL_FLOAT, 0, vert_coords);
+        gl_backend->TexCoordPointer(2, GL_FLOAT, 0, tex_coords);
+
+        gl_backend->DrawArrays(GL_QUADS, 0, 4);
+    }
+
+    gl_backend->DisableClientState(GL_TEXTURE_COORD_ARRAY);
+    gl_backend->DisableClientState(GL_VERTEX_ARRAY);
+
+    /*
+     * Now schedule asynchronous glReadPixels.
+     */
+
     gl_backend->BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, gl_backend->pbo);
 
     if (size > gl_backend->pbo_size) {
@@ -939,7 +1130,11 @@ static void vigs_gl_backend_read_pixels(struct vigs_surface *surface,
                                GL_STREAM_READ);
     }
 
-    surface->read_pixels(surface, NULL);
+    gl_backend->PixelStorei(GL_PACK_ALIGNMENT, 1);
+    gl_backend->ReadPixels(0, 0,
+                           surface->ws_sfc->width, surface->ws_sfc->height,
+                           ws_root_sfc->tex_format, ws_root_sfc->tex_type,
+                           NULL);
 
     gl_backend->BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
 
@@ -958,15 +1153,18 @@ static void vigs_gl_backend_read_pixels(struct vigs_surface *surface,
 
     item->backend = gl_backend;
 
-    item->cb = cb;
+    item->start_cb = start_cb;
+    item->end_cb = end_cb;
     item->user_data = user_data;
-    item->pixels = pixels;
     item->width = surface->ws_sfc->width;
     item->height = surface->ws_sfc->height;
     item->stride = surface->stride;
     item->format = surface->format;
 
     work_queue_add_item(gl_backend->read_pixels_queue, &item->base);
+
+out:
+    gl_backend->BindFramebuffer(GL_FRAMEBUFFER, 0);
 }
 
 static void vigs_gl_backend_batch_end(struct vigs_backend *backend)
@@ -1011,7 +1209,7 @@ bool vigs_gl_backend_init(struct vigs_gl_backend *gl_backend)
 
     gl_backend->base.batch_start = &vigs_gl_backend_batch_start;
     gl_backend->base.create_surface = &vigs_gl_backend_create_surface;
-    gl_backend->base.read_pixels = &vigs_gl_backend_read_pixels;
+    gl_backend->base.composite = &vigs_gl_backend_composite;
     gl_backend->base.batch_end = &vigs_gl_backend_batch_end;
 
     gl_backend->make_current(gl_backend, false);
diff --git a/hw/vigs/vigs_plane.h b/hw/vigs/vigs_plane.h
new file mode 100644 (file)
index 0000000..de53671
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * vigs
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * Stanislav Vorobiov <s.vorobiov@samsung.com>
+ * Jinhyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef _QEMU_VIGS_PLANE_H
+#define _QEMU_VIGS_PLANE_H
+
+#include "vigs_types.h"
+
+struct vigs_surface;
+
+struct vigs_plane
+{
+    struct vigs_surface *sfc;
+
+    struct vigsp_rect src_rect;
+
+    int dst_x;
+    int dst_y;
+    struct vigsp_size dst_size;
+
+    int z_pos;
+
+    /*
+     * Plane moved/resized, need to recomposite.
+     */
+    bool is_dirty;
+};
+
+#endif
index ba853e4..4ab1b14 100644 (file)
@@ -37,7 +37,9 @@
 /*
  * Bump this whenever protocol changes.
  */
-#define VIGS_PROTOCOL_VERSION 15
+#define VIGS_PROTOCOL_VERSION 16
+
+#define VIGS_MAX_PLANES 2
 
 typedef signed char vigsp_s8;
 typedef signed short vigsp_s16;
@@ -78,6 +80,7 @@ typedef enum
     vigsp_cmd_update_gpu = 0x7,
     vigsp_cmd_copy = 0x8,
     vigsp_cmd_solid_fill = 0x9,
+    vigsp_cmd_set_plane = 0xA,
     /*
      * @}
      */
@@ -228,8 +231,8 @@ struct vigsp_cmd_destroy_surface_request
  * cmd_set_root_surface
  *
  * Sets surface identified by 'id' as new root surface. Root surface is the
- * one that's displayed on screen. Root surface must reside in VRAM
- * all the time, pass 'offset' in VRAM here.
+ * one that's displayed on screen. Root surface resides in VRAM
+ * all the time if 'scanout' is true.
  *
  * Pass 0 as id in order to reset the root surface.
  *
@@ -239,6 +242,7 @@ struct vigsp_cmd_destroy_surface_request
 struct vigsp_cmd_set_root_surface_request
 {
     vigsp_surface_id id;
+    vigsp_bool scanout;
     vigsp_offset offset;
 };
 
@@ -325,6 +329,31 @@ struct vigsp_cmd_solid_fill_request
  * @}
  */
 
+/*
+ * cmd_set_plane
+ *
+ * Assigns surface 'sfc_id' to plane identified by 'plane'.
+ *
+ * Pass 0 as sfc_id in order to disable the plane.
+ *
+ * @{
+ */
+
+struct vigsp_cmd_set_plane_request
+{
+    vigsp_u32 plane;
+    vigsp_surface_id sfc_id;
+    struct vigsp_rect src_rect;
+    vigsp_s32 dst_x;
+    vigsp_s32 dst_y;
+    struct vigsp_size dst_size;
+    vigsp_s32 z_pos;
+};
+
+/*
+ * @}
+ */
+
 #pragma pack()
 
 #endif
index 7438c21..a710a6c 100644 (file)
@@ -49,6 +49,7 @@ struct vigs_server_set_root_surface_work_item
     struct vigs_server *server;
 
     vigsp_surface_id id;
+    bool scanout;
     vigsp_offset offset;
 };
 
@@ -62,13 +63,25 @@ static void vigs_server_surface_destroy_func(gpointer data)
 static void vigs_server_unuse_surface(struct vigs_server *server,
                                       struct vigs_surface *sfc)
 {
+    int i;
+
     /*
      * If it was root surface then root surface is now NULL.
      */
 
     if (server->root_sfc == sfc) {
+        vigs_surface_set_scanout(server->root_sfc, NULL);
         server->root_sfc = NULL;
-        server->root_sfc_ptr = NULL;
+    }
+
+    /*
+     * If it was attached to a plane then detach it.
+     */
+    for (i = 0; i < VIGS_MAX_PLANES; ++i) {
+        if (server->planes[i].sfc == sfc) {
+            server->planes[i].sfc = NULL;
+            server->planes[i].is_dirty = true;
+        }
     }
 }
 
@@ -194,7 +207,9 @@ static void vigs_server_dispatch_update_vram(void *user_data,
     vigs_sfc->read_pixels(vigs_sfc,
                           server->vram_ptr + offset);
 
-    vigs_sfc->is_dirty = false;
+    if (vigs_sfc->ptr) {
+        vigs_sfc->is_dirty = false;
+    }
 }
 
 static void vigs_server_dispatch_update_gpu(void *user_data,
@@ -290,6 +305,46 @@ static void vigs_server_dispatch_solid_fill(void *user_data,
     sfc->is_dirty = true;
 }
 
+static void vigs_server_dispatch_set_plane(void *user_data,
+                                           vigsp_u32 plane,
+                                           vigsp_surface_id sfc_id,
+                                           const struct vigsp_rect *src_rect,
+                                           int dst_x,
+                                           int dst_y,
+                                           const struct vigsp_size *dst_size,
+                                           int z_pos)
+{
+    struct vigs_server *server = user_data;
+    struct vigs_surface *sfc = NULL;
+
+    if (!server->initialized) {
+        VIGS_LOG_ERROR("not initialized");
+        return;
+    }
+
+    if (sfc_id) {
+        sfc = g_hash_table_lookup(server->surfaces, GUINT_TO_POINTER(sfc_id));
+
+        if (!sfc) {
+            VIGS_LOG_ERROR("surface %u not found", sfc_id);
+            return;
+        }
+    }
+
+    if (plane >= VIGS_MAX_PLANES) {
+        VIGS_LOG_ERROR("bad plane %u", plane);
+        return;
+    }
+
+    server->planes[plane].sfc = sfc;
+    server->planes[plane].src_rect = *src_rect;
+    server->planes[plane].dst_x = dst_x;
+    server->planes[plane].dst_y = dst_y;
+    server->planes[plane].dst_size = *dst_size;
+    server->planes[plane].z_pos = z_pos;
+    server->planes[plane].is_dirty = true;
+}
+
 static void vigs_server_dispatch_batch_end(void *user_data,
                                            vigsp_fence_seq fence_seq)
 {
@@ -311,6 +366,7 @@ static struct vigs_comm_batch_ops vigs_server_dispatch_batch_ops =
     .update_gpu = &vigs_server_dispatch_update_gpu,
     .copy = &vigs_server_dispatch_copy,
     .solid_fill = &vigs_server_dispatch_solid_fill,
+    .set_plane = &vigs_server_dispatch_set_plane,
     .end = &vigs_server_dispatch_batch_end
 };
 
@@ -339,8 +395,10 @@ static void vigs_server_set_root_surface_work(struct work_queue_item *wq_item)
     }
 
     if (item->id == 0) {
+        if (server->root_sfc) {
+            vigs_surface_set_scanout(server->root_sfc, NULL);
+        }
         server->root_sfc = NULL;
-        server->root_sfc_ptr = NULL;
 
         VIGS_LOG_TRACE("root surface reset");
 
@@ -355,39 +413,55 @@ static void vigs_server_set_root_surface_work(struct work_queue_item *wq_item)
     }
 
     server->root_sfc = sfc;
-    server->root_sfc_ptr = server->vram_ptr + item->offset;
+
+    if (item->scanout) {
+        vigs_surface_set_scanout(server->root_sfc,
+                                 server->vram_ptr + item->offset);
+    } else {
+        vigs_surface_set_scanout(server->root_sfc, NULL);
+
+        /*
+         * We want to display it on next display update.
+         */
+        server->root_sfc->is_dirty = true;
+    }
 
 out:
     g_free(item);
 }
 
-static void vigs_server_update_display_cb(void *user_data,
-                                          uint8_t *pixels,
-                                          uint32_t width,
-                                          uint32_t height,
-                                          uint32_t stride,
-                                          vigsp_surface_format format)
+static uint8_t *vigs_server_update_display_start_cb(void *user_data,
+                                                    uint32_t width,
+                                                    uint32_t height,
+                                                    uint32_t stride,
+                                                    vigsp_surface_format format)
 {
     struct vigs_server *server = user_data;
-    uint32_t capture_fence_seq;
 
     qemu_mutex_lock(&server->capture_mutex);
 
-    if (pixels) {
-        if ((server->captured.stride != stride) ||
-            (server->captured.height != height)) {
-            g_free(server->captured.data);
-            server->captured.data = g_malloc(stride * height);
-        }
+    if ((server->captured.stride != stride) ||
+        (server->captured.height != height)) {
+        g_free(server->captured.data);
+        server->captured.data = g_malloc(stride * height);
+    }
+
+    server->captured.width = width;
+    server->captured.height = height;
+    server->captured.stride = stride;
+    server->captured.format = format;
 
-        memcpy(server->captured.data,
-               pixels,
-               stride * height);
+    return server->captured.data;
+}
 
-        server->captured.width = width;
-        server->captured.height = height;
-        server->captured.stride = stride;
-        server->captured.format = format;
+static void vigs_server_update_display_end_cb(void *user_data,
+                                              bool was_started)
+{
+    struct vigs_server *server = user_data;
+    uint32_t capture_fence_seq;
+
+    if (!was_started) {
+        qemu_mutex_lock(&server->capture_mutex);
     }
 
     server->is_capturing = false;
@@ -407,32 +481,85 @@ static void vigs_server_update_display_work(struct work_queue_item *wq_item)
     struct vigs_server_work_item *item = (struct vigs_server_work_item*)wq_item;
     struct vigs_server *server = item->server;
     struct vigs_surface *root_sfc = server->root_sfc;
+    int i;
+    bool planes_on = false;
+    bool planes_dirty = false;
 
     if (!root_sfc) {
-        vigs_server_update_display_cb(server,
-                                      NULL,
-                                      0,
-                                      0,
-                                      0,
-                                      vigsp_surface_bgrx8888);
+        /*
+         * If no root surface then this is a no-op.
+         * TODO: Can planes be enabled without a root surface ?
+         */
+        vigs_server_update_display_end_cb(server, false);
         goto out;
     }
 
-    if (root_sfc->is_dirty) {
-        root_sfc->is_dirty = false;
+    for (i = 0; i < VIGS_MAX_PLANES; ++i) {
+        /*
+         * If plane was moved/resized or turned on/off
+         * then we're dirty.
+         */
+        if (server->planes[i].is_dirty) {
+            planes_dirty = true;
+        }
+
+        if (server->planes[i].sfc) {
+            planes_on = true;
+
+            /*
+             * If plane's surface is dirty then we're dirty.
+             */
+            if (server->planes[i].sfc->is_dirty) {
+                planes_dirty = true;
+            }
+        }
+    }
+
+    if (root_sfc->ptr && !root_sfc->is_dirty && !planes_on) {
+        /*
+         * Root surface is scanout, it's not dirty and planes not on,
+         * finish immediately.
+         */
+        uint8_t *buff = vigs_server_update_display_start_cb(server,
+                                                            root_sfc->ws_sfc->width,
+                                                            root_sfc->ws_sfc->height,
+                                                            root_sfc->stride,
+                                                            root_sfc->format);
+
+        memcpy(buff,
+               root_sfc->ptr,
+               root_sfc->stride * root_sfc->ws_sfc->height);
+
+        vigs_server_update_display_end_cb(server, true);
+    } else if (root_sfc->ptr || root_sfc->is_dirty || planes_dirty) {
+        /*
+         * Composite root surface and planes.
+         */
         server->backend->batch_start(server->backend);
-        server->backend->read_pixels(root_sfc,
-                                     server->root_sfc_ptr,
-                                     &vigs_server_update_display_cb,
-                                     server);
+        server->backend->composite(root_sfc,
+                                   &server->planes[0],
+                                   &vigs_server_update_display_start_cb,
+                                   &vigs_server_update_display_end_cb,
+                                   server);
         server->backend->batch_end(server->backend);
+
+        root_sfc->is_dirty = false;
+
+        for (i = 0; i < VIGS_MAX_PLANES; ++i) {
+            if (server->planes[i].is_dirty) {
+                server->planes[i].is_dirty = false;
+            }
+
+            if (server->planes[i].sfc &&
+                server->planes[i].sfc->is_dirty) {
+                server->planes[i].sfc->is_dirty = false;
+            }
+        }
     } else {
-        vigs_server_update_display_cb(server,
-                                      server->root_sfc_ptr,
-                                      root_sfc->ws_sfc->width,
-                                      root_sfc->ws_sfc->height,
-                                      root_sfc->stride,
-                                      root_sfc->format);
+        /*
+         * No changes, no-op.
+         */
+        vigs_server_update_display_end_cb(server, false);
     }
 
 out:
@@ -493,6 +620,7 @@ static void vigs_server_dispatch_exit(void *user_data)
 
 static void vigs_server_dispatch_set_root_surface(void *user_data,
                                                   vigsp_surface_id id,
+                                                  bool scanout,
                                                   vigsp_offset offset,
                                                   vigsp_fence_seq fence_seq)
 {
@@ -506,6 +634,7 @@ static void vigs_server_dispatch_set_root_surface(void *user_data,
 
     item->server = server;
     item->id = id;
+    item->scanout = scanout;
     item->offset = offset;
 
     work_queue_add_item(server->render_queue, &item->base);
index fa56e42..9ced88d 100644 (file)
@@ -31,6 +31,7 @@
 #define _QEMU_VIGS_SERVER_H
 
 #include "vigs_types.h"
+#include "vigs_plane.h"
 #include "winsys.h"
 #include <glib.h>
 
@@ -92,7 +93,8 @@ struct vigs_server
     GHashTable *surfaces;
 
     struct vigs_surface *root_sfc;
-    uint8_t *root_sfc_ptr;
+
+    struct vigs_plane planes[VIGS_MAX_PLANES];
 
     QemuMutex capture_mutex;
 
index cc3969b..d44d724 100644 (file)
@@ -40,6 +40,7 @@ void vigs_surface_init(struct vigs_surface *sfc,
     ws_sfc->acquire(ws_sfc);
     sfc->ws_sfc = ws_sfc;
     sfc->backend = backend;
+    sfc->ptr = NULL;
     sfc->stride = stride;
     sfc->format = format;
     sfc->id = id;
@@ -49,3 +50,8 @@ void vigs_surface_cleanup(struct vigs_surface *sfc)
 {
     sfc->ws_sfc->release(sfc->ws_sfc);
 }
+
+void vigs_surface_set_scanout(struct vigs_surface *sfc, uint8_t *ptr)
+{
+    sfc->ptr = ptr;
+}
index 95daa92..9867b0f 100644 (file)
@@ -41,6 +41,11 @@ struct vigs_surface
 
     struct vigs_backend *backend;
 
+    /*
+     * Can be non-NULL only for root surface.
+     */
+    uint8_t *ptr;
+
     uint32_t stride;
     vigsp_surface_format format;
     vigsp_surface_id id;
@@ -77,4 +82,6 @@ void vigs_surface_init(struct vigs_surface *sfc,
 
 void vigs_surface_cleanup(struct vigs_surface *sfc);
 
+void vigs_surface_set_scanout(struct vigs_surface *sfc, uint8_t *ptr);
+
 #endif
index 4489e7d..53886b7 100644 (file)
@@ -310,15 +310,33 @@ static struct vigs_surface *vigs_sw_backend_create_surface(struct vigs_backend *
     return &sw_sfc->base;
 }
 
-static void vigs_sw_backend_read_pixels(struct vigs_surface *surface,
-                                        uint8_t *pixels,
-                                        vigs_read_pixels_cb cb,
-                                        void *user_data)
+static void vigs_sw_backend_composite(struct vigs_surface *surface,
+                                      const struct vigs_plane *planes,
+                                      vigs_composite_start_cb start_cb,
+                                      vigs_composite_end_cb end_cb,
+                                      void *user_data)
 {
-    surface->read_pixels(surface, pixels);
+    struct vigs_sw_surface *sw_sfc = (struct vigs_sw_surface*)surface;
+    uint8_t *buff;
+
+    /*
+     * TODO: Render planes.
+     */
+
+    buff = start_cb(user_data, surface->ws_sfc->width, surface->ws_sfc->height,
+                    surface->stride, surface->format);
+
+    if (surface->ptr) {
+        memcpy(buff,
+               surface->ptr,
+               surface->stride * surface->ws_sfc->height);
+    } else if (surface->is_dirty) {
+        memcpy(buff,
+               sw_sfc->data,
+               surface->stride * surface->ws_sfc->height);
+    }
 
-    cb(user_data, pixels, surface->ws_sfc->width, surface->ws_sfc->height,
-       surface->stride, surface->format);
+    end_cb(user_data, true);
 }
 
 static void vigs_sw_backend_batch_end(struct vigs_backend *backend)
@@ -341,7 +359,7 @@ struct vigs_backend *vigs_sw_backend_create(void)
 
     backend->batch_start = &vigs_sw_backend_batch_start;
     backend->create_surface = &vigs_sw_backend_create_surface;
-    backend->read_pixels = &vigs_sw_backend_read_pixels;
+    backend->composite = &vigs_sw_backend_composite;
     backend->batch_end = &vigs_sw_backend_batch_end;
     backend->destroy = &vigs_sw_backend_destroy;