summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorStanislav Vorobiov <s.vorobiov@samsung.com>2014-02-10 20:50:35 +0400
committerStanislav Vorobiov <s.vorobiov@samsung.com>2014-02-20 12:45:55 +0400
commit1db14cd1c3e060501dedb7040b1c4c829495e952 (patch)
tree4713478e8bb557abd2c610d43daf9125fb0c44ae /hw
parentf0cb9afbb88384291fa1e5b7f2de0cc7b3e5f8e1 (diff)
downloadqemu-1db14cd1c3e060501dedb7040b1c4c829495e952.tar.gz
qemu-1db14cd1c3e060501dedb7040b1c4c829495e952.tar.bz2
qemu-1db14cd1c3e060501dedb7040b1c4c829495e952.zip
VIGS: Implemented plane support
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
Diffstat (limited to 'hw')
-rw-r--r--hw/vigs/vigs_backend.h24
-rw-r--r--hw/vigs/vigs_comm.c32
-rw-r--r--hw/vigs/vigs_comm.h10
-rw-r--r--hw/vigs/vigs_gl_backend.c232
-rw-r--r--hw/vigs/vigs_plane.h55
-rw-r--r--hw/vigs/vigs_protocol.h35
-rw-r--r--hw/vigs/vigs_server.c213
-rw-r--r--hw/vigs/vigs_server.h4
-rw-r--r--hw/vigs/vigs_surface.c6
-rw-r--r--hw/vigs/vigs_surface.h7
-rw-r--r--hw/vigs/vigs_sw_backend.c34
11 files changed, 568 insertions, 84 deletions
diff --git a/hw/vigs/vigs_backend.h b/hw/vigs/vigs_backend.h
index c918c7dcfe..126cc5d2b3 100644
--- a/hw/vigs/vigs_backend.h
+++ b/hw/vigs/vigs_backend.h
@@ -34,13 +34,16 @@
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*/);
diff --git a/hw/vigs/vigs_comm.c b/hw/vigs/vigs_comm.c
index 54577fe3c6..6e085170b0 100644
--- a/hw/vigs/vigs_comm.c
+++ b/hw/vigs/vigs_comm.c
@@ -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)
{
diff --git a/hw/vigs/vigs_comm.h b/hw/vigs/vigs_comm.h
index 40514e760f..b07c71b717 100644
--- a/hw/vigs/vigs_comm.h
+++ b/hw/vigs/vigs_comm.h
@@ -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*/);
};
diff --git a/hw/vigs/vigs_gl_backend.c b/hw/vigs/vigs_gl_backend.c
index 2cf7a94386..1824bf248f 100644
--- a/hw/vigs/vigs_gl_backend.c
+++ b/hw/vigs/vigs_gl_backend.c
@@ -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
index 0000000000..de53671f28
--- /dev/null
+++ b/hw/vigs/vigs_plane.h
@@ -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
diff --git a/hw/vigs/vigs_protocol.h b/hw/vigs/vigs_protocol.h
index ba853e448f..4ab1b141ec 100644
--- a/hw/vigs/vigs_protocol.h
+++ b/hw/vigs/vigs_protocol.h
@@ -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
diff --git a/hw/vigs/vigs_server.c b/hw/vigs/vigs_server.c
index 7438c21cc6..a710a6ce66 100644
--- a/hw/vigs/vigs_server.c
+++ b/hw/vigs/vigs_server.c
@@ -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);
diff --git a/hw/vigs/vigs_server.h b/hw/vigs/vigs_server.h
index fa56e42374..9ced88d124 100644
--- a/hw/vigs/vigs_server.h
+++ b/hw/vigs/vigs_server.h
@@ -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;
diff --git a/hw/vigs/vigs_surface.c b/hw/vigs/vigs_surface.c
index cc3969bd1d..d44d724e82 100644
--- a/hw/vigs/vigs_surface.c
+++ b/hw/vigs/vigs_surface.c
@@ -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;
+}
diff --git a/hw/vigs/vigs_surface.h b/hw/vigs/vigs_surface.h
index 95daa927b2..9867b0f9a1 100644
--- a/hw/vigs/vigs_surface.h
+++ b/hw/vigs/vigs_surface.h
@@ -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
diff --git a/hw/vigs/vigs_sw_backend.c b/hw/vigs/vigs_sw_backend.c
index 4489e7dfc6..53886b7dc3 100644
--- a/hw/vigs/vigs_sw_backend.c
+++ b/hw/vigs/vigs_sw_backend.c
@@ -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;