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
{
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*/);
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);
}
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);
+}
+
/*
* @}
*/
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)
{
void (*set_root_surface)(void */*user_data*/,
vigsp_surface_id /*id*/,
+ bool /*scanout*/,
vigsp_offset /*offset*/,
vigsp_fence_seq /*fence_seq*/);
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*/);
};
#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"
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;
{
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");
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) {
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);
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)
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);
--- /dev/null
+/*
+ * 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
/*
* 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;
vigsp_cmd_update_gpu = 0x7,
vigsp_cmd_copy = 0x8,
vigsp_cmd_solid_fill = 0x9,
+ vigsp_cmd_set_plane = 0xA,
/*
* @}
*/
* 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.
*
struct vigsp_cmd_set_root_surface_request
{
vigsp_surface_id id;
+ vigsp_bool scanout;
vigsp_offset offset;
};
* @}
*/
+/*
+ * 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
struct vigs_server *server;
vigsp_surface_id id;
+ bool scanout;
vigsp_offset offset;
};
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;
+ }
}
}
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,
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)
{
.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
};
}
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");
}
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;
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:
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)
{
item->server = server;
item->id = id;
+ item->scanout = scanout;
item->offset = offset;
work_queue_add_item(server->render_queue, &item->base);
#define _QEMU_VIGS_SERVER_H
#include "vigs_types.h"
+#include "vigs_plane.h"
#include "winsys.h"
#include <glib.h>
GHashTable *surfaces;
struct vigs_surface *root_sfc;
- uint8_t *root_sfc_ptr;
+
+ struct vigs_plane planes[VIGS_MAX_PLANES];
QemuMutex capture_mutex;
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;
{
sfc->ws_sfc->release(sfc->ws_sfc);
}
+
+void vigs_surface_set_scanout(struct vigs_surface *sfc, uint8_t *ptr)
+{
+ sfc->ptr = ptr;
+}
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;
void vigs_surface_cleanup(struct vigs_surface *sfc);
+void vigs_surface_set_scanout(struct vigs_surface *sfc, uint8_t *ptr);
+
#endif
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)
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;