X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=ui%2Fspice-display.c;h=1860492ce992d04f458ecce8e21f66d6cbf7953b;hb=b5b5a72b01ac12c4dfb5867deb00c7b39f4fece5;hp=e293ec20fe8297d12f1a996a901d015f0afd37bd;hpb=9425c004fe287bfe95e2bf64634d6a618c2b596c;p=sdk%2Femulator%2Fqemu.git diff --git a/ui/spice-display.c b/ui/spice-display.c index e293ec2..1860492 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -15,17 +15,21 @@ * along with this program; if not, see . */ +#include "qemu/osdep.h" #include "qemu-common.h" #include "ui/qemu-spice.h" #include "qemu/timer.h" #include "qemu/queue.h" -#include "monitor/monitor.h" #include "ui/console.h" #include "sysemu/sysemu.h" #include "trace.h" #include "ui/spice-display.h" +#ifdef CONFIG_MARU +#define RATIO_SCALE 2 +#endif + static int debug = 0; static void GCC_FMT_ATTR(2, 3) dprint(int level, const char *fmt, ...) @@ -196,17 +200,26 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) { +#ifndef CONFIG_MARU static const int blksize = 32; int blocks = (surface_width(ssd->ds) + blksize - 1) / blksize; int dirty_top[blocks]; - int y, yoff, x, xoff, blk, bw; + int y, yoff1, yoff2, x, xoff, blk, bw; int bpp = surface_bytes_per_pixel(ssd->ds); uint8_t *guest, *mirror; +#endif if (qemu_spice_rect_is_empty(&ssd->dirty)) { return; }; + if (ssd->surface == NULL) { + ssd->surface = pixman_image_ref(ssd->ds->image); + ssd->mirror = qemu_pixman_mirror_create(ssd->ds->format, + ssd->ds->image); + } + +#ifndef CONFIG_MARU for (blk = 0; blk < blocks; blk++) { dirty_top[blk] = -1; } @@ -214,13 +227,14 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) guest = surface_data(ssd->ds); mirror = (void *)pixman_image_get_data(ssd->mirror); for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) { - yoff = y * surface_stride(ssd->ds); + yoff1 = y * surface_stride(ssd->ds); + yoff2 = y * pixman_image_get_stride(ssd->mirror); for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { xoff = x * bpp; blk = x / blksize; bw = MIN(blksize, ssd->dirty.right - x); - if (memcmp(guest + yoff + xoff, - mirror + yoff + xoff, + if (memcmp(guest + yoff1 + xoff, + mirror + yoff2 + xoff, bw * bpp) == 0) { if (dirty_top[blk] != -1) { QXLRect update = { @@ -254,6 +268,27 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) dirty_top[blk] = -1; } } +#endif + +#ifdef CONFIG_MARU + pixman_transform_t matrix; + struct pixman_f_transform matrix_f; + + pixman_f_transform_init_identity(&matrix_f); + pixman_f_transform_scale(&matrix_f, NULL, RATIO_SCALE, RATIO_SCALE); + pixman_transform_from_pixman_f_transform(&matrix, &matrix_f); + pixman_image_set_transform(ssd->ds->image, &matrix); + pixman_image_set_filter(ssd->ds->image, PIXMAN_FILTER_BEST, NULL, 0); + + QXLRect update = { + .top = 0, + .bottom = surface_height(ssd->ds), + .left = 0, + .right = surface_width(ssd->ds), + }; + + qemu_spice_create_one_update(ssd, &update); +#endif memset(&ssd->dirty, 0, sizeof(ssd->dirty)); } @@ -359,6 +394,11 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) surface.mem = (uintptr_t)ssd->buf; surface.group_id = MEMSLOT_GROUP_HOST; +#ifdef CONFIG_MARU + surface.width /= RATIO_SCALE; + surface.height /= RATIO_SCALE; +#endif + qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC); } @@ -408,7 +448,8 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, if (surface && ssd->surface && surface_width(surface) == pixman_image_get_width(ssd->surface) && - surface_height(surface) == pixman_image_get_height(ssd->surface)) { + surface_height(surface) == pixman_image_get_height(ssd->surface) && + surface_format(surface) == pixman_image_get_format(ssd->surface)) { /* no-resize fast path: just swap backing store */ dprint(1, "%s/%d: fast (%dx%d)\n", __func__, ssd->qxl.id, surface_width(surface), surface_height(surface)); @@ -458,6 +499,13 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, memset(&ssd->dirty, 0, sizeof(ssd->dirty)); ssd->notify++; + + qemu_mutex_lock(&ssd->lock); + if (ssd->cursor) { + g_free(ssd->ptr_define); + ssd->ptr_define = qemu_spice_create_cursor_update(ssd, ssd->cursor, 0); + } + qemu_mutex_unlock(&ssd->lock); } static void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) @@ -465,8 +513,6 @@ static void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) if (ssd->cursor) { assert(ssd->dcl.con); dpy_cursor_define(ssd->dcl.con, ssd->cursor); - cursor_put(ssd->cursor); - ssd->cursor = NULL; } if (ssd->mouse_x != -1 && ssd->mouse_y != -1) { assert(ssd->dcl.con); @@ -539,7 +585,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) info->n_surfaces = ssd->num_surfaces; } -static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) +static int interface_get_command(QXLInstance *sin, QXLCommandExt *ext) { SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); SimpleSpiceUpdate *update; @@ -561,12 +607,12 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) static int interface_req_cmd_notification(QXLInstance *sin) { - dprint(1, "%s/%d:\n", __func__, sin->id); + dprint(2, "%s/%d:\n", __func__, sin->id); return 1; } static void interface_release_resource(QXLInstance *sin, - struct QXLReleaseInfoExt rext) + QXLReleaseInfoExt rext) { SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); SimpleSpiceUpdate *update; @@ -589,7 +635,7 @@ static void interface_release_resource(QXLInstance *sin, } } -static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext) +static int interface_get_cursor_command(QXLInstance *sin, QXLCommandExt *ext) { SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); int ret; @@ -614,7 +660,7 @@ static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt * static int interface_req_cursor_notification(QXLInstance *sin) { - dprint(1, "%s:\n", __FUNCTION__); + dprint(2, "%s:\n", __func__); return 1; } @@ -643,9 +689,23 @@ static void interface_update_area_complete(QXLInstance *sin, /* called from spice server thread context only */ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) { - /* should never be called, used in qxl native mode only */ - fprintf(stderr, "%s: abort()\n", __func__); - abort(); + QXLCookie *cookie = (QXLCookie *)(uintptr_t)cookie_token; + + switch (cookie->type) { +#ifdef HAVE_SPICE_GL + case QXL_COOKIE_TYPE_GL_DRAW_DONE: + { + SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); + qemu_bh_schedule(ssd->gl_unblock_bh); + break; + } +#endif + default: + /* should never be called, used in qxl native mode only */ + fprintf(stderr, "%s: abort()\n", __func__); + abort(); + } + g_free(cookie); } static void interface_set_client_capabilities(QXLInstance *sin, @@ -660,7 +720,10 @@ static int interface_client_monitors_config(QXLInstance *sin, { SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); QemuUIInfo info; - int rc; + + if (!dpy_ui_info_supported(ssd->dcl.con)) { + return 0; /* == not supported by guest */ + } if (!mc) { return 1; @@ -675,14 +738,10 @@ static int interface_client_monitors_config(QXLInstance *sin, info.width = mc->monitors[0].width; info.height = mc->monitors[0].height; } - rc = dpy_set_ui_info(ssd->dcl.con, &info); - dprint(1, "%s/%d: size %dx%d, rc %d <--- ==========================\n", - __func__, ssd->qxl.id, info.width, info.height, rc); - if (rc != 0) { - return 0; /* == not supported by guest */ - } else { - return 1; - } + dpy_set_ui_info(ssd->dcl.con, &info); + dprint(1, "%s/%d: size %dx%d\n", __func__, ssd->qxl.id, + info.width, info.height); + return 1; } static const QXLInterface dpy_interface = { @@ -738,9 +797,7 @@ static void display_mouse_set(DisplayChangeListener *dcl, qemu_mutex_lock(&ssd->lock); ssd->ptr_x = x; ssd->ptr_y = y; - if (ssd->ptr_move) { - g_free(ssd->ptr_move); - } + g_free(ssd->ptr_move); ssd->ptr_move = qemu_spice_create_cursor_update(ssd, NULL, on); qemu_mutex_unlock(&ssd->lock); } @@ -751,15 +808,16 @@ static void display_mouse_define(DisplayChangeListener *dcl, SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); qemu_mutex_lock(&ssd->lock); + if (c) { + cursor_get(c); + } + cursor_put(ssd->cursor); + ssd->cursor = c; ssd->hot_x = c->hot_x; ssd->hot_y = c->hot_y; - if (ssd->ptr_move) { - g_free(ssd->ptr_move); - ssd->ptr_move = NULL; - } - if (ssd->ptr_define) { - g_free(ssd->ptr_define); - } + g_free(ssd->ptr_move); + ssd->ptr_move = NULL; + g_free(ssd->ptr_define); ssd->ptr_define = qemu_spice_create_cursor_update(ssd, c, 0); qemu_mutex_unlock(&ssd->lock); } @@ -774,20 +832,128 @@ static const DisplayChangeListenerOps display_listener_ops = { .dpy_cursor_define = display_mouse_define, }; +#ifdef HAVE_SPICE_GL + +static void qemu_spice_gl_block(SimpleSpiceDisplay *ssd, bool block) +{ + uint64_t timeout; + + if (block) { + timeout = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + timeout += 1000; /* one sec */ + timer_mod(ssd->gl_unblock_timer, timeout); + } else { + timer_del(ssd->gl_unblock_timer); + } + graphic_hw_gl_block(ssd->dcl.con, block); +} + +static void qemu_spice_gl_unblock_bh(void *opaque) +{ + SimpleSpiceDisplay *ssd = opaque; + + qemu_spice_gl_block(ssd, false); +} + +static void qemu_spice_gl_block_timer(void *opaque) +{ + fprintf(stderr, "WARNING: spice: no gl-draw-done within one second\n"); +} + +static QEMUGLContext qemu_spice_gl_create_context(DisplayChangeListener *dcl, + QEMUGLParams *params) +{ + eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, + qemu_egl_rn_ctx); + return qemu_egl_create_context(dcl, params); +} + +static void qemu_spice_gl_scanout(DisplayChangeListener *dcl, + uint32_t tex_id, + bool y_0_top, + uint32_t x, uint32_t y, + uint32_t w, uint32_t h) +{ + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + EGLint stride = 0, fourcc = 0; + int fd = -1; + + if (tex_id) { + fd = egl_get_fd_for_texture(tex_id, &stride, &fourcc); + if (fd < 0) { + fprintf(stderr, "%s: failed to get fd for texture\n", __func__); + return; + } + dprint(1, "%s: %dx%d (stride %d, fourcc 0x%x)\n", __func__, + w, h, stride, fourcc); + } else { + dprint(1, "%s: no texture (no framebuffer)\n", __func__); + } + + assert(!tex_id || fd >= 0); + + /* note: spice server will close the fd */ + spice_qxl_gl_scanout(&ssd->qxl, fd, + surface_width(ssd->ds), + surface_height(ssd->ds), + stride, fourcc, y_0_top); +} + +static void qemu_spice_gl_update(DisplayChangeListener *dcl, + uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + uint64_t cookie; + + dprint(2, "%s: %dx%d+%d+%d\n", __func__, w, h, x, y); + qemu_spice_gl_block(ssd, true); + cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0); + spice_qxl_gl_draw_async(&ssd->qxl, x, y, w, h, cookie); +} + +static const DisplayChangeListenerOps display_listener_gl_ops = { + .dpy_name = "spice-egl", + .dpy_gfx_update = display_update, + .dpy_gfx_switch = display_switch, + .dpy_gfx_check_format = qemu_pixman_check_format, + .dpy_refresh = display_refresh, + .dpy_mouse_set = display_mouse_set, + .dpy_cursor_define = display_mouse_define, + + .dpy_gl_ctx_create = qemu_spice_gl_create_context, + .dpy_gl_ctx_destroy = qemu_egl_destroy_context, + .dpy_gl_ctx_make_current = qemu_egl_make_context_current, + .dpy_gl_ctx_get_current = qemu_egl_get_current_context, + + .dpy_gl_scanout = qemu_spice_gl_scanout, + .dpy_gl_update = qemu_spice_gl_update, +}; + +#endif /* HAVE_SPICE_GL */ + static void qemu_spice_display_init_one(QemuConsole *con) { SimpleSpiceDisplay *ssd = g_new0(SimpleSpiceDisplay, 1); qemu_spice_display_init_common(ssd); + ssd->dcl.ops = &display_listener_ops; +#ifdef HAVE_SPICE_GL + if (display_opengl) { + ssd->dcl.ops = &display_listener_gl_ops; + ssd->dmabuf_fd = -1; + ssd->gl_unblock_bh = qemu_bh_new(qemu_spice_gl_unblock_bh, ssd); + ssd->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME, + qemu_spice_gl_block_timer, ssd); + } +#endif + ssd->dcl.con = con; + ssd->qxl.base.sif = &dpy_interface.base; qemu_spice_add_display_interface(&ssd->qxl, con); assert(ssd->worker); - qemu_spice_create_host_memslot(ssd); - ssd->dcl.ops = &display_listener_ops; - ssd->dcl.con = con; register_displaychangelistener(&ssd->dcl); }