aboutsummaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
Diffstat (limited to 'ui')
-rw-r--r--ui/cocoa.m4
-rw-r--r--ui/curses.c21
-rw-r--r--ui/sdl.c140
-rw-r--r--ui/spice-core.c78
-rw-r--r--ui/spice-display.c225
-rw-r--r--ui/spice-display.h19
-rw-r--r--ui/vnc-auth-sasl.c5
-rw-r--r--ui/vnc-enc-hextile-template.h23
-rw-r--r--ui/vnc-enc-hextile.c53
-rw-r--r--ui/vnc-enc-tight.c280
-rw-r--r--ui/vnc-enc-zrle.c18
-rw-r--r--ui/vnc-jobs.c29
-rw-r--r--ui/vnc-jobs.h1
-rw-r--r--ui/vnc-palette.h1
-rw-r--r--ui/vnc-tls.c2
-rw-r--r--ui/vnc.c370
-rw-r--r--ui/vnc.h24
17 files changed, 578 insertions, 715 deletions
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 2383646..87d2e44 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -1017,8 +1017,8 @@ void cocoa_display_init(DisplayState *ds, int full_screen)
dcl = g_malloc0(sizeof(DisplayChangeListener));
// register vga output callbacks
- dcl->dpy_update = cocoa_update;
- dcl->dpy_resize = cocoa_resize;
+ dcl->dpy_gfx_update = cocoa_update;
+ dcl->dpy_gfx_resize = cocoa_resize;
dcl->dpy_refresh = cocoa_refresh;
register_displaychangelistener(ds, dcl);
diff --git a/ui/curses.c b/ui/curses.c
index c2be2c6..b40b223 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -95,17 +95,16 @@ static void curses_calc_pad(void)
}
}
-static void curses_resize(DisplayState *ds)
+static void curses_resize(DisplayState *ds, int width, int height)
{
- if (ds_get_width(ds) == gwidth && ds_get_height(ds) == gheight)
+ if (width == gwidth && height == gheight) {
return;
+ }
- gwidth = ds_get_width(ds);
- gheight = ds_get_height(ds);
+ gwidth = width;
+ gheight = height;
curses_calc_pad();
- ds->surface->width = width * FONT_WIDTH;
- ds->surface->height = height * FONT_HEIGHT;
}
#ifndef _WIN32
@@ -167,8 +166,6 @@ static void curses_refresh(DisplayState *ds)
clear();
refresh();
curses_calc_pad();
- ds->surface->width = FONT_WIDTH * width;
- ds->surface->height = FONT_HEIGHT * height;
vga_hw_invalidate();
invalidate = 0;
}
@@ -195,8 +192,6 @@ static void curses_refresh(DisplayState *ds)
refresh();
curses_calc_pad();
curses_update(ds, 0, 0, width, height);
- ds->surface->width = FONT_WIDTH * width;
- ds->surface->height = FONT_HEIGHT * height;
continue;
}
#endif
@@ -355,13 +350,11 @@ void curses_display_init(DisplayState *ds, int full_screen)
#endif
dcl = (DisplayChangeListener *) g_malloc0(sizeof(DisplayChangeListener));
- dcl->dpy_update = curses_update;
- dcl->dpy_resize = curses_resize;
+ dcl->dpy_text_update = curses_update;
+ dcl->dpy_text_resize = curses_resize;
dcl->dpy_refresh = curses_refresh;
dcl->dpy_text_cursor = curses_cursor_position;
register_displaychangelistener(ds, dcl);
- qemu_free_displaysurface(ds);
- ds->surface = qemu_create_displaysurface_from(640, 400, 0, 0, (uint8_t*) screen);
invalidate = 1;
}
diff --git a/ui/sdl.c b/ui/sdl.c
index f6f711c..37f01b2 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -55,7 +55,6 @@ static int absolute_enabled = 0;
static int guest_cursor = 0;
static int guest_x, guest_y;
static SDL_Cursor *guest_sprite = NULL;
-static uint8_t allocator;
static SDL_PixelFormat host_format;
static int scaling_active = 0;
static Notifier mouse_mode_notifier;
@@ -117,108 +116,13 @@ static void do_sdl_resize(int width, int height, int bpp)
static void sdl_resize(DisplayState *ds)
{
- if (!allocator) {
- if (!scaling_active)
- do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
- else if (real_screen->format->BitsPerPixel != ds_get_bits_per_pixel(ds))
- do_sdl_resize(real_screen->w, real_screen->h, ds_get_bits_per_pixel(ds));
- sdl_setdata(ds);
- } else {
- if (guest_screen != NULL) {
- SDL_FreeSurface(guest_screen);
- guest_screen = NULL;
- }
- }
-}
-
-static PixelFormat sdl_to_qemu_pixelformat(SDL_PixelFormat *sdl_pf)
-{
- PixelFormat qemu_pf;
-
- memset(&qemu_pf, 0x00, sizeof(PixelFormat));
-
- qemu_pf.bits_per_pixel = sdl_pf->BitsPerPixel;
- qemu_pf.bytes_per_pixel = sdl_pf->BytesPerPixel;
- qemu_pf.depth = (qemu_pf.bits_per_pixel) == 32 ? 24 : (qemu_pf.bits_per_pixel);
-
- qemu_pf.rmask = sdl_pf->Rmask;
- qemu_pf.gmask = sdl_pf->Gmask;
- qemu_pf.bmask = sdl_pf->Bmask;
- qemu_pf.amask = sdl_pf->Amask;
-
- qemu_pf.rshift = sdl_pf->Rshift;
- qemu_pf.gshift = sdl_pf->Gshift;
- qemu_pf.bshift = sdl_pf->Bshift;
- qemu_pf.ashift = sdl_pf->Ashift;
-
- qemu_pf.rbits = 8 - sdl_pf->Rloss;
- qemu_pf.gbits = 8 - sdl_pf->Gloss;
- qemu_pf.bbits = 8 - sdl_pf->Bloss;
- qemu_pf.abits = 8 - sdl_pf->Aloss;
-
- qemu_pf.rmax = ((1 << qemu_pf.rbits) - 1);
- qemu_pf.gmax = ((1 << qemu_pf.gbits) - 1);
- qemu_pf.bmax = ((1 << qemu_pf.bbits) - 1);
- qemu_pf.amax = ((1 << qemu_pf.abits) - 1);
-
- return qemu_pf;
-}
-
-static DisplaySurface* sdl_create_displaysurface(int width, int height)
-{
- DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
-
- surface->width = width;
- surface->height = height;
-
- if (scaling_active) {
- int linesize;
- PixelFormat pf;
- if (host_format.BytesPerPixel != 2 && host_format.BytesPerPixel != 4) {
- linesize = width * 4;
- pf = qemu_default_pixelformat(32);
- } else {
- linesize = width * host_format.BytesPerPixel;
- pf = sdl_to_qemu_pixelformat(&host_format);
- }
- qemu_alloc_display(surface, width, height, linesize, pf, 0);
- return surface;
+ if (!scaling_active) {
+ do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
+ } else if (real_screen->format->BitsPerPixel != ds_get_bits_per_pixel(ds)) {
+ do_sdl_resize(real_screen->w, real_screen->h,
+ ds_get_bits_per_pixel(ds));
}
-
- if (host_format.BitsPerPixel == 16)
- do_sdl_resize(width, height, 16);
- else
- do_sdl_resize(width, height, 32);
-
- surface->pf = sdl_to_qemu_pixelformat(real_screen->format);
- surface->linesize = real_screen->pitch;
- surface->data = real_screen->pixels;
-
-#ifdef HOST_WORDS_BIGENDIAN
- surface->flags = QEMU_REALPIXELS_FLAG | QEMU_BIG_ENDIAN_FLAG;
-#else
- surface->flags = QEMU_REALPIXELS_FLAG;
-#endif
- allocator = 1;
-
- return surface;
-}
-
-static void sdl_free_displaysurface(DisplaySurface *surface)
-{
- allocator = 0;
- if (surface == NULL)
- return;
-
- if (surface->flags & QEMU_ALLOCATED_FLAG)
- g_free(surface->data);
- g_free(surface);
-}
-
-static DisplaySurface* sdl_resize_displaysurface(DisplaySurface *surface, int width, int height)
-{
- sdl_free_displaysurface(surface);
- return sdl_create_displaysurface(width, height);
+ sdl_setdata(ds);
}
/* generic keyboard conversion */
@@ -553,7 +457,7 @@ static void sdl_scale(DisplayState *ds, int width, int height)
if (!is_buffer_shared(ds->surface)) {
ds->surface = qemu_resize_displaysurface(ds, ds_get_width(ds),
ds_get_height(ds));
- dpy_resize(ds);
+ dpy_gfx_resize(ds);
}
}
@@ -899,13 +803,7 @@ static void sdl_refresh(DisplayState *ds)
}
}
-static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c)
-{
- SDL_Rect dst = { x, y, w, h };
- SDL_FillRect(real_screen, &dst, c);
-}
-
-static void sdl_mouse_warp(int x, int y, int on)
+static void sdl_mouse_warp(DisplayState *ds, int x, int y, int on)
{
if (on) {
if (!guest_cursor)
@@ -921,7 +819,7 @@ static void sdl_mouse_warp(int x, int y, int on)
guest_x = x, guest_y = y;
}
-static void sdl_mouse_define(QEMUCursor *c)
+static void sdl_mouse_define(DisplayState *ds, QEMUCursor *c)
{
uint8_t *image, *mask;
int bpl;
@@ -955,7 +853,6 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
{
int flags;
uint8_t data = 0;
- DisplayAllocator *da;
const SDL_VideoInfo *vi;
char *filename;
@@ -1020,23 +917,14 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
}
dcl = g_malloc0(sizeof(DisplayChangeListener));
- dcl->dpy_update = sdl_update;
- dcl->dpy_resize = sdl_resize;
+ dcl->dpy_gfx_update = sdl_update;
+ dcl->dpy_gfx_resize = sdl_resize;
dcl->dpy_refresh = sdl_refresh;
- dcl->dpy_setdata = sdl_setdata;
- dcl->dpy_fill = sdl_fill;
- ds->mouse_set = sdl_mouse_warp;
- ds->cursor_define = sdl_mouse_define;
+ dcl->dpy_gfx_setdata = sdl_setdata;
+ dcl->dpy_mouse_set = sdl_mouse_warp;
+ dcl->dpy_cursor_define = sdl_mouse_define;
register_displaychangelistener(ds, dcl);
- da = g_malloc0(sizeof(DisplayAllocator));
- da->create_displaysurface = sdl_create_displaysurface;
- da->resize_displaysurface = sdl_resize_displaysurface;
- da->free_displaysurface = sdl_free_displaysurface;
- if (register_displayallocator(ds, da) == da) {
- dpy_resize(ds);
- }
-
mouse_mode_notifier.notify = sdl_mouse_mode_change;
qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier);
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 4fc48f8..261c6f2 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -37,6 +37,7 @@
#include "migration.h"
#include "monitor.h"
#include "hw/hw.h"
+#include "spice-display.h"
/* core bits */
@@ -45,6 +46,7 @@ static Notifier migration_state;
static const char *auth = "spice";
static char *auth_passwd;
static time_t auth_expires = TIME_MAX;
+static int spice_migration_completed;
int using_spice = 0;
static QemuThread me;
@@ -221,7 +223,6 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
client = qdict_new();
server = qdict_new();
-#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT
if (info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) {
add_addr_info(client, (struct sockaddr *)&info->paddr_ext,
info->plen_ext);
@@ -230,12 +231,7 @@ static void channel_event(int event, SpiceChannelEventInfo *info)
} else {
error_report("spice: %s, extended address is expected",
__func__);
-#endif
- add_addr_info(client, &info->paddr, info->plen);
- add_addr_info(server, &info->laddr, info->llen);
-#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT
}
-#endif
if (event == SPICE_CHANNEL_EVENT_INITIALIZED) {
qdict_put(server, "auth", qstring_from_str(auth));
@@ -274,7 +270,6 @@ static SpiceCoreInterface core_interface = {
.channel_event = channel_event,
};
-#ifdef SPICE_INTERFACE_MIGRATION
typedef struct SpiceMigration {
SpiceMigrateInstance sin;
struct {
@@ -284,6 +279,7 @@ typedef struct SpiceMigration {
} SpiceMigration;
static void migrate_connect_complete_cb(SpiceMigrateInstance *sin);
+static void migrate_end_complete_cb(SpiceMigrateInstance *sin);
static const SpiceMigrateInterface migrate_interface = {
.base.type = SPICE_INTERFACE_MIGRATION,
@@ -291,7 +287,7 @@ static const SpiceMigrateInterface migrate_interface = {
.base.major_version = SPICE_INTERFACE_MIGRATION_MAJOR,
.base.minor_version = SPICE_INTERFACE_MIGRATION_MINOR,
.migrate_connect_complete = migrate_connect_complete_cb,
- .migrate_end_complete = NULL,
+ .migrate_end_complete = migrate_end_complete_cb,
};
static SpiceMigration spice_migrate;
@@ -304,7 +300,12 @@ static void migrate_connect_complete_cb(SpiceMigrateInstance *sin)
}
sm->connect_complete.cb = NULL;
}
-#endif
+
+static void migrate_end_complete_cb(SpiceMigrateInstance *sin)
+{
+ monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL);
+ spice_migration_completed = true;
+}
/* config string parsing */
@@ -344,7 +345,8 @@ static const char *stream_video_names[] = {
[ SPICE_STREAM_VIDEO_FILTER ] = "filter",
};
#define parse_stream_video(_name) \
- name2enum(_name, stream_video_names, ARRAY_SIZE(stream_video_names))
+ parse_name(_name, "stream video control", \
+ stream_video_names, ARRAY_SIZE(stream_video_names))
static const char *compression_names[] = {
[ SPICE_IMAGE_COMPRESS_OFF ] = "off",
@@ -383,17 +385,13 @@ static SpiceChannelList *qmp_query_spice_channels(void)
chan = g_malloc0(sizeof(*chan));
chan->value = g_malloc0(sizeof(*chan->value));
-#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT
if (item->info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) {
paddr = (struct sockaddr *)&item->info->paddr_ext;
plen = item->info->plen_ext;
} else {
-#endif
paddr = &item->info->paddr;
plen = item->info->plen;
-#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT
}
-#endif
getnameinfo(paddr, plen,
host, sizeof(host), port, sizeof(port),
@@ -435,6 +433,7 @@ SpiceInfo *qmp_query_spice(Error **errp)
}
info->enabled = true;
+ info->migrated = spice_migration_completed;
addr = qemu_opt_get(opts, "addr");
port = qemu_opt_get_number(opts, "port", 0);
@@ -462,13 +461,10 @@ SpiceInfo *qmp_query_spice(Error **errp)
info->tls_port = tls_port;
}
-#if SPICE_SERVER_VERSION >= 0x000a03 /* 0.10.3 */
info->mouse_mode = spice_server_is_server_mouse(spice_server) ?
SPICE_QUERY_MOUSE_MODE_SERVER :
SPICE_QUERY_MOUSE_MODE_CLIENT;
-#else
- info->mouse_mode = SPICE_QUERY_MOUSE_MODE_UNKNOWN;
-#endif
+
/* for compatibility with the original command */
info->has_channels = true;
info->channels = qmp_query_spice_channels();
@@ -481,17 +477,11 @@ static void migration_state_notifier(Notifier *notifier, void *data)
MigrationState *s = data;
if (migration_is_active(s)) {
-#ifdef SPICE_INTERFACE_MIGRATION
spice_server_migrate_start(spice_server);
-#endif
} else if (migration_has_finished(s)) {
-#ifndef SPICE_INTERFACE_MIGRATION
- spice_server_migrate_switch(spice_server);
-#else
spice_server_migrate_end(spice_server, true);
} else if (migration_has_failed(s)) {
spice_server_migrate_end(spice_server, false);
-#endif
}
}
@@ -500,16 +490,11 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
MonitorCompletion *cb, void *opaque)
{
int ret;
-#ifdef SPICE_INTERFACE_MIGRATION
+
spice_migrate.connect_complete.cb = cb;
spice_migrate.connect_complete.opaque = opaque;
ret = spice_server_migrate_connect(spice_server, hostname,
port, tls_port, subject);
-#else
- ret = spice_server_migrate_info(spice_server, hostname,
- port, tls_port, subject);
- cb(opaque, NULL);
-#endif
return ret;
}
@@ -545,6 +530,18 @@ static int add_channel(const char *name, const char *value, void *opaque)
return 0;
}
+static void vm_change_state_handler(void *opaque, int running,
+ RunState state)
+{
+ if (running) {
+ qemu_spice_display_start();
+ spice_server_vm_start(spice_server);
+ } else {
+ spice_server_vm_stop(spice_server);
+ qemu_spice_display_stop();
+ }
+}
+
void qemu_spice_init(void)
{
QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
@@ -558,6 +555,7 @@ void qemu_spice_init(void)
int port, tls_port, len, addr_flags;
spice_image_compression_t compression;
spice_wan_compression_t wan_compr;
+ bool seamless_migration;
qemu_thread_get_self(&me);
@@ -612,7 +610,7 @@ void qemu_spice_init(void)
}
x509_key_password = qemu_opt_get(opts, "x509-key-password");
- x509_dh_file = qemu_opt_get(opts, "x509-dh-file");
+ x509_dh_file = qemu_opt_get(opts, "x509-dh-key-file");
tls_ciphers = qemu_opt_get(opts, "tls-ciphers");
}
@@ -642,16 +640,11 @@ void qemu_spice_init(void)
spice_server_set_ticket(spice_server, password, 0, 0, 0);
}
if (qemu_opt_get_bool(opts, "sasl", 0)) {
-#if SPICE_SERVER_VERSION >= 0x000900 /* 0.9.0 */
if (spice_server_set_sasl_appname(spice_server, "qemu") == -1 ||
spice_server_set_sasl(spice_server, 1) == -1) {
error_report("spice: failed to enable sasl");
exit(1);
}
-#else
- error_report("spice: sasl is not available (spice >= 0.9 required)");
- exit(1);
-#endif
}
if (qemu_opt_get_bool(opts, "disable-ticketing", 0)) {
auth = "none";
@@ -696,11 +689,11 @@ void qemu_spice_init(void)
qemu_opt_foreach(opts, add_channel, &tls_port, 0);
-#if SPICE_SERVER_VERSION >= 0x000a02 /* 0.10.2 */
spice_server_set_name(spice_server, qemu_name);
spice_server_set_uuid(spice_server, qemu_uuid);
-#endif
+ seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0);
+ spice_server_set_seamless_migration(spice_server, seamless_migration);
if (0 != spice_server_init(spice_server, &core_interface)) {
error_report("failed to initialize spice server");
exit(1);
@@ -709,15 +702,15 @@ void qemu_spice_init(void)
migration_state.notify = migration_state_notifier;
add_migration_state_change_notifier(&migration_state);
-#ifdef SPICE_INTERFACE_MIGRATION
spice_migrate.sin.base.sif = &migrate_interface.base;
spice_migrate.connect_complete.cb = NULL;
qemu_spice_add_interface(&spice_migrate.sin.base);
-#endif
qemu_spice_input_init();
qemu_spice_audio_init();
+ qemu_add_vm_change_state_handler(vm_change_state_handler, &spice_server);
+
g_free(x509_key_file);
g_free(x509_cert_file);
g_free(x509_cacert_file);
@@ -740,6 +733,7 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin)
spice_server = spice_server_new();
spice_server_init(spice_server, &core_interface);
}
+
return spice_server_add_interface(spice_server, sin);
}
@@ -778,15 +772,11 @@ int qemu_spice_set_pw_expire(time_t expires)
int qemu_spice_display_add_client(int csock, int skipauth, int tls)
{
-#if SPICE_SERVER_VERSION >= 0x000a01
if (tls) {
return spice_server_add_ssl_client(spice_server, csock, skipauth);
} else {
return spice_server_add_client(spice_server, csock, skipauth);
}
-#else
- return -1;
-#endif
}
static void spice_register_config(void)
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 3e8f0b3..6aff336 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -126,46 +126,48 @@ void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
ssd->worker->wakeup(ssd->worker);
}
-void qemu_spice_start(SimpleSpiceDisplay *ssd)
+static int spice_display_is_running;
+
+void qemu_spice_display_start(void)
+{
+ spice_display_is_running = true;
+}
+
+void qemu_spice_display_stop(void)
{
- trace_qemu_spice_start(ssd->qxl.id);
- ssd->worker->start(ssd->worker);
+ spice_display_is_running = false;
}
-void qemu_spice_stop(SimpleSpiceDisplay *ssd)
+int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd)
{
- trace_qemu_spice_stop(ssd->qxl.id);
- ssd->worker->stop(ssd->worker);
+ return spice_display_is_running;
}
-static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
+static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd,
+ QXLRect *rect)
{
SimpleSpiceUpdate *update;
QXLDrawable *drawable;
QXLImage *image;
QXLCommand *cmd;
- uint8_t *src, *dst;
- int by, bw, bh;
+ int bw, bh;
struct timespec time_space;
-
- if (qemu_spice_rect_is_empty(&ssd->dirty)) {
- return NULL;
- };
+ pixman_image_t *dest;
trace_qemu_spice_create_update(
- ssd->dirty.left, ssd->dirty.right,
- ssd->dirty.top, ssd->dirty.bottom);
+ rect->left, rect->right,
+ rect->top, rect->bottom);
update = g_malloc0(sizeof(*update));
drawable = &update->drawable;
image = &update->image;
cmd = &update->ext.cmd;
- bw = ssd->dirty.right - ssd->dirty.left;
- bh = ssd->dirty.bottom - ssd->dirty.top;
+ bw = rect->right - rect->left;
+ bh = rect->bottom - rect->top;
update->bitmap = g_malloc(bw * bh * 4);
- drawable->bbox = ssd->dirty;
+ drawable->bbox = *rect;
drawable->clip.type = SPICE_CLIP_TYPE_NONE;
drawable->effect = QXL_EFFECT_OPAQUE;
drawable->release_info.id = (uintptr_t)update;
@@ -193,31 +195,94 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
image->bitmap.palette = 0;
image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
- if (ssd->conv == NULL) {
- PixelFormat dst = qemu_default_pixelformat(32);
- ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf);
- assert(ssd->conv);
+ dest = pixman_image_create_bits(PIXMAN_x8r8g8b8, bw, bh,
+ (void *)update->bitmap, bw * 4);
+ pixman_image_composite(PIXMAN_OP_SRC, ssd->surface, NULL, ssd->mirror,
+ rect->left, rect->top, 0, 0,
+ rect->left, rect->top, bw, bh);
+ pixman_image_composite(PIXMAN_OP_SRC, ssd->mirror, NULL, dest,
+ rect->left, rect->top, 0, 0,
+ 0, 0, bw, bh);
+ pixman_image_unref(dest);
+
+ cmd->type = QXL_CMD_DRAW;
+ cmd->data = (uintptr_t)drawable;
+
+ QTAILQ_INSERT_TAIL(&ssd->updates, update, next);
+}
+
+static void qemu_spice_create_update(SimpleSpiceDisplay *ssd)
+{
+ static const int blksize = 32;
+ int blocks = (ds_get_width(ssd->ds) + blksize - 1) / blksize;
+ int dirty_top[blocks];
+ int y, yoff, x, xoff, blk, bw;
+ int bpp = ds_get_bytes_per_pixel(ssd->ds);
+ uint8_t *guest, *mirror;
+
+ if (qemu_spice_rect_is_empty(&ssd->dirty)) {
+ return;
+ };
+
+ if (ssd->surface == NULL) {
+ ssd->surface = pixman_image_ref(ds_get_image(ssd->ds));
+ ssd->mirror = qemu_pixman_mirror_create(ds_get_format(ssd->ds),
+ ds_get_image(ssd->ds));
}
- src = ds_get_data(ssd->ds) +
- ssd->dirty.top * ds_get_linesize(ssd->ds) +
- ssd->dirty.left * ds_get_bytes_per_pixel(ssd->ds);
- dst = update->bitmap;
- for (by = 0; by < bh; by++) {
- qemu_pf_conv_run(ssd->conv, dst, src, bw);
- src += ds_get_linesize(ssd->ds);
- dst += image->bitmap.stride;
+ for (blk = 0; blk < blocks; blk++) {
+ dirty_top[blk] = -1;
}
- cmd->type = QXL_CMD_DRAW;
- cmd->data = (uintptr_t)drawable;
+ guest = ds_get_data(ssd->ds);
+ mirror = (void *)pixman_image_get_data(ssd->mirror);
+ for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) {
+ yoff = y * ds_get_linesize(ssd->ds);
+ 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,
+ bw * bpp) == 0) {
+ if (dirty_top[blk] != -1) {
+ QXLRect update = {
+ .top = dirty_top[blk],
+ .bottom = y,
+ .left = x,
+ .right = x + bw,
+ };
+ qemu_spice_create_one_update(ssd, &update);
+ dirty_top[blk] = -1;
+ }
+ } else {
+ if (dirty_top[blk] == -1) {
+ dirty_top[blk] = y;
+ }
+ }
+ }
+ }
+
+ for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) {
+ blk = x / blksize;
+ bw = MIN(blksize, ssd->dirty.right - x);
+ if (dirty_top[blk] != -1) {
+ QXLRect update = {
+ .top = dirty_top[blk],
+ .bottom = ssd->dirty.bottom,
+ .left = x,
+ .right = x + bw,
+ };
+ qemu_spice_create_one_update(ssd, &update);
+ dirty_top[blk] = -1;
+ }
+ }
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
- return update;
}
/*
- * Called from spice server thread context (via interface_release_ressource)
+ * Called from spice server thread context (via interface_release_resource)
* We do *not* hold the global qemu mutex here, so extra care is needed
* when calling qemu functions. QEMU interfaces used:
* - g_free (underlying glibc free is re-entrant).
@@ -269,26 +334,16 @@ void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC);
}
-void qemu_spice_vm_change_state_handler(void *opaque, int running,
- RunState state)
-{
- SimpleSpiceDisplay *ssd = opaque;
-
- if (running) {
- ssd->running = true;
- qemu_spice_start(ssd);
- } else {
- qemu_spice_stop(ssd);
- ssd->running = false;
- }
-}
-
void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds)
{
ssd->ds = ds;
qemu_mutex_init(&ssd->lock);
+ QTAILQ_INIT(&ssd->updates);
ssd->mouse_x = -1;
ssd->mouse_y = -1;
+ if (ssd->num_surfaces == 0) {
+ ssd->num_surfaces = 1024;
+ }
ssd->bufsize = (16 * 1024 * 1024);
ssd->buf = g_malloc(ssd->bufsize);
}
@@ -314,16 +369,22 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
{
+ SimpleSpiceUpdate *update;
+
dprint(1, "%s:\n", __FUNCTION__);
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
- qemu_pf_conv_put(ssd->conv);
- ssd->conv = NULL;
+ if (ssd->surface) {
+ pixman_image_unref(ssd->surface);
+ ssd->surface = NULL;
+ pixman_image_unref(ssd->mirror);
+ ssd->mirror = NULL;
+ }
qemu_mutex_lock(&ssd->lock);
- if (ssd->update != NULL) {
- qemu_spice_destroy_update(ssd, ssd->update);
- ssd->update = NULL;
+ while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) {
+ QTAILQ_REMOVE(&ssd->updates, update, next);
+ qemu_spice_destroy_update(ssd, update);
}
qemu_mutex_unlock(&ssd->lock);
qemu_spice_destroy_host_primary(ssd);
@@ -336,12 +397,12 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd)
{
if (ssd->cursor) {
- ssd->ds->cursor_define(ssd->cursor);
+ dpy_cursor_define(ssd->ds, ssd->cursor);
cursor_put(ssd->cursor);
ssd->cursor = NULL;
}
if (ssd->mouse_x != -1 && ssd->mouse_y != -1) {
- ssd->ds->mouse_set(ssd->mouse_x, ssd->mouse_y, 1);
+ dpy_mouse_set(ssd->ds, ssd->mouse_x, ssd->mouse_y, 1);
ssd->mouse_x = -1;
ssd->mouse_y = -1;
}
@@ -353,8 +414,8 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
vga_hw_update();
qemu_mutex_lock(&ssd->lock);
- if (ssd->update == NULL) {
- ssd->update = qemu_spice_create_update(ssd);
+ if (QTAILQ_EMPTY(&ssd->updates)) {
+ qemu_spice_create_update(ssd);
ssd->notify++;
}
qemu_spice_cursor_refresh_unlocked(ssd);
@@ -399,7 +460,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
info->internal_groupslot_id = 0;
info->qxl_ram_size = ssd->bufsize;
- info->n_surfaces = NUM_SURFACES;
+ info->n_surfaces = ssd->num_surfaces;
}
static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
@@ -411,9 +472,9 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
dprint(3, "%s:\n", __FUNCTION__);
qemu_mutex_lock(&ssd->lock);
- if (ssd->update != NULL) {
- update = ssd->update;
- ssd->update = NULL;
+ update = QTAILQ_FIRST(&ssd->updates);
+ if (update != NULL) {
+ QTAILQ_REMOVE(&ssd->updates, update, next);
*ext = update->ext;
ret = true;
}
@@ -464,6 +525,37 @@ static int interface_flush_resources(QXLInstance *sin)
return 0;
}
+static void interface_update_area_complete(QXLInstance *sin,
+ uint32_t surface_id,
+ QXLRect *dirty, uint32_t num_updated_rects)
+{
+ /* should never be called, used in qxl native mode only */
+ fprintf(stderr, "%s: abort()\n", __func__);
+ abort();
+}
+
+/* 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();
+}
+
+static void interface_set_client_capabilities(QXLInstance *sin,
+ uint8_t client_present,
+ uint8_t caps[58])
+{
+ dprint(3, "%s:\n", __func__);
+}
+
+static int interface_client_monitors_config(QXLInstance *sin,
+ VDAgentMonitorsConfig *monitors_config)
+{
+ dprint(3, "%s:\n", __func__);
+ return 0; /* == not supported by guest */
+}
+
static const QXLInterface dpy_interface = {
.base.type = SPICE_INTERFACE_QXL,
.base.description = "qemu simple display",
@@ -483,6 +575,10 @@ static const QXLInterface dpy_interface = {
.req_cursor_notification = interface_req_cursor_notification,
.notify_update = interface_notify_update,
.flush_resources = interface_flush_resources,
+ .async_complete = interface_async_complete,
+ .update_area_complete = interface_update_area_complete,
+ .set_client_capabilities = interface_set_client_capabilities,
+ .client_monitors_config = interface_client_monitors_config,
};
static SimpleSpiceDisplay sdpy;
@@ -503,8 +599,8 @@ static void display_refresh(struct DisplayState *ds)
}
static DisplayChangeListener display_listener = {
- .dpy_update = display_update,
- .dpy_resize = display_resize,
+ .dpy_gfx_update = display_update,
+ .dpy_gfx_resize = display_resize,
.dpy_refresh = display_refresh,
};
@@ -512,13 +608,12 @@ void qemu_spice_display_init(DisplayState *ds)
{
assert(sdpy.ds == NULL);
qemu_spice_display_init_common(&sdpy, ds);
- register_displaychangelistener(ds, &display_listener);
sdpy.qxl.base.sif = &dpy_interface.base;
qemu_spice_add_interface(&sdpy.qxl.base);
assert(sdpy.worker);
- qemu_add_vm_change_state_handler(qemu_spice_vm_change_state_handler, &sdpy);
qemu_spice_create_host_memslot(&sdpy);
qemu_spice_create_host_primary(&sdpy);
+ register_displaychangelistener(ds, &display_listener);
}
diff --git a/ui/spice-display.h b/ui/spice-display.h
index 12e50b6..38b6ea9 100644
--- a/ui/spice-display.h
+++ b/ui/spice-display.h
@@ -20,8 +20,7 @@
#include <spice/qxl_dev.h>
#include "qemu-thread.h"
-#include "console.h"
-#include "pflib.h"
+#include "qemu-pixman.h"
#include "sysemu.h"
#define NUM_MEMSLOTS 8
@@ -32,8 +31,6 @@
#define MEMSLOT_GROUP_GUEST 1
#define NUM_MEMSLOTS_GROUPS 2
-#define NUM_SURFACES 1024
-
/*
* Internal enum to differenciate between options for
* io calls that have a sync (old) version and an _async (new)
@@ -51,6 +48,7 @@ typedef enum qxl_async_io {
enum {
QXL_COOKIE_TYPE_IO,
QXL_COOKIE_TYPE_RENDER_UPDATE_AREA,
+ QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG,
};
typedef struct QXLCookie {
@@ -78,11 +76,12 @@ struct SimpleSpiceDisplay {
QXLWorker *worker;
QXLInstance qxl;
uint32_t unique;
- QemuPfConv *conv;
+ pixman_image_t *surface;
+ pixman_image_t *mirror;
+ int32_t num_surfaces;
QXLRect dirty;
int notify;
- int running;
/*
* All struct members below this comment can be accessed from
@@ -90,7 +89,7 @@ struct SimpleSpiceDisplay {
* to them must be protected by the lock.
*/
QemuMutex lock;
- SimpleSpiceUpdate *update;
+ QTAILQ_HEAD(, SimpleSpiceUpdate) updates;
QEMUCursor *cursor;
int mouse_x, mouse_y;
};
@@ -100,6 +99,7 @@ struct SimpleSpiceUpdate {
QXLImage image;
QXLCommandExt ext;
uint8_t *bitmap;
+ QTAILQ_ENTRY(SimpleSpiceUpdate) next;
};
int qemu_spice_rect_is_empty(const QXLRect* r);
@@ -129,5 +129,6 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
uint32_t id, qxl_async_io async);
void qemu_spice_wakeup(SimpleSpiceDisplay *ssd);
-void qemu_spice_start(SimpleSpiceDisplay *ssd);
-void qemu_spice_stop(SimpleSpiceDisplay *ssd);
+void qemu_spice_display_start(void);
+void qemu_spice_display_stop(void);
+int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd);
diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c
index 8fba770..f3ad75d 100644
--- a/ui/vnc-auth-sasl.c
+++ b/ui/vnc-auth-sasl.c
@@ -432,9 +432,7 @@ static int protocol_client_auth_sasl_start_len(VncState *vs, uint8_t *data, size
static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_t len)
{
- char *mechname = g_malloc(len + 1);
- strncpy(mechname, (char*)data, len);
- mechname[len] = '\0';
+ char *mechname = g_strndup((const char *) data, len);
VNC_DEBUG("Got client mechname '%s' check against '%s'\n",
mechname, vs->sasl.mechlist);
@@ -619,7 +617,6 @@ void start_auth_sasl(VncState *vs)
authabort:
vnc_client_error(vs);
- return;
}
diff --git a/ui/vnc-enc-hextile-template.h b/ui/vnc-enc-hextile-template.h
index a7310e1..d868d75 100644
--- a/ui/vnc-enc-hextile-template.h
+++ b/ui/vnc-enc-hextile-template.h
@@ -14,7 +14,7 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
int *has_bg, int *has_fg)
{
VncDisplay *vd = vs->vd;
- uint8_t *row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
+ uint8_t *row = vnc_server_fb_ptr(vd, x, y);
pixel_t *irow = (pixel_t *)row;
int j, i;
pixel_t *last_bg = (pixel_t *)last_bg_;
@@ -25,7 +25,7 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
int bg_count = 0;
int fg_count = 0;
int flags = 0;
- uint8_t data[(vs->clientds.pf.bytes_per_pixel + 2) * 16 * 16];
+ uint8_t data[(vs->client_pf.bytes_per_pixel + 2) * 16 * 16];
int n_data = 0;
int n_subtiles = 0;
@@ -58,7 +58,7 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
}
if (n_colors > 2)
break;
- irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
+ irow += vnc_server_fb_stride(vd) / sizeof(pixel_t);
}
if (n_colors > 1 && fg_count > bg_count) {
@@ -106,7 +106,7 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
n_data += 2;
n_subtiles++;
}
- irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
+ irow += vnc_server_fb_stride(vd) / sizeof(pixel_t);
}
break;
case 3:
@@ -133,7 +133,7 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
has_color = 0;
#ifdef GENERIC
vnc_convert_pixel(vs, data + n_data, color);
- n_data += vs->clientds.pf.bytes_per_pixel;
+ n_data += vs->client_pf.bytes_per_pixel;
#else
memcpy(data + n_data, &color, sizeof(color));
n_data += sizeof(pixel_t);
@@ -153,7 +153,7 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
if (has_color) {
#ifdef GENERIC
vnc_convert_pixel(vs, data + n_data, color);
- n_data += vs->clientds.pf.bytes_per_pixel;
+ n_data += vs->client_pf.bytes_per_pixel;
#else
memcpy(data + n_data, &color, sizeof(color));
n_data += sizeof(pixel_t);
@@ -162,7 +162,7 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
n_data += 2;
n_subtiles++;
}
- irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
+ irow += vnc_server_fb_stride(vd) / sizeof(pixel_t);
}
/* A SubrectsColoured subtile invalidates the foreground color */
@@ -190,18 +190,17 @@ static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
vnc_write_u8(vs, flags);
if (n_colors < 4) {
if (flags & 0x02)
- vs->write_pixels(vs, &vd->server->pf, last_bg, sizeof(pixel_t));
+ vs->write_pixels(vs, last_bg, sizeof(pixel_t));
if (flags & 0x04)
- vs->write_pixels(vs, &vd->server->pf, last_fg, sizeof(pixel_t));
+ vs->write_pixels(vs, last_fg, sizeof(pixel_t));
if (n_subtiles) {
vnc_write_u8(vs, n_subtiles);
vnc_write(vs, data, n_data);
}
} else {
for (j = 0; j < h; j++) {
- vs->write_pixels(vs, &vd->server->pf, row,
- w * ds_get_bytes_per_pixel(vs->ds));
- row += ds_get_linesize(vs->ds);
+ vs->write_pixels(vs, row, w * 4);
+ row += vnc_server_fb_stride(vd);
}
}
}
diff --git a/ui/vnc-enc-hextile.c b/ui/vnc-enc-hextile.c
index c860dbb..2e768fd 100644
--- a/ui/vnc-enc-hextile.c
+++ b/ui/vnc-enc-hextile.c
@@ -32,31 +32,11 @@ static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F);
}
-#define BPP 8
-#include "vnc-enc-hextile-template.h"
-#undef BPP
-
-#define BPP 16
-#include "vnc-enc-hextile-template.h"
-#undef BPP
-
#define BPP 32
#include "vnc-enc-hextile-template.h"
#undef BPP
#define GENERIC
-#define BPP 8
-#include "vnc-enc-hextile-template.h"
-#undef BPP
-#undef GENERIC
-
-#define GENERIC
-#define BPP 16
-#include "vnc-enc-hextile-template.h"
-#undef BPP
-#undef GENERIC
-
-#define GENERIC
#define BPP 32
#include "vnc-enc-hextile-template.h"
#undef BPP
@@ -68,10 +48,9 @@ int vnc_hextile_send_framebuffer_update(VncState *vs, int x,
int i, j;
int has_fg, has_bg;
uint8_t *last_fg, *last_bg;
- VncDisplay *vd = vs->vd;
- last_fg = (uint8_t *) g_malloc(vd->server->pf.bytes_per_pixel);
- last_bg = (uint8_t *) g_malloc(vd->server->pf.bytes_per_pixel);
+ last_fg = (uint8_t *) g_malloc(VNC_SERVER_FB_BYTES);
+ last_bg = (uint8_t *) g_malloc(VNC_SERVER_FB_BYTES);
has_fg = has_bg = 0;
for (j = y; j < (y + h); j += 16) {
for (i = x; i < (x + w); i += 16) {
@@ -89,28 +68,16 @@ int vnc_hextile_send_framebuffer_update(VncState *vs, int x,
void vnc_hextile_set_pixel_conversion(VncState *vs, int generic)
{
if (!generic) {
- switch (vs->ds->surface->pf.bits_per_pixel) {
- case 8:
- vs->hextile.send_tile = send_hextile_tile_8;
- break;
- case 16:
- vs->hextile.send_tile = send_hextile_tile_16;
- break;
- case 32:
- vs->hextile.send_tile = send_hextile_tile_32;
- break;
+ switch (VNC_SERVER_FB_BITS) {
+ case 32:
+ vs->hextile.send_tile = send_hextile_tile_32;
+ break;
}
} else {
- switch (vs->ds->surface->pf.bits_per_pixel) {
- case 8:
- vs->hextile.send_tile = send_hextile_tile_generic_8;
- break;
- case 16:
- vs->hextile.send_tile = send_hextile_tile_generic_16;
- break;
- case 32:
- vs->hextile.send_tile = send_hextile_tile_generic_32;
- break;
+ switch (VNC_SERVER_FB_BITS) {
+ case 32:
+ vs->hextile.send_tile = send_hextile_tile_generic_32;
+ break;
}
}
}
diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index 5d492ab..9ae4cab 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -124,7 +124,7 @@ static bool tight_can_send_png_rect(VncState *vs, int w, int h)
}
if (ds_get_bytes_per_pixel(vs->ds) == 1 ||
- vs->clientds.pf.bytes_per_pixel == 1) {
+ vs->client_pf.bytes_per_pixel == 1) {
return false;
}
@@ -153,7 +153,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
* If client is big-endian, color samples begin from the second
* byte (offset 1) of a 32-bit pixel value.
*/
- off = !!(vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG);
+ off = vs->client_be;
memset(stats, 0, sizeof (stats));
@@ -216,16 +216,16 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
unsigned int errors; \
unsigned char *buf = vs->tight.tight.buffer; \
\
- endian = ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) != \
- (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)); \
+ endian = 0; /* FIXME: ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) != \
+ (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)); */ \
\
\
- max[0] = vs->clientds.pf.rmax; \
- max[1] = vs->clientds.pf.gmax; \
- max[2] = vs->clientds.pf.bmax; \
- shift[0] = vs->clientds.pf.rshift; \
- shift[1] = vs->clientds.pf.gshift; \
- shift[2] = vs->clientds.pf.bshift; \
+ max[0] = vs->client_pf.rmax; \
+ max[1] = vs->client_pf.gmax; \
+ max[2] = vs->client_pf.bmax; \
+ shift[0] = vs->client_pf.rshift; \
+ shift[1] = vs->client_pf.gshift; \
+ shift[2] = vs->client_pf.bshift; \
\
memset(stats, 0, sizeof(stats)); \
\
@@ -302,7 +302,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
}
if (ds_get_bytes_per_pixel(vs->ds) == 1 ||
- vs->clientds.pf.bytes_per_pixel == 1 ||
+ vs->client_pf.bytes_per_pixel == 1 ||
w < VNC_TIGHT_DETECT_MIN_WIDTH || h < VNC_TIGHT_DETECT_MIN_HEIGHT) {
return 0;
}
@@ -317,7 +317,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
}
}
- if (vs->clientds.pf.bytes_per_pixel == 4) {
+ if (vs->client_pf.bytes_per_pixel == 4) {
if (vs->tight.pixel24) {
errors = tight_detect_smooth_image24(vs, w, h);
if (vs->tight.quality != (uint8_t)-1) {
@@ -430,7 +430,7 @@ static int tight_fill_palette(VncState *vs, int x, int y,
max = 256;
}
- switch(vs->clientds.pf.bytes_per_pixel) {
+ switch (vs->client_pf.bytes_per_pixel) {
case 4:
return tight_fill_palette32(vs, x, y, max, count, bg, fg, palette);
case 2:
@@ -557,15 +557,15 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
buf32 = (uint32_t *)buf;
memset(vs->tight.gradient.buffer, 0, w * 3 * sizeof(int));
- if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
- (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)) {
- shift[0] = vs->clientds.pf.rshift;
- shift[1] = vs->clientds.pf.gshift;
- shift[2] = vs->clientds.pf.bshift;
+ if (1 /* FIXME: (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
+ (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) */) {
+ shift[0] = vs->client_pf.rshift;
+ shift[1] = vs->client_pf.gshift;
+ shift[2] = vs->client_pf.bshift;
} else {
- shift[0] = 24 - vs->clientds.pf.rshift;
- shift[1] = 24 - vs->clientds.pf.gshift;
- shift[2] = 24 - vs->clientds.pf.bshift;
+ shift[0] = 24 - vs->client_pf.rshift;
+ shift[1] = 24 - vs->client_pf.gshift;
+ shift[2] = 24 - vs->client_pf.bshift;
}
for (y = 0; y < h; y++) {
@@ -615,15 +615,15 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
\
memset (vs->tight.gradient.buffer, 0, w * 3 * sizeof(int)); \
\
- endian = ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) != \
- (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)); \
+ endian = 0; /* FIXME: ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) != \
+ (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)); */ \
\
- max[0] = vs->clientds.pf.rmax; \
- max[1] = vs->clientds.pf.gmax; \
- max[2] = vs->clientds.pf.bmax; \
- shift[0] = vs->clientds.pf.rshift; \
- shift[1] = vs->clientds.pf.gshift; \
- shift[2] = vs->clientds.pf.bshift; \
+ max[0] = vs->client_pf.rmax; \
+ max[1] = vs->client_pf.gmax; \
+ max[2] = vs->client_pf.bmax; \
+ shift[0] = vs->client_pf.rshift; \
+ shift[1] = vs->client_pf.gshift; \
+ shift[2] = vs->client_pf.bshift; \
\
for (y = 0; y < h; y++) { \
for (c = 0; c < 3; c++) { \
@@ -671,56 +671,42 @@ DEFINE_GRADIENT_FILTER_FUNCTION(32)
* that case new color will be stored in *colorPtr.
*/
-#define DEFINE_CHECK_SOLID_FUNCTION(bpp) \
- \
- static bool \
- check_solid_tile##bpp(VncState *vs, int x, int y, int w, int h, \
- uint32_t* color, bool samecolor) \
- { \
- VncDisplay *vd = vs->vd; \
- uint##bpp##_t *fbptr; \
- uint##bpp##_t c; \
- int dx, dy; \
- \
- fbptr = (uint##bpp##_t *) \
- (vd->server->data + y * ds_get_linesize(vs->ds) + \
- x * ds_get_bytes_per_pixel(vs->ds)); \
- \
- c = *fbptr; \
- if (samecolor && (uint32_t)c != *color) { \
- return false; \
- } \
- \
- for (dy = 0; dy < h; dy++) { \
- for (dx = 0; dx < w; dx++) { \
- if (c != fbptr[dx]) { \
- return false; \
- } \
- } \
- fbptr = (uint##bpp##_t *) \
- ((uint8_t *)fbptr + ds_get_linesize(vs->ds)); \
- } \
- \
- *color = (uint32_t)c; \
- return true; \
+static bool
+check_solid_tile32(VncState *vs, int x, int y, int w, int h,
+ uint32_t *color, bool samecolor)
+{
+ VncDisplay *vd = vs->vd;
+ uint32_t *fbptr;
+ uint32_t c;
+ int dx, dy;
+
+ fbptr = vnc_server_fb_ptr(vd, x, y);
+
+ c = *fbptr;
+ if (samecolor && (uint32_t)c != *color) {
+ return false;
+ }
+
+ for (dy = 0; dy < h; dy++) {
+ for (dx = 0; dx < w; dx++) {
+ if (c != fbptr[dx]) {
+ return false;
+ }
+ }
+ fbptr = (uint32_t *)
+ ((uint8_t *)fbptr + vnc_server_fb_stride(vd));
}
-DEFINE_CHECK_SOLID_FUNCTION(32)
-DEFINE_CHECK_SOLID_FUNCTION(16)
-DEFINE_CHECK_SOLID_FUNCTION(8)
+ *color = (uint32_t)c;
+ return true;
+}
static bool check_solid_tile(VncState *vs, int x, int y, int w, int h,
uint32_t* color, bool samecolor)
{
- VncDisplay *vd = vs->vd;
-
- switch(vd->server->pf.bytes_per_pixel) {
+ switch (VNC_SERVER_FB_BYTES) {
case 4:
return check_solid_tile32(vs, x, y, w, h, color, samecolor);
- case 2:
- return check_solid_tile16(vs, x, y, w, h, color, samecolor);
- default:
- return check_solid_tile8(vs, x, y, w, h, color, samecolor);
}
}
@@ -906,15 +892,15 @@ static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret)
buf32 = (uint32_t *)buf;
- if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
- (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)) {
- rshift = vs->clientds.pf.rshift;
- gshift = vs->clientds.pf.gshift;
- bshift = vs->clientds.pf.bshift;
+ if (1 /* FIXME: (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
+ (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) */) {
+ rshift = vs->client_pf.rshift;
+ gshift = vs->client_pf.gshift;
+ bshift = vs->client_pf.bshift;
} else {
- rshift = 24 - vs->clientds.pf.rshift;
- gshift = 24 - vs->clientds.pf.gshift;
- bshift = 24 - vs->clientds.pf.bshift;
+ rshift = 24 - vs->client_pf.rshift;
+ gshift = 24 - vs->client_pf.gshift;
+ bshift = 24 - vs->client_pf.bshift;
}
if (ret) {
@@ -946,7 +932,7 @@ static int send_full_color_rect(VncState *vs, int x, int y, int w, int h)
tight_pack24(vs, vs->tight.tight.buffer, w * h, &vs->tight.tight.offset);
bytes = 3;
} else {
- bytes = vs->clientds.pf.bytes_per_pixel;
+ bytes = vs->client_pf.bytes_per_pixel;
}
bytes = tight_compress_data(vs, stream, w * h * bytes,
@@ -966,7 +952,7 @@ static int send_solid_rect(VncState *vs)
tight_pack24(vs, vs->tight.tight.buffer, 1, &vs->tight.tight.offset);
bytes = 3;
} else {
- bytes = vs->clientds.pf.bytes_per_pixel;
+ bytes = vs->client_pf.bytes_per_pixel;
}
vnc_write(vs, vs->tight.tight.buffer, bytes);
@@ -983,7 +969,7 @@ static int send_mono_rect(VncState *vs, int x, int y,
#ifdef CONFIG_VNC_PNG
if (tight_can_send_png_rect(vs, w, h)) {
int ret;
- int bpp = vs->clientds.pf.bytes_per_pixel * 8;
+ int bpp = vs->client_pf.bytes_per_pixel * 8;
VncPalette *palette = palette_new(2, bpp);
palette_put(palette, bg);
@@ -1000,7 +986,7 @@ static int send_mono_rect(VncState *vs, int x, int y,
vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
vnc_write_u8(vs, 1);
- switch(vs->clientds.pf.bytes_per_pixel) {
+ switch (vs->client_pf.bytes_per_pixel) {
case 4:
{
uint32_t buf[2] = {bg, fg};
@@ -1043,7 +1029,7 @@ static void write_palette(int idx, uint32_t color, void *opaque)
{
struct palette_cb_priv *priv = opaque;
VncState *vs = priv->vs;
- uint32_t bytes = vs->clientds.pf.bytes_per_pixel;
+ uint32_t bytes = vs->client_pf.bytes_per_pixel;
if (bytes == 4) {
((uint32_t*)priv->header)[idx] = color;
@@ -1058,8 +1044,9 @@ static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
int level = tight_conf[vs->tight.compression].gradient_zlib_level;
ssize_t bytes;
- if (vs->clientds.pf.bytes_per_pixel == 1)
+ if (vs->client_pf.bytes_per_pixel == 1) {
return send_full_color_rect(vs, x, y, w, h);
+ }
vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT);
@@ -1069,7 +1056,7 @@ static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
if (vs->tight.pixel24) {
tight_filter_gradient24(vs, vs->tight.tight.buffer, w, h);
bytes = 3;
- } else if (vs->clientds.pf.bytes_per_pixel == 4) {
+ } else if (vs->client_pf.bytes_per_pixel == 4) {
tight_filter_gradient32(vs, (uint32_t *)vs->tight.tight.buffer, w, h);
bytes = 4;
} else {
@@ -1107,7 +1094,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
vnc_write_u8(vs, colors - 1);
- switch(vs->clientds.pf.bytes_per_pixel) {
+ switch (vs->client_pf.bytes_per_pixel) {
case 4:
{
size_t old_offset, offset;
@@ -1148,79 +1135,6 @@ static int send_palette_rect(VncState *vs, int x, int y,
return (bytes >= 0);
}
-#if defined(CONFIG_VNC_JPEG) || defined(CONFIG_VNC_PNG)
-static void rgb_prepare_row24(VncState *vs, uint8_t *dst, int x, int y,
- int count)
-{
- VncDisplay *vd = vs->vd;
- uint32_t *fbptr;
- uint32_t pix;
-
- fbptr = (uint32_t *)(vd->server->data + y * ds_get_linesize(vs->ds) +
- x * ds_get_bytes_per_pixel(vs->ds));
-
- while (count--) {
- pix = *fbptr++;
- *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.rshift);
- *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.gshift);
- *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.bshift);
- }
-}
-
-#define DEFINE_RGB_GET_ROW_FUNCTION(bpp) \
- \
- static void \
- rgb_prepare_row##bpp(VncState *vs, uint8_t *dst, \
- int x, int y, int count) \
- { \
- VncDisplay *vd = vs->vd; \
- uint##bpp##_t *fbptr; \
- uint##bpp##_t pix; \
- int r, g, b; \
- \
- fbptr = (uint##bpp##_t *) \
- (vd->server->data + y * ds_get_linesize(vs->ds) + \
- x * ds_get_bytes_per_pixel(vs->ds)); \
- \
- while (count--) { \
- pix = *fbptr++; \
- \
- r = (int)((pix >> vs->ds->surface->pf.rshift) \
- & vs->ds->surface->pf.rmax); \
- g = (int)((pix >> vs->ds->surface->pf.gshift) \
- & vs->ds->surface->pf.gmax); \
- b = (int)((pix >> vs->ds->surface->pf.bshift) \
- & vs->ds->surface->pf.bmax); \
- \
- *dst++ = (uint8_t)((r * 255 + vs->ds->surface->pf.rmax / 2) \
- / vs->ds->surface->pf.rmax); \
- *dst++ = (uint8_t)((g * 255 + vs->ds->surface->pf.gmax / 2) \
- / vs->ds->surface->pf.gmax); \
- *dst++ = (uint8_t)((b * 255 + vs->ds->surface->pf.bmax / 2) \
- / vs->ds->surface->pf.bmax); \
- } \
- }
-
-DEFINE_RGB_GET_ROW_FUNCTION(16)
-DEFINE_RGB_GET_ROW_FUNCTION(32)
-
-static void rgb_prepare_row(VncState *vs, uint8_t *dst, int x, int y,
- int count)
-{
- if (ds_get_bytes_per_pixel(vs->ds) == 4) {
- if (vs->ds->surface->pf.rmax == 0xFF &&
- vs->ds->surface->pf.gmax == 0xFF &&
- vs->ds->surface->pf.bmax == 0xFF) {
- rgb_prepare_row24(vs, dst, x, y, count);
- } else {
- rgb_prepare_row32(vs, dst, x, y, count);
- }
- } else {
- rgb_prepare_row16(vs, dst, x, y, count);
- }
-}
-#endif /* CONFIG_VNC_JPEG or CONFIG_VNC_PNG */
-
/*
* JPEG compression stuff.
*/
@@ -1265,6 +1179,7 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
struct jpeg_destination_mgr manager;
+ pixman_image_t *linebuf;
JSAMPROW row[1];
uint8_t *buf;
int dy;
@@ -1293,13 +1208,14 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
jpeg_start_compress(&cinfo, true);
- buf = g_malloc(w * 3);
+ linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, w);
+ buf = (uint8_t *)pixman_image_get_data(linebuf);
row[0] = buf;
for (dy = 0; dy < h; dy++) {
- rgb_prepare_row(vs, buf, x, y + dy, w);
+ qemu_pixman_linebuf_fill(linebuf, vs->vd->server, w, dy);
jpeg_write_scanlines(&cinfo, row, 1);
}
- g_free(buf);
+ qemu_pixman_image_unref(linebuf);
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
@@ -1326,23 +1242,23 @@ static void write_png_palette(int idx, uint32_t pix, void *opaque)
if (vs->tight.pixel24)
{
- color->red = (pix >> vs->clientds.pf.rshift) & vs->clientds.pf.rmax;
- color->green = (pix >> vs->clientds.pf.gshift) & vs->clientds.pf.gmax;
- color->blue = (pix >> vs->clientds.pf.bshift) & vs->clientds.pf.bmax;
+ color->red = (pix >> vs->client_pf.rshift) & vs->client_pf.rmax;
+ color->green = (pix >> vs->client_pf.gshift) & vs->client_pf.gmax;
+ color->blue = (pix >> vs->client_pf.bshift) & vs->client_pf.bmax;
}
else
{
int red, green, blue;
- red = (pix >> vs->clientds.pf.rshift) & vs->clientds.pf.rmax;
- green = (pix >> vs->clientds.pf.gshift) & vs->clientds.pf.gmax;
- blue = (pix >> vs->clientds.pf.bshift) & vs->clientds.pf.bmax;
- color->red = ((red * 255 + vs->clientds.pf.rmax / 2) /
- vs->clientds.pf.rmax);
- color->green = ((green * 255 + vs->clientds.pf.gmax / 2) /
- vs->clientds.pf.gmax);
- color->blue = ((blue * 255 + vs->clientds.pf.bmax / 2) /
- vs->clientds.pf.bmax);
+ red = (pix >> vs->client_pf.rshift) & vs->client_pf.rmax;
+ green = (pix >> vs->client_pf.gshift) & vs->client_pf.gmax;
+ blue = (pix >> vs->client_pf.bshift) & vs->client_pf.bmax;
+ color->red = ((red * 255 + vs->client_pf.rmax / 2) /
+ vs->client_pf.rmax);
+ color->green = ((green * 255 + vs->client_pf.gmax / 2) /
+ vs->client_pf.gmax);
+ color->blue = ((blue * 255 + vs->client_pf.bmax / 2) /
+ vs->client_pf.bmax);
}
}
@@ -1378,6 +1294,7 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
png_structp png_ptr;
png_infop info_ptr;
png_colorp png_palette = NULL;
+ pixman_image_t *linebuf;
int level = tight_png_conf[vs->tight.compression].png_zlib_level;
int filters = tight_png_conf[vs->tight.compression].png_filters;
uint8_t *buf;
@@ -1422,7 +1339,7 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette));
- if (vs->clientds.pf.bytes_per_pixel == 4) {
+ if (vs->client_pf.bytes_per_pixel == 4) {
tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
} else {
tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
@@ -1432,17 +1349,18 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
png_write_info(png_ptr, info_ptr);
buffer_reserve(&vs->tight.png, 2048);
- buf = g_malloc(w * 3);
+ linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, w);
+ buf = (uint8_t *)pixman_image_get_data(linebuf);
for (dy = 0; dy < h; dy++)
{
if (color_type == PNG_COLOR_TYPE_PALETTE) {
memcpy(buf, vs->tight.tight.buffer + (dy * w), w);
} else {
- rgb_prepare_row(vs, buf, x, y + dy, w);
+ qemu_pixman_linebuf_fill(linebuf, vs->vd->server, w, dy);
}
png_write_row(png_ptr, buf);
}
- g_free(buf);
+ qemu_pixman_image_unref(linebuf);
png_write_end(png_ptr, NULL);
@@ -1713,8 +1631,8 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
{
int max_rows;
- if (vs->clientds.pf.bytes_per_pixel == 4 && vs->clientds.pf.rmax == 0xFF &&
- vs->clientds.pf.bmax == 0xFF && vs->clientds.pf.gmax == 0xFF) {
+ if (vs->client_pf.bytes_per_pixel == 4 && vs->client_pf.rmax == 0xFF &&
+ vs->client_pf.bmax == 0xFF && vs->client_pf.gmax == 0xFF) {
vs->tight.pixel24 = true;
} else {
vs->tight.pixel24 = false;
diff --git a/ui/vnc-enc-zrle.c b/ui/vnc-enc-zrle.c
index 917d384..ed3b484 100644
--- a/ui/vnc-enc-zrle.c
+++ b/ui/vnc-enc-zrle.c
@@ -255,7 +255,7 @@ static void zrle_write_u8(VncState *vs, uint8_t value)
static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
int w, int h)
{
- bool be = !!(vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG);
+ bool be = vs->client_be;
size_t bytes;
int zywrle_level;
@@ -277,13 +277,13 @@ static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
vnc_zrle_start(vs);
- switch(vs->clientds.pf.bytes_per_pixel) {
+ switch (vs->client_pf.bytes_per_pixel) {
case 1:
zrle_encode_8ne(vs, x, y, w, h, zywrle_level);
break;
case 2:
- if (vs->clientds.pf.gmax > 0x1F) {
+ if (vs->client_pf.gmax > 0x1F) {
if (be) {
zrle_encode_16be(vs, x, y, w, h, zywrle_level);
} else {
@@ -304,13 +304,13 @@ static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
bool fits_in_ms3bytes;
fits_in_ls3bytes =
- ((vs->clientds.pf.rmax << vs->clientds.pf.rshift) < (1 << 24) &&
- (vs->clientds.pf.gmax << vs->clientds.pf.gshift) < (1 << 24) &&
- (vs->clientds.pf.bmax << vs->clientds.pf.bshift) < (1 << 24));
+ ((vs->client_pf.rmax << vs->client_pf.rshift) < (1 << 24) &&
+ (vs->client_pf.gmax << vs->client_pf.gshift) < (1 << 24) &&
+ (vs->client_pf.bmax << vs->client_pf.bshift) < (1 << 24));
- fits_in_ms3bytes = (vs->clientds.pf.rshift > 7 &&
- vs->clientds.pf.gshift > 7 &&
- vs->clientds.pf.bshift > 7);
+ fits_in_ms3bytes = (vs->client_pf.rshift > 7 &&
+ vs->client_pf.gshift > 7 &&
+ vs->client_pf.bshift > 7);
if ((fits_in_ls3bytes && !be) || (fits_in_ms3bytes && be)) {
if (be) {
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index 087b84d..57c0916 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -33,21 +33,21 @@
/*
* Locking:
*
- * There is three levels of locking:
+ * There are three levels of locking:
* - jobs queue lock: for each operation on the queue (push, pop, isEmpty?)
* - VncDisplay global lock: mainly used for framebuffer updates to avoid
* screen corruption if the framebuffer is updated
- * while the worker is doing something.
+ * while the worker is doing something.
* - VncState::output lock: used to make sure the output buffer is not corrupted
- * if two threads try to write on it at the same time
+ * if two threads try to write on it at the same time
*
- * While the VNC worker thread is working, the VncDisplay global lock is hold
- * to avoid screen corruptions (this does not block vnc_refresh() because it
- * uses trylock()) but the output lock is not hold because the thread work on
+ * While the VNC worker thread is working, the VncDisplay global lock is held
+ * to avoid screen corruption (this does not block vnc_refresh() because it
+ * uses trylock()) but the output lock is not held because the thread works on
* its own output buffer.
* When the encoding job is done, the worker thread will hold the output lock
* and copy its output buffer in vs->output.
-*/
+ */
struct VncJobQueue {
QemuCond cond;
@@ -62,7 +62,7 @@ typedef struct VncJobQueue VncJobQueue;
/*
* We use a single global queue, but most of the functions are
- * already reetrant, so we can easilly add more than one encoding thread
+ * already reentrant, so we can easily add more than one encoding thread
*/
static VncJobQueue *queue;
@@ -187,7 +187,8 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
local->vd = orig->vd;
local->lossy_rect = orig->lossy_rect;
local->write_pixels = orig->write_pixels;
- local->clientds = orig->clientds;
+ local->client_pf = orig->client_pf;
+ local->client_be = orig->client_be;
local->tight = orig->tight;
local->zlib = orig->zlib;
local->hextile = orig->hextile;
@@ -320,6 +321,11 @@ static void *vnc_worker_thread(void *arg)
return NULL;
}
+static bool vnc_worker_thread_running(void)
+{
+ return queue; /* Check global queue */
+}
+
void vnc_start_worker_thread(void)
{
VncJobQueue *q;
@@ -332,11 +338,6 @@ void vnc_start_worker_thread(void)
queue = q; /* Set global queue */
}
-bool vnc_worker_thread_running(void)
-{
- return queue; /* Check global queue */
-}
-
void vnc_stop_worker_thread(void)
{
if (!vnc_worker_thread_running())
diff --git a/ui/vnc-jobs.h b/ui/vnc-jobs.h
index 86e6d88..31da103 100644
--- a/ui/vnc-jobs.h
+++ b/ui/vnc-jobs.h
@@ -40,7 +40,6 @@ void vnc_jobs_join(VncState *vs);
void vnc_jobs_consume_buffer(VncState *vs);
void vnc_start_worker_thread(void);
-bool vnc_worker_thread_running(void);
void vnc_stop_worker_thread(void);
/* Locks */
diff --git a/ui/vnc-palette.h b/ui/vnc-palette.h
index 3260885..b82dc5d 100644
--- a/ui/vnc-palette.h
+++ b/ui/vnc-palette.h
@@ -32,6 +32,7 @@
#include "qlist.h"
#include "qemu-queue.h"
#include <stdint.h>
+#include <stdbool.h>
#define VNC_PALETTE_HASH_SIZE 256
#define VNC_PALETTE_MAX_SIZE 256
diff --git a/ui/vnc-tls.c b/ui/vnc-tls.c
index 3aaa939..a7f7d07 100644
--- a/ui/vnc-tls.c
+++ b/ui/vnc-tls.c
@@ -49,7 +49,7 @@ static int vnc_tls_initialize(void)
if (gnutls_global_init () < 0)
return 0;
- /* XXX ought to re-generate diffie-hellmen params periodically */
+ /* XXX ought to re-generate diffie-hellman params periodically */
if (gnutls_dh_params_init (&dh_params) < 0)
return 0;
if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
diff --git a/ui/vnc.c b/ui/vnc.c
index 385e345..ba30362 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -372,6 +372,10 @@ VncInfo *qmp_query_vnc(Error **errp)
}
}
+ if (vnc_display->lsock == -1) {
+ return info;
+ }
+
if (getsockname(vnc_display->lsock, (struct sockaddr *)&sa,
&salen) == -1) {
error_set(errp, QERR_UNDEFINED_ERROR);
@@ -432,6 +436,8 @@ static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
int i;
VncDisplay *vd = ds->opaque;
struct VncSurface *s = &vd->guest;
+ int width = ds_get_width(ds);
+ int height = ds_get_height(ds);
h += y;
@@ -442,10 +448,10 @@ static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
w += (x % 16);
x -= (x % 16);
- x = MIN(x, s->ds->width);
- y = MIN(y, s->ds->height);
- w = MIN(x + w, s->ds->width) - x;
- h = MIN(h, s->ds->height);
+ x = MIN(x, width);
+ y = MIN(y, height);
+ w = MIN(x + w, width) - x;
+ h = MIN(h, height);
for (; y < h; y++)
for (i = 0; i < w; i += 16)
@@ -475,12 +481,12 @@ void buffer_reserve(Buffer *buffer, size_t len)
}
}
-int buffer_empty(Buffer *buffer)
+static int buffer_empty(Buffer *buffer)
{
return buffer->offset == 0;
}
-uint8_t *buffer_end(Buffer *buffer)
+static uint8_t *buffer_end(Buffer *buffer)
{
return buffer->buffer + buffer->offset;
}
@@ -546,6 +552,21 @@ static void vnc_abort_display_jobs(VncDisplay *vd)
}
}
+int vnc_server_fb_stride(VncDisplay *vd)
+{
+ return pixman_image_get_stride(vd->server);
+}
+
+void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y)
+{
+ uint8_t *ptr;
+
+ ptr = (uint8_t *)pixman_image_get_data(vd->server);
+ ptr += y * vnc_server_fb_stride(vd);
+ ptr += x * VNC_SERVER_FB_BYTES;
+ return ptr;
+}
+
static void vnc_dpy_resize(DisplayState *ds)
{
VncDisplay *vd = ds->opaque;
@@ -554,20 +575,20 @@ static void vnc_dpy_resize(DisplayState *ds)
vnc_abort_display_jobs(vd);
/* server surface */
- if (!vd->server)
- vd->server = g_malloc0(sizeof(*vd->server));
- if (vd->server->data)
- g_free(vd->server->data);
- *(vd->server) = *(ds->surface);
- vd->server->data = g_malloc0(vd->server->linesize *
- vd->server->height);
+ qemu_pixman_image_unref(vd->server);
+ vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
+ ds_get_width(ds),
+ ds_get_height(ds),
+ NULL, 0);
/* guest surface */
- if (!vd->guest.ds)
- vd->guest.ds = g_malloc0(sizeof(*vd->guest.ds));
+#if 0 /* FIXME */
if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
console_color_init(ds);
- *(vd->guest.ds) = *(ds->surface);
+#endif
+ qemu_pixman_image_unref(vd->guest.fb);
+ vd->guest.fb = pixman_image_ref(ds->surface->image);
+ vd->guest.format = ds->surface->format;
memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty));
QTAILQ_FOREACH(vs, &vd->clients, next) {
@@ -581,7 +602,7 @@ static void vnc_dpy_resize(DisplayState *ds)
}
/* fastest code */
-static void vnc_write_pixels_copy(VncState *vs, struct PixelFormat *pf,
+static void vnc_write_pixels_copy(VncState *vs,
void *pixels, int size)
{
vnc_write(vs, pixels, size);
@@ -591,23 +612,23 @@ static void vnc_write_pixels_copy(VncState *vs, struct PixelFormat *pf,
void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
{
uint8_t r, g, b;
- VncDisplay *vd = vs->vd;
- r = ((((v & vd->server->pf.rmask) >> vd->server->pf.rshift) << vs->clientds.pf.rbits) >>
- vd->server->pf.rbits);
- g = ((((v & vd->server->pf.gmask) >> vd->server->pf.gshift) << vs->clientds.pf.gbits) >>
- vd->server->pf.gbits);
- b = ((((v & vd->server->pf.bmask) >> vd->server->pf.bshift) << vs->clientds.pf.bbits) >>
- vd->server->pf.bbits);
- v = (r << vs->clientds.pf.rshift) |
- (g << vs->clientds.pf.gshift) |
- (b << vs->clientds.pf.bshift);
- switch(vs->clientds.pf.bytes_per_pixel) {
+#if VNC_SERVER_FB_FORMAT == PIXMAN_FORMAT(32, PIXMAN_TYPE_ARGB, 0, 8, 8, 8)
+ r = (((v & 0x00ff0000) >> 16) << vs->client_pf.rbits) >> 8;
+ g = (((v & 0x0000ff00) >> 8) << vs->client_pf.gbits) >> 8;
+ b = (((v & 0x000000ff) >> 0) << vs->client_pf.bbits) >> 8;
+#else
+# error need some bits here if you change VNC_SERVER_FB_FORMAT
+#endif
+ v = (r << vs->client_pf.rshift) |
+ (g << vs->client_pf.gshift) |
+ (b << vs->client_pf.bshift);
+ switch (vs->client_pf.bytes_per_pixel) {
case 1:
buf[0] = v;
break;
case 2:
- if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
+ if (vs->client_be) {
buf[0] = v >> 8;
buf[1] = v;
} else {
@@ -617,7 +638,7 @@ void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
break;
default:
case 4:
- if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) {
+ if (vs->client_be) {
buf[0] = v >> 24;
buf[1] = v >> 16;
buf[2] = v >> 8;
@@ -632,37 +653,19 @@ void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
}
}
-static void vnc_write_pixels_generic(VncState *vs, struct PixelFormat *pf,
+static void vnc_write_pixels_generic(VncState *vs,
void *pixels1, int size)
{
uint8_t buf[4];
- if (pf->bytes_per_pixel == 4) {
+ if (VNC_SERVER_FB_BYTES == 4) {
uint32_t *pixels = pixels1;
int n, i;
n = size >> 2;
- for(i = 0; i < n; i++) {
+ for (i = 0; i < n; i++) {
vnc_convert_pixel(vs, buf, pixels[i]);
- vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
+ vnc_write(vs, buf, vs->client_pf.bytes_per_pixel);
}
- } else if (pf->bytes_per_pixel == 2) {
- uint16_t *pixels = pixels1;
- int n, i;
- n = size >> 1;
- for(i = 0; i < n; i++) {
- vnc_convert_pixel(vs, buf, pixels[i]);
- vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
- }
- } else if (pf->bytes_per_pixel == 1) {
- uint8_t *pixels = pixels1;
- int n, i;
- n = size;
- for(i = 0; i < n; i++) {
- vnc_convert_pixel(vs, buf, pixels[i]);
- vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
- }
- } else {
- fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n");
}
}
@@ -672,10 +675,10 @@ int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
uint8_t *row;
VncDisplay *vd = vs->vd;
- row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
+ row = vnc_server_fb_ptr(vd, x, y);
for (i = 0; i < h; i++) {
- vs->write_pixels(vs, &vd->server->pf, row, w * ds_get_bytes_per_pixel(vs->ds));
- row += ds_get_linesize(vs->ds);
+ vs->write_pixels(vs, row, w * VNC_SERVER_FB_BYTES);
+ row += vnc_server_fb_stride(vd);
}
return 1;
}
@@ -732,7 +735,7 @@ static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int
VncState *vs, *vn;
uint8_t *src_row;
uint8_t *dst_row;
- int i,x,y,pitch,depth,inc,w_lim,s;
+ int i, x, y, pitch, inc, w_lim, s;
int cmp_bytes;
vnc_refresh_server_surface(vd);
@@ -745,10 +748,9 @@ static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int
}
/* do bitblit op on the local surface too */
- pitch = ds_get_linesize(vd->ds);
- depth = ds_get_bytes_per_pixel(vd->ds);
- src_row = vd->server->data + pitch * src_y + depth * src_x;
- dst_row = vd->server->data + pitch * dst_y + depth * dst_x;
+ pitch = vnc_server_fb_stride(vd);
+ src_row = vnc_server_fb_ptr(vd, src_x, src_y);
+ dst_row = vnc_server_fb_ptr(vd, dst_x, dst_y);
y = dst_y;
inc = 1;
if (dst_y > src_y) {
@@ -776,7 +778,7 @@ static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int
} else {
s = 16;
}
- cmp_bytes = s * depth;
+ cmp_bytes = s * VNC_SERVER_FB_BYTES;
if (memcmp(src_row, dst_row, cmp_bytes) == 0)
continue;
memmove(dst_row, src_row, cmp_bytes);
@@ -786,8 +788,8 @@ static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int
}
}
}
- src_row += pitch - w * depth;
- dst_row += pitch - w * depth;
+ src_row += pitch - w * VNC_SERVER_FB_BYTES;
+ dst_row += pitch - w * VNC_SERVER_FB_BYTES;
y += inc;
}
@@ -798,7 +800,7 @@ static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int
}
}
-static void vnc_mouse_set(int x, int y, int visible)
+static void vnc_mouse_set(DisplayState *ds, int x, int y, int visible)
{
/* can we ask the client(s) to move the pointer ??? */
}
@@ -806,7 +808,6 @@ static void vnc_mouse_set(int x, int y, int visible)
static int vnc_cursor_define(VncState *vs)
{
QEMUCursor *c = vs->vd->cursor;
- PixelFormat pf = qemu_default_pixelformat(32);
int isize;
if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) {
@@ -816,8 +817,8 @@ static int vnc_cursor_define(VncState *vs)
vnc_write_u16(vs, 1); /* # of rects */
vnc_framebuffer_update(vs, c->hot_x, c->hot_y, c->width, c->height,
VNC_ENCODING_RICH_CURSOR);
- isize = c->width * c->height * vs->clientds.pf.bytes_per_pixel;
- vnc_write_pixels_generic(vs, &pf, c->data, isize);
+ isize = c->width * c->height * vs->client_pf.bytes_per_pixel;
+ vnc_write_pixels_generic(vs, c->data, isize);
vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize);
vnc_unlock_output(vs);
return 0;
@@ -825,7 +826,7 @@ static int vnc_cursor_define(VncState *vs)
return -1;
}
-static void vnc_dpy_cursor_define(QEMUCursor *c)
+static void vnc_dpy_cursor_define(DisplayState *ds, QEMUCursor *c)
{
VncDisplay *vd = vnc_display;
VncState *vs;
@@ -894,8 +895,8 @@ static int vnc_update_client(VncState *vs, int has_dirty)
*/
job = vnc_job_new(vs);
- width = MIN(vd->server->width, vs->client_width);
- height = MIN(vd->server->height, vs->client_height);
+ width = MIN(pixman_image_get_width(vd->server), vs->client_width);
+ height = MIN(pixman_image_get_height(vd->server), vs->client_height);
for (y = 0; y < height; y++) {
int x;
@@ -1372,17 +1373,17 @@ void vnc_flush(VncState *vs)
vnc_unlock_output(vs);
}
-uint8_t read_u8(uint8_t *data, size_t offset)
+static uint8_t read_u8(uint8_t *data, size_t offset)
{
return data[offset];
}
-uint16_t read_u16(uint8_t *data, size_t offset)
+static uint16_t read_u16(uint8_t *data, size_t offset)
{
return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF);
}
-int32_t read_s32(uint8_t *data, size_t offset)
+static int32_t read_s32(uint8_t *data, size_t offset)
{
return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) |
(data[offset + 2] << 8) | data[offset + 3]);
@@ -1802,10 +1803,12 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
vs->features |= VNC_FEATURE_TIGHT_MASK;
vs->vnc_encoding = enc;
break;
+#ifdef CONFIG_VNC_PNG
case VNC_ENCODING_TIGHT_PNG:
vs->features |= VNC_FEATURE_TIGHT_PNG_MASK;
vs->vnc_encoding = enc;
break;
+#endif
case VNC_ENCODING_ZLIB:
vs->features |= VNC_FEATURE_ZLIB_MASK;
vs->vnc_encoding = enc;
@@ -1855,9 +1858,9 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
static void set_pixel_conversion(VncState *vs)
{
- if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) ==
- (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) &&
- !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) {
+ pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf);
+
+ if (fmt == VNC_SERVER_FB_FORMAT) {
vs->write_pixels = vnc_write_pixels_copy;
vnc_hextile_set_pixel_conversion(vs, 0);
} else {
@@ -1877,23 +1880,22 @@ static void set_pixel_format(VncState *vs,
return;
}
- vs->clientds = *(vs->vd->guest.ds);
- vs->clientds.pf.rmax = red_max;
- vs->clientds.pf.rbits = hweight_long(red_max);
- vs->clientds.pf.rshift = red_shift;
- vs->clientds.pf.rmask = red_max << red_shift;
- vs->clientds.pf.gmax = green_max;
- vs->clientds.pf.gbits = hweight_long(green_max);
- vs->clientds.pf.gshift = green_shift;
- vs->clientds.pf.gmask = green_max << green_shift;
- vs->clientds.pf.bmax = blue_max;
- vs->clientds.pf.bbits = hweight_long(blue_max);
- vs->clientds.pf.bshift = blue_shift;
- vs->clientds.pf.bmask = blue_max << blue_shift;
- vs->clientds.pf.bits_per_pixel = bits_per_pixel;
- vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8;
- vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
- vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00;
+ vs->client_pf.rmax = red_max;
+ vs->client_pf.rbits = hweight_long(red_max);
+ vs->client_pf.rshift = red_shift;
+ vs->client_pf.rmask = red_max << red_shift;
+ vs->client_pf.gmax = green_max;
+ vs->client_pf.gbits = hweight_long(green_max);
+ vs->client_pf.gshift = green_shift;
+ vs->client_pf.gmask = green_max << green_shift;
+ vs->client_pf.bmax = blue_max;
+ vs->client_pf.bbits = hweight_long(blue_max);
+ vs->client_pf.bshift = blue_shift;
+ vs->client_pf.bmask = blue_max << blue_shift;
+ vs->client_pf.bits_per_pixel = bits_per_pixel;
+ vs->client_pf.bytes_per_pixel = bits_per_pixel / 8;
+ vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
+ vs->client_be = big_endian_flag;
set_pixel_conversion(vs);
@@ -1904,8 +1906,10 @@ static void set_pixel_format(VncState *vs,
static void pixel_format_message (VncState *vs) {
char pad[3] = { 0, 0, 0 };
- vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */
- vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */
+ vs->client_pf = qemu_default_pixelformat(32);
+
+ vnc_write_u8(vs, vs->client_pf.bits_per_pixel); /* bits-per-pixel */
+ vnc_write_u8(vs, vs->client_pf.depth); /* depth */
#ifdef HOST_WORDS_BIGENDIAN
vnc_write_u8(vs, 1); /* big-endian-flag */
@@ -1913,27 +1917,25 @@ static void pixel_format_message (VncState *vs) {
vnc_write_u8(vs, 0); /* big-endian-flag */
#endif
vnc_write_u8(vs, 1); /* true-color-flag */
- vnc_write_u16(vs, vs->ds->surface->pf.rmax); /* red-max */
- vnc_write_u16(vs, vs->ds->surface->pf.gmax); /* green-max */
- vnc_write_u16(vs, vs->ds->surface->pf.bmax); /* blue-max */
- vnc_write_u8(vs, vs->ds->surface->pf.rshift); /* red-shift */
- vnc_write_u8(vs, vs->ds->surface->pf.gshift); /* green-shift */
- vnc_write_u8(vs, vs->ds->surface->pf.bshift); /* blue-shift */
+ vnc_write_u16(vs, vs->client_pf.rmax); /* red-max */
+ vnc_write_u16(vs, vs->client_pf.gmax); /* green-max */
+ vnc_write_u16(vs, vs->client_pf.bmax); /* blue-max */
+ vnc_write_u8(vs, vs->client_pf.rshift); /* red-shift */
+ vnc_write_u8(vs, vs->client_pf.gshift); /* green-shift */
+ vnc_write_u8(vs, vs->client_pf.bshift); /* blue-shift */
+ vnc_write(vs, pad, 3); /* padding */
vnc_hextile_set_pixel_conversion(vs, 0);
-
- vs->clientds = *(vs->ds->surface);
- vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG;
vs->write_pixels = vnc_write_pixels_copy;
-
- vnc_write(vs, pad, 3); /* padding */
}
static void vnc_dpy_setdata(DisplayState *ds)
{
VncDisplay *vd = ds->opaque;
- *(vd->guest.ds) = *(ds->surface);
+ qemu_pixman_image_unref(vd->guest.fb);
+ vd->guest.fb = pixman_image_ref(ds->surface->image);
+ vd->guest.format = ds->surface->format;
vnc_dpy_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds));
}
@@ -2437,12 +2439,14 @@ static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
static int vnc_update_stats(VncDisplay *vd, struct timeval * tv)
{
+ int width = pixman_image_get_width(vd->guest.fb);
+ int height = pixman_image_get_height(vd->guest.fb);
int x, y;
struct timeval res;
int has_dirty = 0;
- for (y = 0; y < vd->guest.ds->height; y += VNC_STAT_RECT) {
- for (x = 0; x < vd->guest.ds->width; x += VNC_STAT_RECT) {
+ for (y = 0; y < height; y += VNC_STAT_RECT) {
+ for (x = 0; x < width; x += VNC_STAT_RECT) {
VncRectStat *rect = vnc_stat_rect(vd, x, y);
rect->updated = false;
@@ -2456,8 +2460,8 @@ static int vnc_update_stats(VncDisplay *vd, struct timeval * tv)
}
vd->guest.last_freq_check = *tv;
- for (y = 0; y < vd->guest.ds->height; y += VNC_STAT_RECT) {
- for (x = 0; x < vd->guest.ds->width; x += VNC_STAT_RECT) {
+ for (y = 0; y < height; y += VNC_STAT_RECT) {
+ for (x = 0; x < width; x += VNC_STAT_RECT) {
VncRectStat *rect= vnc_stat_rect(vd, x, y);
int count = ARRAY_SIZE(rect->times);
struct timeval min, max;
@@ -2526,12 +2530,15 @@ static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv)
static int vnc_refresh_server_surface(VncDisplay *vd)
{
+ int width = pixman_image_get_width(vd->guest.fb);
+ int height = pixman_image_get_height(vd->guest.fb);
int y;
uint8_t *guest_row;
uint8_t *server_row;
int cmp_bytes;
VncState *vs;
int has_dirty = 0;
+ pixman_image_t *tmpbuf = NULL;
struct timeval tv = { 0, 0 };
@@ -2545,22 +2552,31 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
* Check and copy modified bits from guest to server surface.
* Update server dirty map.
*/
- cmp_bytes = 16 * ds_get_bytes_per_pixel(vd->ds);
- if (cmp_bytes > vd->ds->surface->linesize) {
- cmp_bytes = vd->ds->surface->linesize;
+ cmp_bytes = 64;
+ if (cmp_bytes > vnc_server_fb_stride(vd)) {
+ cmp_bytes = vnc_server_fb_stride(vd);
+ }
+ if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
+ int width = pixman_image_get_width(vd->server);
+ tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width);
}
- guest_row = vd->guest.ds->data;
- server_row = vd->server->data;
- for (y = 0; y < vd->guest.ds->height; y++) {
+ guest_row = (uint8_t *)pixman_image_get_data(vd->guest.fb);
+ server_row = (uint8_t *)pixman_image_get_data(vd->server);
+ for (y = 0; y < height; y++) {
if (!bitmap_empty(vd->guest.dirty[y], VNC_DIRTY_BITS)) {
int x;
uint8_t *guest_ptr;
uint8_t *server_ptr;
- guest_ptr = guest_row;
+ if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
+ qemu_pixman_linebuf_fill(tmpbuf, vd->guest.fb, width, y);
+ guest_ptr = (uint8_t *)pixman_image_get_data(tmpbuf);
+ } else {
+ guest_ptr = guest_row;
+ }
server_ptr = server_row;
- for (x = 0; x + 15 < vd->guest.ds->width;
+ for (x = 0; x + 15 < width;
x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
if (!test_and_clear_bit((x / 16), vd->guest.dirty[y]))
continue;
@@ -2575,9 +2591,10 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
has_dirty++;
}
}
- guest_row += ds_get_linesize(vd->ds);
- server_row += ds_get_linesize(vd->ds);
+ guest_row += pixman_image_get_stride(vd->guest.fb);
+ server_row += pixman_image_get_stride(vd->server);
}
+ qemu_pixman_image_unref(tmpbuf);
return has_dirty;
}
@@ -2747,17 +2764,17 @@ void vnc_display_init(DisplayState *ds)
qemu_mutex_init(&vs->mutex);
vnc_start_worker_thread();
- dcl->dpy_copy = vnc_dpy_copy;
- dcl->dpy_update = vnc_dpy_update;
- dcl->dpy_resize = vnc_dpy_resize;
- dcl->dpy_setdata = vnc_dpy_setdata;
+ dcl->dpy_gfx_copy = vnc_dpy_copy;
+ dcl->dpy_gfx_update = vnc_dpy_update;
+ dcl->dpy_gfx_resize = vnc_dpy_resize;
+ dcl->dpy_gfx_setdata = vnc_dpy_setdata;
+ dcl->dpy_mouse_set = vnc_mouse_set;
+ dcl->dpy_cursor_define = vnc_dpy_cursor_define;
register_displaychangelistener(ds, dcl);
- ds->mouse_set = vnc_mouse_set;
- ds->cursor_define = vnc_dpy_cursor_define;
}
-void vnc_display_close(DisplayState *ds)
+static void vnc_display_close(DisplayState *ds)
{
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
@@ -2779,7 +2796,7 @@ void vnc_display_close(DisplayState *ds)
#endif
}
-int vnc_display_disable_login(DisplayState *ds)
+static int vnc_display_disable_login(DisplayState *ds)
{
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
@@ -2844,7 +2861,7 @@ char *vnc_display_local_addr(DisplayState *ds)
return vnc_socket_local_addr("%s:%s", vs->lsock);
}
-int vnc_display_open(DisplayState *ds, const char *display)
+void vnc_display_open(DisplayState *ds, const char *display, Error **errp)
{
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
const char *options;
@@ -2862,14 +2879,15 @@ int vnc_display_open(DisplayState *ds, const char *display)
#endif
int lock_key_sync = 1;
- if (!vnc_display)
- return -1;
+ if (!vnc_display) {
+ error_setg(errp, "VNC display not active");
+ return;
+ }
vnc_display_close(ds);
if (strcmp(display, "none") == 0)
- return 0;
+ return;
- if (!(vs->display = strdup(display)))
- return -1;
+ vs->display = g_strdup(display);
vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
options = display;
@@ -2877,13 +2895,11 @@ int vnc_display_open(DisplayState *ds, const char *display)
options++;
if (strncmp(options, "password", 8) == 0) {
if (fips_get_state()) {
- fprintf(stderr,
- "VNC password auth disabled due to FIPS mode, "
- "consider using the VeNCrypt or SASL authentication "
- "methods as an alternative\n");
- g_free(vs->display);
- vs->display = NULL;
- return -1;
+ error_setg(errp,
+ "VNC password auth disabled due to FIPS mode, "
+ "consider using the VeNCrypt or SASL authentication "
+ "methods as an alternative");
+ goto fail;
}
password = 1; /* Require password auth */
} else if (strncmp(options, "reverse", 7) == 0) {
@@ -2913,18 +2929,14 @@ int vnc_display_open(DisplayState *ds, const char *display)
VNC_DEBUG("Trying certificate path '%s'\n", path);
if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
- fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
+ error_setg(errp, "Failed to find x509 certificates/keys in %s", path);
g_free(path);
- g_free(vs->display);
- vs->display = NULL;
- return -1;
+ goto fail;
}
g_free(path);
} else {
- fprintf(stderr, "No certificate path provided\n");
- g_free(vs->display);
- vs->display = NULL;
- return -1;
+ error_setg(errp, "No certificate path provided");
+ goto fail;
}
#endif
#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
@@ -2933,7 +2945,7 @@ int vnc_display_open(DisplayState *ds, const char *display)
#endif
} else if (strncmp(options, "lossy", 5) == 0) {
vs->lossy = true;
- } else if (strncmp(options, "non-adapative", 13) == 0) {
+ } else if (strncmp(options, "non-adaptive", 12) == 0) {
vs->non_adaptive = true;
} else if (strncmp(options, "share=", 6) == 0) {
if (strncmp(options+6, "ignore", 6) == 0) {
@@ -2943,10 +2955,8 @@ int vnc_display_open(DisplayState *ds, const char *display)
} else if (strncmp(options+6, "force-shared", 12) == 0) {
vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
} else {
- fprintf(stderr, "unknown vnc share= option\n");
- g_free(vs->display);
- vs->display = NULL;
- return -1;
+ error_setg(errp, "unknown vnc share= option");
+ goto fail;
}
}
}
@@ -3047,52 +3057,50 @@ int vnc_display_open(DisplayState *ds, const char *display)
#ifdef CONFIG_VNC_SASL
if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) {
- fprintf(stderr, "Failed to initialize SASL auth %s",
- sasl_errstring(saslErr, NULL, NULL));
- g_free(vs->display);
- vs->display = NULL;
- return -1;
+ error_setg(errp, "Failed to initialize SASL auth: %s",
+ sasl_errstring(saslErr, NULL, NULL));
+ goto fail;
}
#endif
vs->lock_key_sync = lock_key_sync;
if (reverse) {
/* connect to viewer */
- if (strncmp(display, "unix:", 5) == 0)
- vs->lsock = unix_connect(display+5);
- else
- vs->lsock = inet_connect(display, true, NULL, NULL);
- if (-1 == vs->lsock) {
- g_free(vs->display);
- vs->display = NULL;
- return -1;
+ int csock;
+ vs->lsock = -1;
+ if (strncmp(display, "unix:", 5) == 0) {
+ csock = unix_connect(display+5, errp);
} else {
- int csock = vs->lsock;
- vs->lsock = -1;
- vnc_connect(vs, csock, 0);
+ csock = inet_connect(display, errp);
}
- return 0;
-
+ if (csock < 0) {
+ goto fail;
+ }
+ vnc_connect(vs, csock, 0);
} else {
/* listen for connects */
char *dpy;
dpy = g_malloc(256);
if (strncmp(display, "unix:", 5) == 0) {
pstrcpy(dpy, 256, "unix:");
- vs->lsock = unix_listen(display+5, dpy+5, 256-5);
+ vs->lsock = unix_listen(display+5, dpy+5, 256-5, errp);
} else {
vs->lsock = inet_listen(display, dpy, 256,
- SOCK_STREAM, 5900, NULL);
+ SOCK_STREAM, 5900, errp);
}
- if (-1 == vs->lsock) {
+ if (vs->lsock < 0) {
g_free(dpy);
- return -1;
- } else {
- g_free(vs->display);
- vs->display = dpy;
+ goto fail;
}
+ g_free(vs->display);
+ vs->display = dpy;
+ qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
}
- return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
+ return;
+
+fail:
+ g_free(vs->display);
+ vs->display = NULL;
}
void vnc_display_add_client(DisplayState *ds, int csock, int skipauth)
diff --git a/ui/vnc.h b/ui/vnc.h
index 068c2fc..6141e88 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -69,7 +69,7 @@ typedef struct VncRectEntry VncRectEntry;
typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
-typedef void VncWritePixels(VncState *vs, struct PixelFormat *pf, void *data, int size);
+typedef void VncWritePixels(VncState *vs, void *data, int size);
typedef void VncSendHextileTile(VncState *vs,
int x, int y, int w, int h,
@@ -117,7 +117,8 @@ struct VncSurface
struct timeval last_freq_check;
DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], VNC_MAX_WIDTH / 16);
VncRectStat stats[VNC_STAT_ROWS][VNC_STAT_COLS];
- DisplaySurface *ds;
+ pixman_image_t *fb;
+ pixman_format_code_t format;
};
typedef enum VncShareMode {
@@ -151,7 +152,7 @@ struct VncDisplay
uint8_t *cursor_mask;
struct VncSurface guest; /* guest visible surface (aka ds->surface) */
- DisplaySurface *server; /* vnc server surface */
+ pixman_image_t *server; /* vnc server surface */
char *display;
char *password;
@@ -275,7 +276,9 @@ struct VncState
Buffer input;
/* current output mode information */
VncWritePixels *write_pixels;
- DisplaySurface clientds;
+ PixelFormat client_pf;
+ pixman_format_code_t client_format;
+ bool client_be;
CaptureVoiceOut *audio_cap;
struct audsettings as;
@@ -493,9 +496,6 @@ void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting);
/* Buffer I/O functions */
-uint8_t read_u8(uint8_t *data, size_t offset);
-uint16_t read_u16(uint8_t *data, size_t offset);
-int32_t read_s32(uint8_t *data, size_t offset);
uint32_t read_u32(uint8_t *data, size_t offset);
/* Protocol stage functions */
@@ -507,8 +507,6 @@ void start_auth_vnc(VncState *vs);
/* Buffer management */
void buffer_reserve(Buffer *buffer, size_t len);
-int buffer_empty(Buffer *buffer);
-uint8_t *buffer_end(Buffer *buffer);
void buffer_reset(Buffer *buffer);
void buffer_free(Buffer *buffer);
void buffer_append(Buffer *buffer, const void *data, size_t len);
@@ -527,6 +525,14 @@ static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
int32_t encoding);
+/* server fb is in PIXMAN_x8r8g8b8 */
+#define VNC_SERVER_FB_FORMAT PIXMAN_FORMAT(32, PIXMAN_TYPE_ARGB, 0, 8, 8, 8)
+#define VNC_SERVER_FB_BITS (PIXMAN_FORMAT_BPP(VNC_SERVER_FB_FORMAT))
+#define VNC_SERVER_FB_BYTES ((VNC_SERVER_FB_BITS+7)/8)
+
+void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y);
+int vnc_server_fb_stride(VncDisplay *vd);
+
void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v);
double vnc_update_freq(VncState *vs, int x, int y, int w, int h);
void vnc_sent_lossy_rect(VncState *vs, int x, int y, int w, int h);