All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13
@ 2010-07-07 18:57 Corentin Chary
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 01/18] vnc: tight: add JPEG and gradient subencoding with smooth image detection Corentin Chary
                   ` (18 more replies)
  0 siblings, 19 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

This set contains all my patchs related to tight and threaded vnc server.

Since v1:
* Add a fix for jpeg and png with non-24bpp displays
* Better default values for vnc options in ./configure
* Fixed Tight PNG to use its own encoding number (-260)
* Cleaned tight send_sub_rect()

Tight JPEG and Move to ui
=========================
This set starts by adding JPEG and gradient to tight, then move all ui code
in the ui/ subdirectory.
Thanks,

Since v1:
* Format patch with rename detection
* Add "lossy" parameter instead of "lossless"
* Disable lossy encodings by default
* Add a small tight fix (for indexed colors)

Since v2:
* Rebased on current master
* Removed a leak in send_jpeg_rect()

Misc
=======
* Add the missing last color while filling palette
* Rewrite the palette code without using qdict. I did some profiling using `perf`
  and a lot of cpu time was spent in qdict, mainly due to memory allocation, hash, and
  qobject conversion. The new code is faster and uses less memory.

Tight PNG
==========
This set introduce a new encoding: VNC_ENCODING_TIGHT_PNG [1] (-260) and a new
tight filter VNC_TIGHT_PNG (0x0A). When the client tells it supports the -260
encoding, the server will use tight, but will always send encoding pixels using
PNG instead of zlib. If the client also told it support JPEG, then the server can
send JPEG, because PNG will only be used in the cases zlib was used in normal tight.

This encoding was introduced to speed up HTML5 based VNC clients like noVNC [2], but
can also be used on devices like iPhone where PNG can be rendered in hardware.

I also made a quick patch to add support for PNG in gtk-vnc [3] and noVNC already support
PNG encoding. Note: There is a bug in gtk-vnc when using pixbuf on a 16bit display,
which also happens with JPEG.

[1] http://wiki.qemu.org/VNC_Tight_PNG
[2] http://github.com/kanaka/noVNC/
[3] http://xf.iksaif.net/dev/vnc/gtk-vnc/0001-add-png-support.patch

Threaded Server
===============

Since v1:
* Moved locks from VncState to VncDisplay because it's only used in vnc_refresh
* Use trylock in vnc_refresh. If there is an encoding task still running, reschedule the refresh.
 This really boost performances and make the vnc server truly asynchroneous. The only blocking
 lock is the output_mutex which is only held during a simple memcpy().
* Fixed issues found by Paolo, except the exit condition, mainly because we can only have
 one queue per VncState (due to zstreams), so this is not really an issue.
* Rebased on top of jpeg and ui/ patchs

Since v2:
* renamed vnc-jobs.c vnc-jobs-async.c
* added vnc-jobs.h, refactor functions declarations, export vnc_[un]lock_display()
 and vnc_[un]lock_output() and use them in vnc-jobs-async.c (reported by Avi)
* rework exit condition for vnc_worker_thread_loop (Paolo)
* abord -> abort (Paolo)
* call qemu_thread_self() (Paolo)
* Coding style issues (Alexander)
* Move from empty macros to empty statis inline (Alexander)

Alexander also suggested me to use stw_be_p() defined in cpu-all.h,
but when I tried to include cpu-all.h, it broke every thing. Anyway it can
be done later since this code is already present in vnc.c.

Also vnc_async_encoding_start() could be cleaner if encoding members where
in a specific structure, but this is a lot of changes, and as I'm also working
on encodings, I want this patch to be easy to rebase. So I'll do as soon as
the VNC server is merged.

Since v3:
* Encoding are data is now in specific structures, that makes
  vnc_async_encoding_start a lot cleaner.
* Added a missing vnc_output_lock(vs)

Corentin Chary (18):
  vnc: tight: add JPEG and gradient subencoding with smooth image
    detection
  vnc: JPEG should be disabled if the client don't set tight quality
  vnc: add lossy option
  ui: move all ui components in ui/
  vnc: rename vnc-encoding-* vnc-enc-*
  vnc: tight: don't forget do at the last color
  vnc: tight: remove a memleak in send_jpeg_rect()
  vnc: tight add PNG encoding
  vnc: tight: specific zlib level and filters for each compression
    level
  vnc: tight: stop using qdict for palette stuff
  vnc: encapsulate encoding members
  vnc: fix tight png memory leak
  qemu-thread: add qemu_mutex/cond_destroy and qemu_mutex_exit
  vnc: threaded VNC server
  vnc: add missing lock for vnc_cursor_define()
  vnc: tight: fix rgb_prepare_row
  vnc: tight: split send_sub_rect
  vnc: better default values for VNC options

 Makefile                                       |   38 +-
 Makefile.objs                                  |   29 +-
 Makefile.target                                |    2 +
 configure                                      |   83 ++
 qemu-options.hx                                |    7 +
 qemu-thread.c                                  |   22 +
 qemu-thread.h                                  |    4 +
 cocoa.m => ui/cocoa.m                          |    0
 curses.c => ui/curses.c                        |    0
 curses_keys.h => ui/curses_keys.h              |    0
 d3des.c => ui/d3des.c                          |    0
 d3des.h => ui/d3des.h                          |    0
 keymaps.c => ui/keymaps.c                      |    0
 keymaps.h => ui/keymaps.h                      |    0
 sdl.c => ui/sdl.c                              |    0
 sdl_keysym.h => ui/sdl_keysym.h                |    0
 sdl_zoom.c => ui/sdl_zoom.c                    |    0
 sdl_zoom.h => ui/sdl_zoom.h                    |    0
 sdl_zoom_template.h => ui/sdl_zoom_template.h  |    0
 vnc-auth-sasl.c => ui/vnc-auth-sasl.c          |    0
 vnc-auth-sasl.h => ui/vnc-auth-sasl.h          |    0
 vnc-auth-vencrypt.c => ui/vnc-auth-vencrypt.c  |    0
 vnc-auth-vencrypt.h => ui/vnc-auth-vencrypt.h  |    0
 vnchextile.h => ui/vnc-enc-hextile-template.h  |    0
 vnc-encoding-hextile.c => ui/vnc-enc-hextile.c |   26 +-
 ui/vnc-enc-tight.c                             | 1715 ++++++++++++++++++++++++
 vnc-encoding-tight.h => ui/vnc-enc-tight.h     |   21 +-
 vnc-encoding-zlib.c => ui/vnc-enc-zlib.c       |   34 +-
 ui/vnc-jobs-async.c                            |  331 +++++
 vnc-tls.h => ui/vnc-jobs-sync.c                |   99 +-
 ui/vnc-jobs.h                                  |   87 ++
 ui/vnc-palette.c                               |  136 ++
 ui/vnc-palette.h                               |   63 +
 vnc-tls.c => ui/vnc-tls.c                      |    0
 vnc-tls.h => ui/vnc-tls.h                      |    0
 vnc.c => ui/vnc.c                              |  167 ++-
 vnc.h => ui/vnc.h                              |  115 ++-
 vnc_keysym.h => ui/vnc_keysym.h                |    0
 x_keymap.c => ui/x_keymap.c                    |    0
 x_keymap.h => ui/x_keymap.h                    |    0
 vnc-encoding-tight.c                           |  959 -------------
 41 files changed, 2796 insertions(+), 1142 deletions(-)
 rename cocoa.m => ui/cocoa.m (100%)
 rename curses.c => ui/curses.c (100%)
 rename curses_keys.h => ui/curses_keys.h (100%)
 rename d3des.c => ui/d3des.c (100%)
 rename d3des.h => ui/d3des.h (100%)
 rename keymaps.c => ui/keymaps.c (100%)
 rename keymaps.h => ui/keymaps.h (100%)
 rename sdl.c => ui/sdl.c (100%)
 rename sdl_keysym.h => ui/sdl_keysym.h (100%)
 rename sdl_zoom.c => ui/sdl_zoom.c (100%)
 rename sdl_zoom.h => ui/sdl_zoom.h (100%)
 rename sdl_zoom_template.h => ui/sdl_zoom_template.h (100%)
 rename vnc-auth-sasl.c => ui/vnc-auth-sasl.c (100%)
 rename vnc-auth-sasl.h => ui/vnc-auth-sasl.h (100%)
 rename vnc-auth-vencrypt.c => ui/vnc-auth-vencrypt.c (100%)
 rename vnc-auth-vencrypt.h => ui/vnc-auth-vencrypt.h (100%)
 rename vnchextile.h => ui/vnc-enc-hextile-template.h (100%)
 rename vnc-encoding-hextile.c => ui/vnc-enc-hextile.c (81%)
 create mode 100644 ui/vnc-enc-tight.c
 rename vnc-encoding-tight.h => ui/vnc-enc-tight.h (92%)
 rename vnc-encoding-zlib.c => ui/vnc-enc-zlib.c (83%)
 create mode 100644 ui/vnc-jobs-async.c
 copy vnc-tls.h => ui/vnc-jobs-sync.c (54%)
 create mode 100644 ui/vnc-jobs.h
 create mode 100644 ui/vnc-palette.c
 create mode 100644 ui/vnc-palette.h
 rename vnc-tls.c => ui/vnc-tls.c (100%)
 rename vnc-tls.h => ui/vnc-tls.h (100%)
 rename vnc.c => ui/vnc.c (95%)
 rename vnc.h => ui/vnc.h (87%)
 rename vnc_keysym.h => ui/vnc_keysym.h (100%)
 rename x_keymap.c => ui/x_keymap.c (100%)
 rename x_keymap.h => ui/x_keymap.h (100%)
 delete mode 100644 vnc-encoding-tight.c

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 01/18] vnc: tight: add JPEG and gradient subencoding with smooth image detection
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
@ 2010-07-07 18:57 ` Corentin Chary
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 02/18] vnc: JPEG should be disabled if the client don't set tight quality Corentin Chary
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

Add gradient filter and JPEG compression with an heuristic to detect how
lossy the comppression will be. This code has been adapted from
libvncserver/tight.c.

JPEG support can be enabled/disabled at compile time with --enable-vnc-jpeg
and --disable-vnc-jpeg.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 Makefile.target      |    1 +
 configure            |   33 +++
 vnc-encoding-tight.c |  559 +++++++++++++++++++++++++++++++++++++++++++++++++-
 vnc-encoding-tight.h |    5 +
 vnc.h                |    4 +
 5 files changed, 601 insertions(+), 1 deletions(-)

diff --git a/Makefile.target b/Makefile.target
index 7489910..eb801df 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -177,6 +177,7 @@ LIBS+=-lz
 
 QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
+QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
 
 # xen backend driver support
 obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
diff --git a/configure b/configure
index b68f01a..27791b5 100755
--- a/configure
+++ b/configure
@@ -268,6 +268,7 @@ uuid=""
 vde=""
 vnc_tls=""
 vnc_sasl=""
+vnc_jpeg=""
 xen=""
 linux_aio=""
 attr=""
@@ -575,6 +576,10 @@ for opt do
   ;;
   --enable-vnc-sasl) vnc_sasl="yes"
   ;;
+  --disable-vnc-jpeg) vnc_jpeg="no"
+  ;;
+  --enable-vnc-jpeg) vnc_jpeg="yes"
+  ;;
   --disable-slirp) slirp="no"
   ;;
   --disable-uuid) uuid="no"
@@ -825,6 +830,8 @@ echo "  --disable-vnc-tls        disable TLS encryption for VNC server"
 echo "  --enable-vnc-tls         enable TLS encryption for VNC server"
 echo "  --disable-vnc-sasl       disable SASL encryption for VNC server"
 echo "  --enable-vnc-sasl        enable SASL encryption for VNC server"
+echo "  --disable-vnc-jpeg       disable JPEG lossy compression for VNC server"
+echo "  --enable-vnc-jpeg        enable JPEG lossy compression for VNC server"
 echo "  --disable-curses         disable curses output"
 echo "  --enable-curses          enable curses output"
 echo "  --disable-curl           disable curl connectivity"
@@ -1246,6 +1253,27 @@ EOF
 fi
 
 ##########################################
+# VNC JPEG detection
+if test "$vnc_jpeg" = "yes" ; then
+cat > $TMPC <<EOF
+#include <stdio.h>
+#include <jpeglib.h>
+int main(void) { struct jpeg_compress_struct s; jpeg_create_compress(&s); return 0; }
+EOF
+    vnc_jpeg_cflags=""
+    vnc_jpeg_libs="-ljpeg"
+  if compile_prog "$vnc_jpeg_cflags" "$vnc_jpeg_libs" ; then
+    vnc_jpeg=yes
+    libs_softmmu="$vnc_jpeg_libs $libs_softmmu"
+  else
+    if test "$vnc_jpeg" = "yes" ; then
+      feature_not_found "vnc-jpeg"
+    fi
+    vnc_jpeg=no
+  fi
+fi
+
+##########################################
 # fnmatch() probe, used for ACL routines
 fnmatch="no"
 cat > $TMPC << EOF
@@ -2094,6 +2122,7 @@ echo "Block whitelist   $block_drv_whitelist"
 echo "Mixer emulation   $mixemu"
 echo "VNC TLS support   $vnc_tls"
 echo "VNC SASL support  $vnc_sasl"
+echo "VNC JPEG support  $vnc_jpeg"
 if test -n "$sparc_cpu"; then
     echo "Target Sparc Arch $sparc_cpu"
 fi
@@ -2231,6 +2260,10 @@ if test "$vnc_sasl" = "yes" ; then
   echo "CONFIG_VNC_SASL=y" >> $config_host_mak
   echo "VNC_SASL_CFLAGS=$vnc_sasl_cflags" >> $config_host_mak
 fi
+if test "$vnc_jpeg" = "yes" ; then
+  echo "CONFIG_VNC_JPEG=y" >> $config_host_mak
+  echo "VNC_JPEG_CFLAGS=$vnc_jpeg_cflags" >> $config_host_mak
+fi
 if test "$fnmatch" = "yes" ; then
   echo "CONFIG_FNMATCH=y" >> $config_host_mak
 fi
diff --git a/vnc-encoding-tight.c b/vnc-encoding-tight.c
index faba483..5b69ff0 100644
--- a/vnc-encoding-tight.c
+++ b/vnc-encoding-tight.c
@@ -26,6 +26,14 @@
  * THE SOFTWARE.
  */
 
+#include "qemu-common.h"
+
+#ifdef CONFIG_VNC_JPEG
+#include <stdio.h>
+#include <jpeglib.h>
+#endif
+
+#include "bswap.h"
 #include "qdict.h"
 #include "qint.h"
 #include "vnc.h"
@@ -56,6 +64,206 @@ static const struct {
 };
 
 /*
+ * Code to guess if given rectangle is suitable for smooth image
+ * compression (by applying "gradient" filter or JPEG coder).
+ */
+
+static uint
+tight_detect_smooth_image24(VncState *vs, int w, int h)
+{
+    int off;
+    int x, y, d, dx;
+    uint c;
+    uint stats[256];
+    int pixels = 0;
+    int pix, left[3];
+    uint errors;
+    unsigned char *buf = vs->tight.buffer;
+
+    /*
+     * 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);
+
+    memset(stats, 0, sizeof (stats));
+
+    for (y = 0, x = 0; y < h && x < w;) {
+        for (d = 0; d < h - y && d < w - x - VNC_TIGHT_DETECT_SUBROW_WIDTH;
+             d++) {
+            for (c = 0; c < 3; c++) {
+                left[c] = buf[((y+d)*w+x+d)*4+off+c] & 0xFF;
+            }
+            for (dx = 1; dx <= VNC_TIGHT_DETECT_SUBROW_WIDTH; dx++) {
+                for (c = 0; c < 3; c++) {
+                    pix = buf[((y+d)*w+x+d+dx)*4+off+c] & 0xFF;
+                    stats[abs(pix - left[c])]++;
+                    left[c] = pix;
+                }
+                pixels++;
+            }
+        }
+        if (w > h) {
+            x += h;
+            y = 0;
+        } else {
+            x = 0;
+            y += w;
+        }
+    }
+
+    /* 95% smooth or more ... */
+    if (stats[0] * 33 / pixels >= 95) {
+        return 0;
+    }
+
+    errors = 0;
+    for (c = 1; c < 8; c++) {
+        errors += stats[c] * (c * c);
+        if (stats[c] == 0 || stats[c] > stats[c-1] * 2) {
+            return 0;
+        }
+    }
+    for (; c < 256; c++) {
+        errors += stats[c] * (c * c);
+    }
+    errors /= (pixels * 3 - stats[0]);
+
+    return errors;
+}
+
+#define DEFINE_DETECT_FUNCTION(bpp)                                     \
+                                                                        \
+    static uint                                                         \
+    tight_detect_smooth_image##bpp(VncState *vs, int w, int h) {        \
+        bool endian;                                                    \
+        uint##bpp##_t pix;                                              \
+        int max[3], shift[3];                                           \
+        int x, y, d, dx;                                                \
+        uint c;                                                         \
+        uint stats[256];                                                \
+        int pixels = 0;                                                 \
+        int sample, sum, left[3];                                       \
+        uint errors;                                                    \
+        unsigned char *buf = vs->tight.buffer;                          \
+                                                                        \
+        endian = ((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;                              \
+                                                                        \
+        memset(stats, 0, sizeof(stats));                                \
+                                                                        \
+        y = 0, x = 0;                                                   \
+        while (y < h && x < w) {                                        \
+            for (d = 0; d < h - y &&                                    \
+                     d < w - x - VNC_TIGHT_DETECT_SUBROW_WIDTH; d++) {  \
+                pix = ((uint##bpp##_t *)buf)[(y+d)*w+x+d];              \
+                if (endian) {                                           \
+                    pix = bswap_##bpp(pix);                             \
+                }                                                       \
+                for (c = 0; c < 3; c++) {                               \
+                    left[c] = (int)(pix >> shift[c] & max[c]);          \
+                }                                                       \
+                for (dx = 1; dx <= VNC_TIGHT_DETECT_SUBROW_WIDTH;       \
+                     dx++) {                                            \
+                    pix = ((uint##bpp##_t *)buf)[(y+d)*w+x+d+dx];       \
+                    if (endian) {                                       \
+                        pix = bswap_##bpp(pix);                         \
+                    }                                                   \
+                    sum = 0;                                            \
+                    for (c = 0; c < 3; c++) {                           \
+                        sample = (int)(pix >> shift[c] & max[c]);       \
+                        sum += abs(sample - left[c]);                   \
+                        left[c] = sample;                               \
+                    }                                                   \
+                    if (sum > 255) {                                    \
+                        sum = 255;                                      \
+                    }                                                   \
+                    stats[sum]++;                                       \
+                    pixels++;                                           \
+                }                                                       \
+            }                                                           \
+            if (w > h) {                                                \
+                x += h;                                                 \
+                y = 0;                                                  \
+            } else {                                                    \
+                x = 0;                                                  \
+                y += w;                                                 \
+            }                                                           \
+        }                                                               \
+                                                                        \
+        if ((stats[0] + stats[1]) * 100 / pixels >= 90) {               \
+            return 0;                                                   \
+        }                                                               \
+                                                                        \
+        errors = 0;                                                     \
+        for (c = 1; c < 8; c++) {                                       \
+            errors += stats[c] * (c * c);                               \
+            if (stats[c] == 0 || stats[c] > stats[c-1] * 2) {           \
+                return 0;                                               \
+            }                                                           \
+        }                                                               \
+        for (; c < 256; c++) {                                          \
+            errors += stats[c] * (c * c);                               \
+        }                                                               \
+        errors /= (pixels - stats[0]);                                  \
+                                                                        \
+        return errors;                                                  \
+    }
+
+DEFINE_DETECT_FUNCTION(16)
+DEFINE_DETECT_FUNCTION(32)
+
+static int
+tight_detect_smooth_image(VncState *vs, int w, int h)
+{
+    uint errors;
+    int compression = vs->tight_compression;
+    int quality = vs->tight_quality;
+
+    if (ds_get_bytes_per_pixel(vs->ds) == 1 ||
+        vs->clientds.pf.bytes_per_pixel == 1 ||
+        w < VNC_TIGHT_DETECT_MIN_WIDTH || h < VNC_TIGHT_DETECT_MIN_HEIGHT) {
+        return 0;
+    }
+
+    if (vs->tight_quality != -1) {
+        if (w * h < VNC_TIGHT_JPEG_MIN_RECT_SIZE) {
+            return 0;
+        }
+    } else {
+        if (w * h < tight_conf[compression].gradient_min_rect_size) {
+            return 0;
+        }
+    }
+
+    if (vs->clientds.pf.bytes_per_pixel == 4) {
+        if (vs->tight_pixel24) {
+            errors = tight_detect_smooth_image24(vs, w, h);
+            if (vs->tight_quality != -1) {
+                return (errors < tight_conf[quality].jpeg_threshold24);
+            }
+            return (errors < tight_conf[compression].gradient_threshold24);
+        } else {
+            errors = tight_detect_smooth_image32(vs, w, h);
+        }
+    } else {
+        errors = tight_detect_smooth_image16(vs, w, h);
+    }
+    if (quality != -1) {
+        return (errors < tight_conf[quality].jpeg_threshold);
+    }
+    return (errors < tight_conf[compression].gradient_threshold);
+}
+
+/*
  * Code to determine how many different colors used in rectangle.
  */
 
@@ -335,6 +543,133 @@ DEFINE_MONO_ENCODE_FUNCTION(16)
 DEFINE_MONO_ENCODE_FUNCTION(32)
 
 /*
+ * ``Gradient'' filter for 24-bit color samples.
+ * Should be called only when redMax, greenMax and blueMax are 255.
+ * Color components assumed to be byte-aligned.
+ */
+
+static void
+tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
+{
+    uint32_t *buf32;
+    uint32_t pix32;
+    int shift[3];
+    int *prev;
+    int here[3], upper[3], left[3], upperleft[3];
+    int prediction;
+    int x, y, c;
+
+    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;
+    } else {
+        shift[0] = 24 - vs->clientds.pf.rshift;
+        shift[1] = 24 - vs->clientds.pf.gshift;
+        shift[2] = 24 - vs->clientds.pf.bshift;
+    }
+
+    for (y = 0; y < h; y++) {
+        for (c = 0; c < 3; c++) {
+            upper[c] = 0;
+            here[c] = 0;
+        }
+        prev = (int *)vs->tight_gradient.buffer;
+        for (x = 0; x < w; x++) {
+            pix32 = *buf32++;
+            for (c = 0; c < 3; c++) {
+                upperleft[c] = upper[c];
+                left[c] = here[c];
+                upper[c] = *prev;
+                here[c] = (int)(pix32 >> shift[c] & 0xFF);
+                *prev++ = here[c];
+
+                prediction = left[c] + upper[c] - upperleft[c];
+                if (prediction < 0) {
+                    prediction = 0;
+                } else if (prediction > 0xFF) {
+                    prediction = 0xFF;
+                }
+                *buf++ = (char)(here[c] - prediction);
+            }
+        }
+    }
+}
+
+
+/*
+ * ``Gradient'' filter for other color depths.
+ */
+
+#define DEFINE_GRADIENT_FILTER_FUNCTION(bpp)                            \
+                                                                        \
+    static void                                                         \
+    tight_filter_gradient##bpp(VncState *vs, uint##bpp##_t *buf,        \
+                               int w, int h) {                          \
+        uint##bpp##_t pix, diff;                                        \
+        bool endian;                                                    \
+        int *prev;                                                      \
+        int max[3], shift[3];                                           \
+        int here[3], upper[3], left[3], upperleft[3];                   \
+        int prediction;                                                 \
+        int x, y, c;                                                    \
+                                                                        \
+        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));     \
+                                                                        \
+        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;                              \
+                                                                        \
+        for (y = 0; y < h; y++) {                                       \
+            for (c = 0; c < 3; c++) {                                   \
+                upper[c] = 0;                                           \
+                here[c] = 0;                                            \
+            }                                                           \
+            prev = (int *)vs->tight_gradient.buffer;                    \
+            for (x = 0; x < w; x++) {                                   \
+                pix = *buf;                                             \
+                if (endian) {                                           \
+                    pix = bswap_##bpp(pix);                             \
+                }                                                       \
+                diff = 0;                                               \
+                for (c = 0; c < 3; c++) {                               \
+                    upperleft[c] = upper[c];                            \
+                    left[c] = here[c];                                  \
+                    upper[c] = *prev;                                   \
+                    here[c] = (int)(pix >> shift[c] & max[c]);          \
+                    *prev++ = here[c];                                  \
+                                                                        \
+                    prediction = left[c] + upper[c] - upperleft[c];     \
+                    if (prediction < 0) {                               \
+                        prediction = 0;                                 \
+                    } else if (prediction > max[c]) {                   \
+                        prediction = max[c];                            \
+                    }                                                   \
+                    diff |= ((here[c] - prediction) & max[c])           \
+                        << shift[c];                                    \
+                }                                                       \
+                if (endian) {                                           \
+                    diff = bswap_##bpp(diff);                           \
+                }                                                       \
+                *buf++ = diff;                                          \
+            }                                                           \
+        }                                                               \
+    }
+
+DEFINE_GRADIENT_FILTER_FUNCTION(16)
+DEFINE_GRADIENT_FILTER_FUNCTION(32)
+
+/*
  * Check if a rectangle is all of the same color. If needSameColor is
  * set to non-zero, then also check that its color equals to the
  * *colorPtr value. The result is 1 if the test is successfull, and in
@@ -702,6 +1037,41 @@ static void write_palette(const char *key, QObject *obj, void *opaque)
     }
 }
 
+static bool send_gradient_rect(VncState *vs, int w, int h)
+{
+    int stream = 3;
+    int level = tight_conf[vs->tight_compression].gradient_zlib_level;
+    size_t bytes;
+
+    if (vs->clientds.pf.bytes_per_pixel == 1)
+        return send_full_color_rect(vs, w, h);
+
+    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
+    vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT);
+
+    buffer_reserve(&vs->tight_gradient, w * 3 * sizeof (int));
+
+    if (vs->tight_pixel24) {
+        tight_filter_gradient24(vs, vs->tight.buffer, w, h);
+        bytes = 3;
+    } else if (vs->clientds.pf.bytes_per_pixel == 4) {
+        tight_filter_gradient32(vs, (uint32_t *)vs->tight.buffer, w, h);
+        bytes = 4;
+    } else {
+        tight_filter_gradient16(vs, (uint16_t *)vs->tight.buffer, w, h);
+        bytes = 2;
+    }
+
+    buffer_reset(&vs->tight_gradient);
+
+    bytes = w * h * bytes;
+    vs->tight.offset = bytes;
+
+    bytes = tight_compress_data(vs, stream, bytes,
+                                level, Z_FILTERED);
+    return (bytes >= 0);
+}
+
 static int send_palette_rect(VncState *vs, int w, int h, struct QDict *palette)
 {
     int stream = 2;
@@ -756,6 +1126,164 @@ static int send_palette_rect(VncState *vs, int w, int h, struct QDict *palette)
     return (bytes >= 0);
 }
 
+/*
+ * JPEG compression stuff.
+ */
+#ifdef CONFIG_VNC_JPEG
+static void jpeg_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_JPEG_GET_ROW_FUNCTION(bpp)                               \
+                                                                        \
+    static void                                                         \
+    jpeg_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_JPEG_GET_ROW_FUNCTION(16)
+DEFINE_JPEG_GET_ROW_FUNCTION(32)
+
+static void jpeg_prepare_row(VncState *vs, uint8_t *dst, int x, int y,
+                                       int count)
+{
+    if (vs->tight_pixel24)
+        jpeg_prepare_row24(vs, dst, x, y, count);
+    else if (ds_get_bytes_per_pixel(vs->ds) == 4)
+        jpeg_prepare_row32(vs, dst, x, y, count);
+    else
+        jpeg_prepare_row16(vs, dst, x, y, count);
+}
+
+/*
+ * Destination manager implementation for JPEG library.
+ */
+
+/* This is called once per encoding */
+static void jpeg_init_destination(j_compress_ptr cinfo)
+{
+    VncState *vs = cinfo->client_data;
+    Buffer *buffer = &vs->tight_jpeg;
+
+    cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset;
+    cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset);
+}
+
+/* This is called when we ran out of buffer (shouldn't happen!) */
+static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
+{
+    VncState *vs = cinfo->client_data;
+    Buffer *buffer = &vs->tight_jpeg;
+
+    buffer->offset = buffer->capacity;
+    buffer_reserve(buffer, 2048);
+    jpeg_init_destination(cinfo);
+    return TRUE;
+}
+
+/* This is called when we are done processing data */
+static void jpeg_term_destination(j_compress_ptr cinfo)
+{
+    VncState *vs = cinfo->client_data;
+    Buffer *buffer = &vs->tight_jpeg;
+
+    buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer;
+}
+
+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;
+    JSAMPROW row[1];
+    uint8_t *buf;
+    int dy;
+
+    if (ds_get_bytes_per_pixel(vs->ds) == 1)
+        return send_full_color_rect(vs, w, h);
+
+    buf = qemu_malloc(w * 3);
+    row[0] = buf;
+    buffer_reserve(&vs->tight_jpeg, 2048);
+
+    cinfo.err = jpeg_std_error(&jerr);
+    jpeg_create_compress(&cinfo);
+
+    cinfo.client_data = vs;
+    cinfo.image_width = w;
+    cinfo.image_height = h;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_RGB;
+
+    jpeg_set_defaults(&cinfo);
+    jpeg_set_quality(&cinfo, quality, true);
+
+    manager.init_destination = jpeg_init_destination;
+    manager.empty_output_buffer = jpeg_empty_output_buffer;
+    manager.term_destination = jpeg_term_destination;
+    cinfo.dest = &manager;
+
+    jpeg_start_compress(&cinfo, true);
+
+    for (dy = 0; dy < h; dy++) {
+        jpeg_prepare_row(vs, buf, x, y + dy, w);
+        jpeg_write_scanlines(&cinfo, row, 1);
+    }
+
+    jpeg_finish_compress(&cinfo);
+    jpeg_destroy_compress(&cinfo);
+
+    vnc_write_u8(vs, VNC_TIGHT_JPEG << 4);
+
+    tight_send_compact_size(vs, vs->tight_jpeg.offset);
+    vnc_write(vs, vs->tight_jpeg.buffer, vs->tight_jpeg.offset);
+    buffer_reset(&vs->tight_jpeg);
+
+    return 1;
+}
+#endif /* CONFIG_VNC_JPEG */
+
 static void vnc_tight_start(VncState *vs)
 {
     buffer_reset(&vs->tight);
@@ -788,13 +1316,38 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
     colors = tight_fill_palette(vs, x, y, w * h, &fg, &bg, &palette);
 
     if (colors == 0) {
-        ret = send_full_color_rect(vs, w, h);
+        if (tight_detect_smooth_image(vs, w, h)) {
+            if (vs->tight_quality == -1) {
+                ret = send_gradient_rect(vs, w, h);
+            } else {
+#ifdef CONFIG_VNC_JPEG
+                int quality = tight_conf[vs->tight_quality].jpeg_quality;
+
+                ret = send_jpeg_rect(vs, x, y, w, h, quality);
+#else
+                ret = send_full_color_rect(vs, w, h);
+#endif
+            }
+        } else {
+            ret = send_full_color_rect(vs, w, h);
+        }
     } else if (colors == 1) {
         ret = send_solid_rect(vs);
     } else if (colors == 2) {
         ret = send_mono_rect(vs, w, h, bg, fg);
     } else if (colors <= 256) {
+#ifdef CONFIG_VNC_JPEG
+        if (colors > 96 && vs->tight_quality != -1 && vs->tight_quality <= 3 &&
+            tight_detect_smooth_image(vs, w, h)) {
+            int quality = tight_conf[vs->tight_quality].jpeg_quality;
+
+            ret = send_jpeg_rect(vs, x, y, w, h, quality);
+        } else {
+            ret = send_palette_rect(vs, w, h, palette);
+        }
+#else
         ret = send_palette_rect(vs, w, h, palette);
+#endif
     }
     QDECREF(palette);
     return ret;
@@ -956,4 +1509,8 @@ void vnc_tight_clear(VncState *vs)
 
     buffer_free(&vs->tight);
     buffer_free(&vs->tight_zlib);
+    buffer_free(&vs->tight_gradient);
+#ifdef CONFIG_VNC_JPEG
+    buffer_free(&vs->tight_jpeg);
+#endif
 }
diff --git a/vnc-encoding-tight.h b/vnc-encoding-tight.h
index 64d1062..9b0910c 100644
--- a/vnc-encoding-tight.h
+++ b/vnc-encoding-tight.h
@@ -173,4 +173,9 @@
 #define VNC_TIGHT_MIN_SOLID_SUBRECT_SIZE  2048
 #define VNC_TIGHT_MAX_SPLIT_TILE_SIZE       16
 
+#define VNC_TIGHT_JPEG_MIN_RECT_SIZE      4096
+#define VNC_TIGHT_DETECT_SUBROW_WIDTH        7
+#define VNC_TIGHT_DETECT_MIN_WIDTH           8
+#define VNC_TIGHT_DETECT_MIN_HEIGHT          8
+
 #endif /* VNC_ENCODING_TIGHT_H */
diff --git a/vnc.h b/vnc.h
index 7b64cf7..2a9024d 100644
--- a/vnc.h
+++ b/vnc.h
@@ -176,6 +176,10 @@ struct VncState
     Buffer tight;
     Buffer tight_tmp;
     Buffer tight_zlib;
+    Buffer tight_gradient;
+#ifdef CONFIG_VNC_JPEG
+    Buffer tight_jpeg;
+#endif
     int tight_levels[4];
     z_stream tight_stream[4];
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 02/18] vnc: JPEG should be disabled if the client don't set tight quality
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 01/18] vnc: tight: add JPEG and gradient subencoding with smooth image detection Corentin Chary
@ 2010-07-07 18:57 ` Corentin Chary
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 03/18] vnc: add lossy option Corentin Chary
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

Disable JPEG compression by default and only enable it if the
VNC client has sent the requested quality.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 vnc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/vnc.c b/vnc.c
index ed0e096..9cf38d1 100644
--- a/vnc.c
+++ b/vnc.c
@@ -1644,7 +1644,7 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
     vs->features = 0;
     vs->vnc_encoding = 0;
     vs->tight_compression = 9;
-    vs->tight_quality = 9;
+    vs->tight_quality = -1; /* Lossless by default */
     vs->absolute = -1;
 
     /*
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 03/18] vnc: add lossy option
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 01/18] vnc: tight: add JPEG and gradient subencoding with smooth image detection Corentin Chary
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 02/18] vnc: JPEG should be disabled if the client don't set tight quality Corentin Chary
@ 2010-07-07 18:57 ` Corentin Chary
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 04/18] ui: move all ui components in ui/ Corentin Chary
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

The lossy option can be used to enable lossy compression
methods like gradient or jpeg. This patch disable them by
default.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 qemu-options.hx      |    7 +++++++
 vnc-encoding-tight.c |    4 ++++
 vnc.c                |    2 ++
 vnc.h                |    2 ++
 4 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/qemu-options.hx b/qemu-options.hx
index d1d2272..2fad881 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -835,6 +835,13 @@ empty, with a @code{deny} policy. Thus no one will be allowed to
 use the VNC server until the ACLs have been loaded. This can be
 achieved using the @code{acl} monitor command.
 
+@item lossy
+
+Enable lossy compression methods (gradient, JPEG, ...). If this
+option is set, VNC client may receive lossy framebuffer updates
+depending on its encoding settings. Enabling this option can save
+a lot of bandwidth at the expense of quality.
+
 @end table
 ETEXI
 
diff --git a/vnc-encoding-tight.c b/vnc-encoding-tight.c
index 5b69ff0..c1a292b 100644
--- a/vnc-encoding-tight.c
+++ b/vnc-encoding-tight.c
@@ -228,6 +228,10 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
     int compression = vs->tight_compression;
     int quality = vs->tight_quality;
 
+    if (!vs->vd->lossy) {
+        return 0;
+    }
+
     if (ds_get_bytes_per_pixel(vs->ds) == 1 ||
         vs->clientds.pf.bytes_per_pixel == 1 ||
         w < VNC_TIGHT_DETECT_MIN_WIDTH || h < VNC_TIGHT_DETECT_MIN_HEIGHT) {
diff --git a/vnc.c b/vnc.c
index 9cf38d1..ccd7aad 100644
--- a/vnc.c
+++ b/vnc.c
@@ -2482,6 +2482,8 @@ int vnc_display_open(DisplayState *ds, const char *display)
 #endif
         } else if (strncmp(options, "acl", 3) == 0) {
             acl = 1;
+        } else if (strncmp(options, "lossy", 5) == 0) {
+            vs->lossy = true;
         }
     }
 
diff --git a/vnc.h b/vnc.h
index 2a9024d..ec90cd3 100644
--- a/vnc.h
+++ b/vnc.h
@@ -33,6 +33,7 @@
 #include "monitor.h"
 #include "audio/audio.h"
 #include <zlib.h>
+#include <stdbool.h>
 
 #include "keymaps.h"
 
@@ -111,6 +112,7 @@ struct VncDisplay
     char *display;
     char *password;
     int auth;
+    bool lossy;
 #ifdef CONFIG_VNC_TLS
     int subauth; /* Used by VeNCrypt */
     VncDisplayTLS tls;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 04/18] ui: move all ui components in ui/
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (2 preceding siblings ...)
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 03/18] vnc: add lossy option Corentin Chary
@ 2010-07-07 18:57 ` Corentin Chary
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 05/18] vnc: rename vnc-encoding-* vnc-enc-* Corentin Chary
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

Move sdl, vnc, curses and cocoa UI into ui/ to cleanup
the root directory. Also remove some unnecessary explicit
targets from Makefile.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 Makefile                                           |   38 +++-----------------
 Makefile.objs                                      |   22 ++++++-----
 cocoa.m => ui/cocoa.m                              |    0
 curses.c => ui/curses.c                            |    0
 curses_keys.h => ui/curses_keys.h                  |    0
 d3des.c => ui/d3des.c                              |    0
 d3des.h => ui/d3des.h                              |    0
 keymaps.c => ui/keymaps.c                          |    0
 keymaps.h => ui/keymaps.h                          |    0
 sdl.c => ui/sdl.c                                  |    0
 sdl_keysym.h => ui/sdl_keysym.h                    |    0
 sdl_zoom.c => ui/sdl_zoom.c                        |    0
 sdl_zoom.h => ui/sdl_zoom.h                        |    0
 sdl_zoom_template.h => ui/sdl_zoom_template.h      |    0
 vnc-auth-sasl.c => ui/vnc-auth-sasl.c              |    0
 vnc-auth-sasl.h => ui/vnc-auth-sasl.h              |    0
 vnc-auth-vencrypt.c => ui/vnc-auth-vencrypt.c      |    0
 vnc-auth-vencrypt.h => ui/vnc-auth-vencrypt.h      |    0
 .../vnc-encoding-hextile.c                         |    0
 vnc-encoding-tight.c => ui/vnc-encoding-tight.c    |    0
 vnc-encoding-tight.h => ui/vnc-encoding-tight.h    |    0
 vnc-encoding-zlib.c => ui/vnc-encoding-zlib.c      |    0
 vnc-tls.c => ui/vnc-tls.c                          |    0
 vnc-tls.h => ui/vnc-tls.h                          |    0
 vnc.c => ui/vnc.c                                  |    0
 vnc.h => ui/vnc.h                                  |    0
 vnc_keysym.h => ui/vnc_keysym.h                    |    0
 vnchextile.h => ui/vnchextile.h                    |    0
 x_keymap.c => ui/x_keymap.c                        |    0
 x_keymap.h => ui/x_keymap.h                        |    0
 30 files changed, 17 insertions(+), 43 deletions(-)
 rename cocoa.m => ui/cocoa.m (100%)
 rename curses.c => ui/curses.c (100%)
 rename curses_keys.h => ui/curses_keys.h (100%)
 rename d3des.c => ui/d3des.c (100%)
 rename d3des.h => ui/d3des.h (100%)
 rename keymaps.c => ui/keymaps.c (100%)
 rename keymaps.h => ui/keymaps.h (100%)
 rename sdl.c => ui/sdl.c (100%)
 rename sdl_keysym.h => ui/sdl_keysym.h (100%)
 rename sdl_zoom.c => ui/sdl_zoom.c (100%)
 rename sdl_zoom.h => ui/sdl_zoom.h (100%)
 rename sdl_zoom_template.h => ui/sdl_zoom_template.h (100%)
 rename vnc-auth-sasl.c => ui/vnc-auth-sasl.c (100%)
 rename vnc-auth-sasl.h => ui/vnc-auth-sasl.h (100%)
 rename vnc-auth-vencrypt.c => ui/vnc-auth-vencrypt.c (100%)
 rename vnc-auth-vencrypt.h => ui/vnc-auth-vencrypt.h (100%)
 rename vnc-encoding-hextile.c => ui/vnc-encoding-hextile.c (100%)
 rename vnc-encoding-tight.c => ui/vnc-encoding-tight.c (100%)
 rename vnc-encoding-tight.h => ui/vnc-encoding-tight.h (100%)
 rename vnc-encoding-zlib.c => ui/vnc-encoding-zlib.c (100%)
 rename vnc-tls.c => ui/vnc-tls.c (100%)
 rename vnc-tls.h => ui/vnc-tls.h (100%)
 rename vnc.c => ui/vnc.c (100%)
 rename vnc.h => ui/vnc.h (100%)
 rename vnc_keysym.h => ui/vnc_keysym.h (100%)
 rename vnchextile.h => ui/vnchextile.h (100%)
 rename x_keymap.c => ui/x_keymap.c (100%)
 rename x_keymap.h => ui/x_keymap.h (100%)

diff --git a/Makefile b/Makefile
index 560eac6..2c74d17 100644
--- a/Makefile
+++ b/Makefile
@@ -96,42 +96,14 @@ audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
 
 QEMU_CFLAGS+=$(CURL_CFLAGS)
 
-cocoa.o: cocoa.m
+ui/cocoa.o: ui/cocoa.m
 
-keymaps.o: keymaps.c keymaps.h
+ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
 
-sdl_zoom.o: sdl_zoom.c sdl_zoom.h sdl_zoom_template.h
-
-sdl.o: sdl.c keymaps.h sdl_keysym.h sdl_zoom.h
-
-sdl.o audio/sdlaudio.o sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
-
-acl.o: acl.h acl.c
-
-vnc.h: vnc-tls.h vnc-auth-vencrypt.h vnc-auth-sasl.h keymaps.h
-
-vnc.o: vnc.c vnc.h vnc_keysym.h vnchextile.h d3des.c d3des.h acl.h
-
-vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
-
-vnc-tls.o: vnc-tls.c vnc.h
-
-vnc-auth-vencrypt.o: vnc-auth-vencrypt.c vnc.h
-
-vnc-auth-sasl.o: vnc-auth-sasl.c vnc.h
-
-vnc-encoding-zlib.o: vnc-encoding-zlib.c vnc.h
-
-vnc-encoding-hextile.o: vnc-encoding-hextile.c vnc.h
-
-vnc-encoding-tight.o: vnc-encoding-tight.c vnc.h vnc-encoding-tight.h
-
-curses.o: curses.c keymaps.h curses_keys.h
+ui/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 
 bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
 
-iov.o: iov.c iov.h
-
 ######################################################################
 
 qemu-img.o: qemu-img-cmds.h
@@ -159,7 +131,7 @@ clean:
 # avoid old build problems by removing potentially incorrect old files
 	rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
 	rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
-	rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d
+	rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d ui/*.o ui/*.d
 	rm -f qemu-img-cmds.h
 	$(MAKE) -C tests clean
 	for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
@@ -344,4 +316,4 @@ tarbin:
 	$(mandir)/man8/qemu-nbd.8
 
 # Include automatically generated dependency files
--include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d)
+-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d)
diff --git a/Makefile.objs b/Makefile.objs
index 67f1b21..43b4e16 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -102,16 +102,18 @@ audio-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
 audio-obj-y += wavcapture.o
 common-obj-y += $(addprefix audio/, $(audio-obj-y))
 
-common-obj-y += keymaps.o
-common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
-common-obj-$(CONFIG_CURSES) += curses.o
-common-obj-y += vnc.o acl.o d3des.o
-common-obj-y += vnc-encoding-zlib.o vnc-encoding-hextile.o
-common-obj-y += vnc-encoding-tight.o
-common-obj-y += iov.o
-common-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
-common-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
-common-obj-$(CONFIG_COCOA) += cocoa.o
+ui-obj-y += keymaps.o
+ui-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
+ui-obj-$(CONFIG_CURSES) += curses.o
+ui-obj-y += vnc.o d3des.o
+ui-obj-y += vnc-encoding-zlib.o vnc-encoding-hextile.o
+ui-obj-y += vnc-encoding-tight.o
+ui-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
+ui-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
+ui-obj-$(CONFIG_COCOA) += cocoa.o
+common-obj-y += $(addprefix ui/, $(ui-obj-y))
+
+common-obj-y += iov.o acl.o
 common-obj-$(CONFIG_IOTHREAD) += qemu-thread.o
 common-obj-y += notify.o event_notifier.o
 common-obj-y += qemu-timer.o
diff --git a/cocoa.m b/ui/cocoa.m
similarity index 100%
rename from cocoa.m
rename to ui/cocoa.m
diff --git a/curses.c b/ui/curses.c
similarity index 100%
rename from curses.c
rename to ui/curses.c
diff --git a/curses_keys.h b/ui/curses_keys.h
similarity index 100%
rename from curses_keys.h
rename to ui/curses_keys.h
diff --git a/d3des.c b/ui/d3des.c
similarity index 100%
rename from d3des.c
rename to ui/d3des.c
diff --git a/d3des.h b/ui/d3des.h
similarity index 100%
rename from d3des.h
rename to ui/d3des.h
diff --git a/keymaps.c b/ui/keymaps.c
similarity index 100%
rename from keymaps.c
rename to ui/keymaps.c
diff --git a/keymaps.h b/ui/keymaps.h
similarity index 100%
rename from keymaps.h
rename to ui/keymaps.h
diff --git a/sdl.c b/ui/sdl.c
similarity index 100%
rename from sdl.c
rename to ui/sdl.c
diff --git a/sdl_keysym.h b/ui/sdl_keysym.h
similarity index 100%
rename from sdl_keysym.h
rename to ui/sdl_keysym.h
diff --git a/sdl_zoom.c b/ui/sdl_zoom.c
similarity index 100%
rename from sdl_zoom.c
rename to ui/sdl_zoom.c
diff --git a/sdl_zoom.h b/ui/sdl_zoom.h
similarity index 100%
rename from sdl_zoom.h
rename to ui/sdl_zoom.h
diff --git a/sdl_zoom_template.h b/ui/sdl_zoom_template.h
similarity index 100%
rename from sdl_zoom_template.h
rename to ui/sdl_zoom_template.h
diff --git a/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c
similarity index 100%
rename from vnc-auth-sasl.c
rename to ui/vnc-auth-sasl.c
diff --git a/vnc-auth-sasl.h b/ui/vnc-auth-sasl.h
similarity index 100%
rename from vnc-auth-sasl.h
rename to ui/vnc-auth-sasl.h
diff --git a/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c
similarity index 100%
rename from vnc-auth-vencrypt.c
rename to ui/vnc-auth-vencrypt.c
diff --git a/vnc-auth-vencrypt.h b/ui/vnc-auth-vencrypt.h
similarity index 100%
rename from vnc-auth-vencrypt.h
rename to ui/vnc-auth-vencrypt.h
diff --git a/vnc-encoding-hextile.c b/ui/vnc-encoding-hextile.c
similarity index 100%
rename from vnc-encoding-hextile.c
rename to ui/vnc-encoding-hextile.c
diff --git a/vnc-encoding-tight.c b/ui/vnc-encoding-tight.c
similarity index 100%
rename from vnc-encoding-tight.c
rename to ui/vnc-encoding-tight.c
diff --git a/vnc-encoding-tight.h b/ui/vnc-encoding-tight.h
similarity index 100%
rename from vnc-encoding-tight.h
rename to ui/vnc-encoding-tight.h
diff --git a/vnc-encoding-zlib.c b/ui/vnc-encoding-zlib.c
similarity index 100%
rename from vnc-encoding-zlib.c
rename to ui/vnc-encoding-zlib.c
diff --git a/vnc-tls.c b/ui/vnc-tls.c
similarity index 100%
rename from vnc-tls.c
rename to ui/vnc-tls.c
diff --git a/vnc-tls.h b/ui/vnc-tls.h
similarity index 100%
rename from vnc-tls.h
rename to ui/vnc-tls.h
diff --git a/vnc.c b/ui/vnc.c
similarity index 100%
rename from vnc.c
rename to ui/vnc.c
diff --git a/vnc.h b/ui/vnc.h
similarity index 100%
rename from vnc.h
rename to ui/vnc.h
diff --git a/vnc_keysym.h b/ui/vnc_keysym.h
similarity index 100%
rename from vnc_keysym.h
rename to ui/vnc_keysym.h
diff --git a/vnchextile.h b/ui/vnchextile.h
similarity index 100%
rename from vnchextile.h
rename to ui/vnchextile.h
diff --git a/x_keymap.c b/ui/x_keymap.c
similarity index 100%
rename from x_keymap.c
rename to ui/x_keymap.c
diff --git a/x_keymap.h b/ui/x_keymap.h
similarity index 100%
rename from x_keymap.h
rename to ui/x_keymap.h
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 05/18] vnc: rename vnc-encoding-* vnc-enc-*
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (3 preceding siblings ...)
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 04/18] ui: move all ui components in ui/ Corentin Chary
@ 2010-07-07 18:57 ` Corentin Chary
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 06/18] vnc: tight: don't forget do at the last color Corentin Chary
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

For the same reason that we don't use vnc-authentication-sasl.c but
vnc-auth-sals.c. Because it's tooooo long.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 Makefile.objs                                    |    4 ++--
 ui/{vnchextile.h => vnc-enc-hextile-template.h}  |    0
 ui/{vnc-encoding-hextile.c => vnc-enc-hextile.c} |   12 ++++++------
 ui/{vnc-encoding-tight.c => vnc-enc-tight.c}     |    2 +-
 ui/{vnc-encoding-tight.h => vnc-enc-tight.h}     |    0
 ui/{vnc-encoding-zlib.c => vnc-enc-zlib.c}       |    0
 6 files changed, 9 insertions(+), 9 deletions(-)
 rename ui/{vnchextile.h => vnc-enc-hextile-template.h} (100%)
 rename ui/{vnc-encoding-hextile.c => vnc-enc-hextile.c} (93%)
 rename ui/{vnc-encoding-tight.c => vnc-enc-tight.c} (99%)
 rename ui/{vnc-encoding-tight.h => vnc-enc-tight.h} (100%)
 rename ui/{vnc-encoding-zlib.c => vnc-enc-zlib.c} (100%)

diff --git a/Makefile.objs b/Makefile.objs
index 43b4e16..a0b8200 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -106,8 +106,8 @@ ui-obj-y += keymaps.o
 ui-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
 ui-obj-$(CONFIG_CURSES) += curses.o
 ui-obj-y += vnc.o d3des.o
-ui-obj-y += vnc-encoding-zlib.o vnc-encoding-hextile.o
-ui-obj-y += vnc-encoding-tight.o
+ui-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o
+ui-obj-y += vnc-enc-tight.o
 ui-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
 ui-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
 ui-obj-$(CONFIG_COCOA) += cocoa.o
diff --git a/ui/vnchextile.h b/ui/vnc-enc-hextile-template.h
similarity index 100%
rename from ui/vnchextile.h
rename to ui/vnc-enc-hextile-template.h
diff --git a/ui/vnc-encoding-hextile.c b/ui/vnc-enc-hextile.c
similarity index 93%
rename from ui/vnc-encoding-hextile.c
rename to ui/vnc-enc-hextile.c
index 728f25e..fa4b264 100644
--- a/ui/vnc-encoding-hextile.c
+++ b/ui/vnc-enc-hextile.c
@@ -33,32 +33,32 @@ static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
 }
 
 #define BPP 8
-#include "vnchextile.h"
+#include "vnc-enc-hextile-template.h"
 #undef BPP
 
 #define BPP 16
-#include "vnchextile.h"
+#include "vnc-enc-hextile-template.h"
 #undef BPP
 
 #define BPP 32
-#include "vnchextile.h"
+#include "vnc-enc-hextile-template.h"
 #undef BPP
 
 #define GENERIC
 #define BPP 8
-#include "vnchextile.h"
+#include "vnc-enc-hextile-template.h"
 #undef BPP
 #undef GENERIC
 
 #define GENERIC
 #define BPP 16
-#include "vnchextile.h"
+#include "vnc-enc-hextile-template.h"
 #undef BPP
 #undef GENERIC
 
 #define GENERIC
 #define BPP 32
-#include "vnchextile.h"
+#include "vnc-enc-hextile-template.h"
 #undef BPP
 #undef GENERIC
 
diff --git a/ui/vnc-encoding-tight.c b/ui/vnc-enc-tight.c
similarity index 99%
rename from ui/vnc-encoding-tight.c
rename to ui/vnc-enc-tight.c
index c1a292b..358221d 100644
--- a/ui/vnc-encoding-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -37,7 +37,7 @@
 #include "qdict.h"
 #include "qint.h"
 #include "vnc.h"
-#include "vnc-encoding-tight.h"
+#include "vnc-enc-tight.h"
 
 /* Compression level stuff. The following array contains various
    encoder parameters for each of 10 compression levels (0..9).
diff --git a/ui/vnc-encoding-tight.h b/ui/vnc-enc-tight.h
similarity index 100%
rename from ui/vnc-encoding-tight.h
rename to ui/vnc-enc-tight.h
diff --git a/ui/vnc-encoding-zlib.c b/ui/vnc-enc-zlib.c
similarity index 100%
rename from ui/vnc-encoding-zlib.c
rename to ui/vnc-enc-zlib.c
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 06/18] vnc: tight: don't forget do at the last color
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (4 preceding siblings ...)
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 05/18] vnc: rename vnc-encoding-* vnc-enc-* Corentin Chary
@ 2010-07-07 18:57 ` Corentin Chary
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 07/18] vnc: tight: remove a memleak in send_jpeg_rect() Corentin Chary
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

While using indexed colors, the last color was never added to the palette.
Triggered with ubuntu livecd.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 ui/vnc-enc-tight.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index 358221d..ade8e5f 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -393,11 +393,11 @@ static int tight_palette_insert(QDict *palette, uint32_t rgb, int bpp, int max)
             if (data[i] == ci) {                                        \
                 continue;                                               \
             } else {                                                    \
+                ci = data[i];                                           \
                 if (!tight_palette_insert(*palette, (uint32_t)ci,       \
                                           bpp, max)) {                  \
                     return 0;                                           \
                 }                                                       \
-                ci = data[i];                                           \
             }                                                           \
         }                                                               \
                                                                         \
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 07/18] vnc: tight: remove a memleak in send_jpeg_rect()
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (5 preceding siblings ...)
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 06/18] vnc: tight: don't forget do at the last color Corentin Chary
@ 2010-07-07 18:57 ` Corentin Chary
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 08/18] vnc: tight add PNG encoding Corentin Chary
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

buf was never freed.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 ui/vnc-enc-tight.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index ade8e5f..4ff88a8 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -1247,8 +1247,6 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
     if (ds_get_bytes_per_pixel(vs->ds) == 1)
         return send_full_color_rect(vs, w, h);
 
-    buf = qemu_malloc(w * 3);
-    row[0] = buf;
     buffer_reserve(&vs->tight_jpeg, 2048);
 
     cinfo.err = jpeg_std_error(&jerr);
@@ -1270,10 +1268,13 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
 
     jpeg_start_compress(&cinfo, true);
 
+    buf = qemu_malloc(w * 3);
+    row[0] = buf;
     for (dy = 0; dy < h; dy++) {
         jpeg_prepare_row(vs, buf, x, y + dy, w);
         jpeg_write_scanlines(&cinfo, row, 1);
     }
+    qemu_free(buf);
 
     jpeg_finish_compress(&cinfo);
     jpeg_destroy_compress(&cinfo);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 08/18] vnc: tight add PNG encoding
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (6 preceding siblings ...)
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 07/18] vnc: tight: remove a memleak in send_jpeg_rect() Corentin Chary
@ 2010-07-07 18:57 ` Corentin Chary
  2010-07-08  9:48   ` Daniel P. Berrange
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 09/18] vnc: tight: specific zlib level and filters for each compression level Corentin Chary
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

Introduce a new encoding: VNC_ENCODING_TIGHT_PNG [1] (-269) with a new
tight filter VNC_TIGHT_PNG (0x0A). When the client tells it supports the Tight PNG
encoding, the server will use tight, but will always send encoding pixels using
PNG instead of zlib. If the client also told it support JPEG, then the server can
send JPEG, because PNG will only be used in the cases zlib was used in normal tight.

This encoding was introduced to speed up HTML5 based VNC clients like noVNC [2], but
can also be used on devices like iPhone where PNG can be rendered in hardware.

[1] http://wiki.qemu.org/VNC_Tight_PNG
[2] http://github.com/kanaka/noVNC/

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 Makefile.target    |    1 +
 configure          |   37 ++++++
 ui/vnc-enc-tight.c |  316 +++++++++++++++++++++++++++++++++++++++++++++-------
 ui/vnc-enc-tight.h |   16 ++-
 ui/vnc.c           |   11 +-
 ui/vnc.h           |   15 +++-
 6 files changed, 342 insertions(+), 54 deletions(-)

diff --git a/Makefile.target b/Makefile.target
index eb801df..fa9ec0d 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -178,6 +178,7 @@ LIBS+=-lz
 QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
 QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
+QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
 
 # xen backend driver support
 obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
diff --git a/configure b/configure
index 27791b5..eba9606 100755
--- a/configure
+++ b/configure
@@ -269,6 +269,7 @@ vde=""
 vnc_tls=""
 vnc_sasl=""
 vnc_jpeg=""
+vnc_png=""
 xen=""
 linux_aio=""
 attr=""
@@ -580,6 +581,10 @@ for opt do
   ;;
   --enable-vnc-jpeg) vnc_jpeg="yes"
   ;;
+  --disable-vnc-png) vnc_png="no"
+  ;;
+  --enable-vnc-png) vnc_png="yes"
+  ;;
   --disable-slirp) slirp="no"
   ;;
   --disable-uuid) uuid="no"
@@ -832,6 +837,8 @@ echo "  --disable-vnc-sasl       disable SASL encryption for VNC server"
 echo "  --enable-vnc-sasl        enable SASL encryption for VNC server"
 echo "  --disable-vnc-jpeg       disable JPEG lossy compression for VNC server"
 echo "  --enable-vnc-jpeg        enable JPEG lossy compression for VNC server"
+echo "  --disable-vnc-png        disable PNG compression for VNC server"
+echo "  --enable-vnc-png         enable PNG compression for VNC server"
 echo "  --disable-curses         disable curses output"
 echo "  --enable-curses          enable curses output"
 echo "  --disable-curl           disable curl connectivity"
@@ -1274,6 +1281,31 @@ EOF
 fi
 
 ##########################################
+# VNC PNG detection
+if test "$vnc_png" = "yes" ; then
+cat > $TMPC <<EOF
+//#include <stdio.h>
+#include <png.h>
+int main(void) {
+    png_structp png_ptr;
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    return 0;
+}
+EOF
+    vnc_png_cflags=""
+    vnc_png_libs="-lpng"
+  if compile_prog "$vnc_png_cflags" "$vnc_png_libs" ; then
+    vnc_png=yes
+    libs_softmmu="$vnc_png_libs $libs_softmmu"
+  else
+    if test "$vnc_png" = "yes" ; then
+      feature_not_found "vnc-png"
+    fi
+    vnc_png=no
+  fi
+fi
+
+##########################################
 # fnmatch() probe, used for ACL routines
 fnmatch="no"
 cat > $TMPC << EOF
@@ -2123,6 +2155,7 @@ echo "Mixer emulation   $mixemu"
 echo "VNC TLS support   $vnc_tls"
 echo "VNC SASL support  $vnc_sasl"
 echo "VNC JPEG support  $vnc_jpeg"
+echo "VNC PNG support   $vnc_png"
 if test -n "$sparc_cpu"; then
     echo "Target Sparc Arch $sparc_cpu"
 fi
@@ -2264,6 +2297,10 @@ if test "$vnc_jpeg" = "yes" ; then
   echo "CONFIG_VNC_JPEG=y" >> $config_host_mak
   echo "VNC_JPEG_CFLAGS=$vnc_jpeg_cflags" >> $config_host_mak
 fi
+if test "$vnc_png" = "yes" ; then
+  echo "CONFIG_VNC_PNG=y" >> $config_host_mak
+  echo "VNC_PNG_CFLAGS=$vnc_png_cflags" >> $config_host_mak
+fi
 if test "$fnmatch" = "yes" ; then
   echo "CONFIG_FNMATCH=y" >> $config_host_mak
 fi
diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index 4ff88a8..cc57c26 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -26,13 +26,18 @@
  * THE SOFTWARE.
  */
 
-#include "qemu-common.h"
+#include "config-host.h"
 
+#ifdef CONFIG_VNC_PNG
+#include <png.h>
+#endif
 #ifdef CONFIG_VNC_JPEG
 #include <stdio.h>
 #include <jpeglib.h>
 #endif
 
+#include "qemu-common.h"
+
 #include "bswap.h"
 #include "qdict.h"
 #include "qint.h"
@@ -63,6 +68,29 @@ static const struct {
     { 65536, 2048,  32,  8192, 9, 9, 9, 6, 200, 500,  96, 80,   200,   500 }
 };
 
+
+static int tight_send_framebuffer_update(VncState *vs, int x, int y,
+                                         int w, int h);
+
+#ifdef CONFIG_VNC_PNG
+static int send_png_rect(VncState *vs, int x, int y, int w, int h,
+                         QDict *palette);
+
+static bool tight_can_send_png_rect(VncState *vs, int w, int h)
+{
+    if (vs->tight_type != VNC_ENCODING_TIGHT_PNG) {
+        return false;
+    }
+
+    if (ds_get_bytes_per_pixel(vs->ds) == 1 ||
+        vs->clientds.pf.bytes_per_pixel == 1) {
+        return false;
+    }
+
+    return true;
+}
+#endif
+
 /*
  * Code to guess if given rectangle is suitable for smooth image
  * compression (by applying "gradient" filter or JPEG coder).
@@ -466,6 +494,7 @@ static void print_palette(const char *key, QObject *obj, void *opaque)
         src = (uint##bpp##_t *) buf;                                    \
                                                                         \
         for (i = 0; i < count; i++) {                                   \
+                                                                        \
             rgb = *src++;                                               \
             rep = 0;                                                    \
             while (i < count && *src == rgb) {                          \
@@ -937,11 +966,17 @@ static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret)
     }
 }
 
-static int send_full_color_rect(VncState *vs, int w, int h)
+static int send_full_color_rect(VncState *vs, int x, int y, int w, int h)
 {
     int stream = 0;
     size_t bytes;
 
+#ifdef CONFIG_VNC_PNG
+    if (tight_can_send_png_rect(vs, w, h)) {
+        return send_png_rect(vs, x, y, w, h, NULL);
+    }
+#endif
+
     vnc_write_u8(vs, stream << 4); /* no flushing, no filter */
 
     if (vs->tight_pixel24) {
@@ -975,12 +1010,27 @@ static int send_solid_rect(VncState *vs)
     return 1;
 }
 
-static int send_mono_rect(VncState *vs, int w, int h, uint32_t bg, uint32_t fg)
+static int send_mono_rect(VncState *vs, int x, int y,
+                          int w, int h, uint32_t bg, uint32_t fg)
 {
     size_t bytes;
     int stream = 1;
     int level = tight_conf[vs->tight_compression].mono_zlib_level;
 
+#ifdef CONFIG_VNC_PNG
+    if (tight_can_send_png_rect(vs, w, h)) {
+        int ret;
+        QDict *palette = qdict_new();
+        int bpp = vs->clientds.pf.bytes_per_pixel * 8;
+
+        tight_palette_insert(palette, bg, bpp, 2);
+        tight_palette_insert(palette, fg, bpp, 2);
+        ret = send_png_rect(vs, x, y, w, h, palette);
+        QDECREF(palette);
+        return ret;
+    }
+#endif
+
     bytes = ((w + 7) / 8) * h;
 
     vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
@@ -1021,6 +1071,9 @@ static int send_mono_rect(VncState *vs, int w, int h, uint32_t bg, uint32_t fg)
 struct palette_cb_priv {
     VncState *vs;
     uint8_t *header;
+#ifdef CONFIG_VNC_PNG
+    png_colorp png_palette;
+#endif
 };
 
 static void write_palette(const char *key, QObject *obj, void *opaque)
@@ -1041,14 +1094,14 @@ static void write_palette(const char *key, QObject *obj, void *opaque)
     }
 }
 
-static bool send_gradient_rect(VncState *vs, int w, int h)
+static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
 {
     int stream = 3;
     int level = tight_conf[vs->tight_compression].gradient_zlib_level;
     size_t bytes;
 
     if (vs->clientds.pf.bytes_per_pixel == 1)
-        return send_full_color_rect(vs, w, h);
+        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);
@@ -1076,13 +1129,20 @@ static bool send_gradient_rect(VncState *vs, int w, int h)
     return (bytes >= 0);
 }
 
-static int send_palette_rect(VncState *vs, int w, int h, struct QDict *palette)
+static int send_palette_rect(VncState *vs, int x, int y,
+                             int w, int h, struct QDict *palette)
 {
     int stream = 2;
     int level = tight_conf[vs->tight_compression].idx_zlib_level;
     int colors;
     size_t bytes;
 
+#ifdef CONFIG_VNC_PNG
+    if (tight_can_send_png_rect(vs, w, h)) {
+        return send_png_rect(vs, x, y, w, h, palette);
+    }
+#endif
+
     colors = qdict_size(palette);
 
     vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
@@ -1130,12 +1190,9 @@ static int send_palette_rect(VncState *vs, int w, int h, struct QDict *palette)
     return (bytes >= 0);
 }
 
-/*
- * JPEG compression stuff.
- */
-#ifdef CONFIG_VNC_JPEG
-static void jpeg_prepare_row24(VncState *vs, uint8_t *dst, int x, int y,
-                                     int count)
+#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;
@@ -1152,11 +1209,11 @@ static void jpeg_prepare_row24(VncState *vs, uint8_t *dst, int x, int y,
     }
 }
 
-#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp)                               \
+#define DEFINE_RGB_GET_ROW_FUNCTION(bpp)                                \
                                                                         \
     static void                                                         \
-    jpeg_prepare_row##bpp(VncState *vs, uint8_t *dst,                   \
-                                int x, int y, int count)                \
+    rgb_prepare_row##bpp(VncState *vs, uint8_t *dst,                    \
+                         int x, int y, int count)                       \
     {                                                                   \
         VncDisplay *vd = vs->vd;                                        \
         uint##bpp##_t *fbptr;                                           \
@@ -1186,21 +1243,26 @@ static void jpeg_prepare_row24(VncState *vs, uint8_t *dst, int x, int y,
         }                                                               \
     }
 
-DEFINE_JPEG_GET_ROW_FUNCTION(16)
-DEFINE_JPEG_GET_ROW_FUNCTION(32)
+DEFINE_RGB_GET_ROW_FUNCTION(16)
+DEFINE_RGB_GET_ROW_FUNCTION(32)
 
-static void jpeg_prepare_row(VncState *vs, uint8_t *dst, int x, int y,
-                                       int count)
+static void rgb_prepare_row(VncState *vs, uint8_t *dst, int x, int y,
+                            int count)
 {
     if (vs->tight_pixel24)
-        jpeg_prepare_row24(vs, dst, x, y, count);
+        rgb_prepare_row24(vs, dst, x, y, count);
     else if (ds_get_bytes_per_pixel(vs->ds) == 4)
-        jpeg_prepare_row32(vs, dst, x, y, count);
+        rgb_prepare_row32(vs, dst, x, y, count);
     else
-        jpeg_prepare_row16(vs, dst, x, y, count);
+        rgb_prepare_row16(vs, dst, x, y, count);
 }
+#endif /* CONFIG_VNC_JPEG or CONFIG_VNC_PNG */
 
 /*
+ * JPEG compression stuff.
+ */
+#ifdef CONFIG_VNC_JPEG
+/*
  * Destination manager implementation for JPEG library.
  */
 
@@ -1245,7 +1307,7 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
     int dy;
 
     if (ds_get_bytes_per_pixel(vs->ds) == 1)
-        return send_full_color_rect(vs, w, h);
+        return send_full_color_rect(vs, x, y, w, h);
 
     buffer_reserve(&vs->tight_jpeg, 2048);
 
@@ -1271,7 +1333,7 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
     buf = qemu_malloc(w * 3);
     row[0] = buf;
     for (dy = 0; dy < h; dy++) {
-        jpeg_prepare_row(vs, buf, x, y + dy, w);
+        rgb_prepare_row(vs, buf, x, y + dy, w);
         jpeg_write_scanlines(&cinfo, row, 1);
     }
     qemu_free(buf);
@@ -1289,6 +1351,162 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
 }
 #endif /* CONFIG_VNC_JPEG */
 
+/*
+ * PNG compression stuff.
+ */
+#ifdef CONFIG_VNC_PNG
+static void write_png_palette(const char *key, QObject *obj, void *opaque)
+{
+    struct palette_cb_priv *priv = opaque;
+    VncState *vs = priv->vs;
+    uint32_t bytes = vs->clientds.pf.bytes_per_pixel;
+    uint8_t idx = qint_get_int(qobject_to_qint(obj));
+    png_colorp color = &priv->png_palette[idx];
+    uint32_t pix;
+
+    if (bytes == 4) {
+        pix = tight_palette_buf2rgb(32, (uint8_t *)key);
+    } else {
+        pix = tight_palette_buf2rgb(16, (uint8_t *)key);
+    }
+
+    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;
+    }
+    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);
+    }
+}
+
+static void png_write_data(png_structp png_ptr, png_bytep data,
+                           png_size_t length)
+{
+    VncState *vs = png_get_io_ptr(png_ptr);
+
+    buffer_reserve(&vs->tight_png, vs->tight_png.offset + length);
+    memcpy(vs->tight_png.buffer + vs->tight_png.offset, data, length);
+
+    vs->tight_png.offset += length;
+}
+
+static void png_flush_data(png_structp png_ptr)
+{
+}
+
+static void *vnc_png_malloc(png_structp png_ptr, png_size_t size)
+{
+    return qemu_malloc(size);
+}
+
+static void vnc_png_free(png_structp png_ptr, png_voidp ptr)
+{
+    qemu_free(ptr);
+}
+
+static int send_png_rect(VncState *vs, int x, int y, int w, int h,
+                         QDict *palette)
+{
+    png_byte color_type;
+    png_structp png_ptr;
+    png_infop info_ptr;
+    png_colorp png_palette = NULL;
+    size_t offset;
+    int level = tight_conf[vs->tight_compression].raw_zlib_level;
+    uint8_t *buf;
+    int dy;
+
+    png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL,
+                                        NULL, vnc_png_malloc, vnc_png_free);
+
+    if (png_ptr == NULL)
+        return -1;
+
+    info_ptr = png_create_info_struct(png_ptr);
+
+    if (info_ptr == NULL) {
+        png_destroy_write_struct(&png_ptr, NULL);
+        return -1;
+    }
+
+    png_set_write_fn(png_ptr, (void *) vs, png_write_data, png_flush_data);
+    png_set_compression_level(png_ptr, level);
+
+    if (palette) {
+        color_type = PNG_COLOR_TYPE_PALETTE;
+    } else {
+        color_type = PNG_COLOR_TYPE_RGB;
+    }
+
+    png_set_IHDR(png_ptr, info_ptr, w, h,
+                 8, color_type, PNG_INTERLACE_NONE,
+                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+    if (color_type == PNG_COLOR_TYPE_PALETTE) {
+        struct palette_cb_priv priv;
+
+        png_palette = png_malloc(png_ptr, sizeof(*png_palette) *
+                                 qdict_size(palette));
+
+        priv.vs = vs;
+        priv.png_palette = png_palette;
+        qdict_iter(palette, write_png_palette, &priv);
+
+        png_set_PLTE(png_ptr, info_ptr, png_palette, qdict_size(palette));
+
+        offset = vs->tight.offset;
+        if (vs->clientds.pf.bytes_per_pixel == 4) {
+            tight_encode_indexed_rect32(vs->tight.buffer, w * h, palette);
+        } else {
+            tight_encode_indexed_rect16(vs->tight.buffer, w * h, palette);
+        }
+    }
+
+    png_write_info(png_ptr, info_ptr);
+
+    buffer_reserve(&vs->tight_png, 2048);
+    buf = qemu_malloc(w * 3);
+    for (dy = 0; dy < h; dy++)
+    {
+        if (color_type == PNG_COLOR_TYPE_PALETTE) {
+            memcpy(buf, vs->tight.buffer + (dy * w), w);
+        } else {
+            rgb_prepare_row(vs, buf, x, y + dy, w);
+        }
+        png_write_row(png_ptr, buf);
+    }
+    qemu_free(buf);
+
+    png_write_end(png_ptr, NULL);
+
+    if (color_type == PNG_COLOR_TYPE_PALETTE) {
+        png_free(png_ptr, png_palette);
+    }
+
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+
+    vnc_write_u8(vs, VNC_TIGHT_PNG << 4);
+
+    tight_send_compact_size(vs, vs->tight_png.offset);
+    vnc_write(vs, vs->tight_png.buffer, vs->tight_png.offset);
+    buffer_reset(&vs->tight_png);
+    return 1;
+}
+#endif /* CONFIG_VNC_PNG */
+
 static void vnc_tight_start(VncState *vs)
 {
     buffer_reset(&vs->tight);
@@ -1312,7 +1530,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
     int colors;
     int ret = 0;
 
-    vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT);
+    vnc_framebuffer_update(vs, x, y, w, h, vs->tight_type);
 
     vnc_tight_start(vs);
     vnc_raw_send_framebuffer_update(vs, x, y, w, h);
@@ -1323,23 +1541,23 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
     if (colors == 0) {
         if (tight_detect_smooth_image(vs, w, h)) {
             if (vs->tight_quality == -1) {
-                ret = send_gradient_rect(vs, w, h);
+                ret = send_gradient_rect(vs, x, y, w, h);
             } else {
 #ifdef CONFIG_VNC_JPEG
                 int quality = tight_conf[vs->tight_quality].jpeg_quality;
 
                 ret = send_jpeg_rect(vs, x, y, w, h, quality);
 #else
-                ret = send_full_color_rect(vs, w, h);
+                ret = send_full_color_rect(vs, x, y, w, h);
 #endif
             }
         } else {
-            ret = send_full_color_rect(vs, w, h);
+            ret = send_full_color_rect(vs, x, y, w, h);
         }
     } else if (colors == 1) {
         ret = send_solid_rect(vs);
     } else if (colors == 2) {
-        ret = send_mono_rect(vs, w, h, bg, fg);
+        ret = send_mono_rect(vs, x, y, w, h, bg, fg);
     } else if (colors <= 256) {
 #ifdef CONFIG_VNC_JPEG
         if (colors > 96 && vs->tight_quality != -1 && vs->tight_quality <= 3 &&
@@ -1348,10 +1566,10 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
 
             ret = send_jpeg_rect(vs, x, y, w, h, quality);
         } else {
-            ret = send_palette_rect(vs, w, h, palette);
+            ret = send_palette_rect(vs, x, y, w, h, palette);
         }
 #else
-        ret = send_palette_rect(vs, w, h, palette);
+        ret = send_palette_rect(vs, x, y, w, h, palette);
 #endif
     }
     QDECREF(palette);
@@ -1360,7 +1578,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
 
 static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
 {
-    vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT);
+    vnc_framebuffer_update(vs, x, y, w, h, vs->tight_type);
 
     vnc_tight_start(vs);
     vnc_raw_send_framebuffer_update(vs, x, y, w, h);
@@ -1453,8 +1671,8 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y,
                 n += send_rect_simple(vs, x, y, w, y_best-y);
             }
             if (x_best != x) {
-                n += vnc_tight_send_framebuffer_update(vs, x, y_best,
-                                                       x_best-x, h_best);
+                n += tight_send_framebuffer_update(vs, x, y_best,
+                                                   x_best-x, h_best);
             }
 
             /* Send solid-color rectangle. */
@@ -1463,14 +1681,14 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y,
             /* Send remaining rectangles (at right and bottom). */
 
             if (x_best + w_best != x + w) {
-                n += vnc_tight_send_framebuffer_update(vs, x_best+w_best,
-                                                       y_best,
-                                                       w-(x_best-x)-w_best,
-                                                       h_best);
+                n += tight_send_framebuffer_update(vs, x_best+w_best,
+                                                   y_best,
+                                                   w-(x_best-x)-w_best,
+                                                   h_best);
             }
             if (y_best + h_best != y + h) {
-                n += vnc_tight_send_framebuffer_update(vs, x, y_best+h_best,
-                                                       w, h-(y_best-y)-h_best);
+                n += tight_send_framebuffer_update(vs, x, y_best+h_best,
+                                                   w, h-(y_best-y)-h_best);
             }
 
             /* Return after all recursive calls are done. */
@@ -1480,8 +1698,8 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y,
     return n + send_rect_simple(vs, x, y, w, h);
 }
 
-int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
-                                      int w, int h)
+static int tight_send_framebuffer_update(VncState *vs, int x, int y,
+                                         int w, int h)
 {
     int max_rows;
 
@@ -1503,6 +1721,20 @@ int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
     return find_large_solid_color_rect(vs, x, y, w, h, max_rows);
 }
 
+int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
+                                      int w, int h)
+{
+    vs->tight_type = VNC_ENCODING_TIGHT;
+    return tight_send_framebuffer_update(vs, x, y, w, h);
+}
+
+int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
+                                          int w, int h)
+{
+    vs->tight_type = VNC_ENCODING_TIGHT_PNG;
+    return tight_send_framebuffer_update(vs, x, y, w, h);
+}
+
 void vnc_tight_clear(VncState *vs)
 {
     int i;
diff --git a/ui/vnc-enc-tight.h b/ui/vnc-enc-tight.h
index 9b0910c..a3add78 100644
--- a/ui/vnc-enc-tight.h
+++ b/ui/vnc-enc-tight.h
@@ -42,8 +42,9 @@
  *   bit 3:    if 1, then compression stream 3 should be reset;
  *   bits 7-4: if 1000 (0x08), then the compression type is "fill",
  *             if 1001 (0x09), then the compression type is "jpeg",
+ *             if 1010 (0x0A), then the compression type is "png",
  *             if 0xxx, then the compression type is "basic",
- *             values greater than 1001 are not valid.
+ *             values greater than 1010 are not valid.
  *
  * If the compression type is "basic", then bits 6..4 of the
  * compression control byte (those xxx in 0xxx) specify the following:
@@ -53,17 +54,17 @@
  *   bit 6:     if 1, then a "filter id" byte is following this byte.
  *
  *-- The data that follows after the compression control byte described
- * above depends on the compression type ("fill", "jpeg" or "basic").
+ * above depends on the compression type ("fill", "jpeg", "png" or "basic").
  *
  *-- If the compression type is "fill", then the only pixel value follows, in
  * client pixel format (see NOTE 1). This value applies to all pixels of the
  * rectangle.
  *
- *-- If the compression type is "jpeg", the following data stream looks like
- * this:
+ *-- If the compression type is "jpeg" or "png", the following data stream
+ * looks like this:
  *
  *   1..3 bytes:  data size (N) in compact representation;
- *   N bytes:     JPEG image.
+ *   N bytes:     JPEG or PNG image.
  *
  * Data size is compactly represented in one, two or three bytes, according
  * to the following scheme:
@@ -144,7 +145,7 @@
  *-- NOTE 2. The decoder must reset compression streams' states before
  * decoding the rectangle, if some of bits 0,1,2,3 in the compression control
  * byte are set to 1. Note that the decoder must reset zlib streams even if
- * the compression type is "fill" or "jpeg".
+ * the compression type is "fill", "jpeg" or "png".
  *
  *-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only
  * when bits-per-pixel value is either 16 or 32, not 8.
@@ -158,7 +159,8 @@
 #define VNC_TIGHT_EXPLICIT_FILTER       0x04
 #define VNC_TIGHT_FILL                  0x08
 #define VNC_TIGHT_JPEG                  0x09
-#define VNC_TIGHT_MAX_SUBENCODING       0x09
+#define VNC_TIGHT_PNG                   0x0A
+#define VNC_TIGHT_MAX_SUBENCODING       0x0A
 
 /* Filters to improve compression efficiency */
 #define VNC_TIGHT_FILTER_COPY             0x00
diff --git a/ui/vnc.c b/ui/vnc.c
index ccd7aad..1fc6d38 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -351,10 +351,6 @@ void do_info_vnc(Monitor *mon, QObject **ret_data)
     }
 }
 
-static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
-    return (vs->features & (1 << feature));
-}
-
 /* TODO
    1) Get the queue working for IO.
    2) there is some weirdness when using the -S option (the screen is grey
@@ -661,6 +657,9 @@ static int send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
         case VNC_ENCODING_TIGHT:
             n = vnc_tight_send_framebuffer_update(vs, x, y, w, h);
             break;
+        case VNC_ENCODING_TIGHT_PNG:
+            n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h);
+            break;
         default:
             vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW);
             n = vnc_raw_send_framebuffer_update(vs, x, y, w, h);
@@ -1669,6 +1668,10 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
             vs->features |= VNC_FEATURE_TIGHT_MASK;
             vs->vnc_encoding = enc;
             break;
+        case VNC_ENCODING_TIGHT_PNG:
+            vs->features |= VNC_FEATURE_TIGHT_PNG_MASK;
+            vs->vnc_encoding = enc;
+            break;
         case VNC_ENCODING_ZLIB:
             vs->features |= VNC_FEATURE_ZLIB_MASK;
             vs->vnc_encoding = enc;
diff --git a/ui/vnc.h b/ui/vnc.h
index ec90cd3..3b8b911 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -172,6 +172,7 @@ struct VncState
     /* Encoding specific */
 
     /* Tight */
+    int tight_type;
     uint8_t tight_quality;
     uint8_t tight_compression;
     uint8_t tight_pixel24;
@@ -182,6 +183,9 @@ struct VncState
 #ifdef CONFIG_VNC_JPEG
     Buffer tight_jpeg;
 #endif
+#ifdef CONFIG_VNC_PNG
+    Buffer tight_png;
+#endif
     int tight_levels[4];
     z_stream tight_stream[4];
 
@@ -259,6 +263,7 @@ enum {
 #define VNC_ENCODING_POINTER_TYPE_CHANGE  0XFFFFFEFF /* -257 */
 #define VNC_ENCODING_EXT_KEY_EVENT        0XFFFFFEFE /* -258 */
 #define VNC_ENCODING_AUDIO                0XFFFFFEFD /* -259 */
+#define VNC_ENCODING_TIGHT_PNG            0xFFFFFEFC /* -260 */
 #define VNC_ENCODING_WMVi                 0x574D5669
 
 /*****************************************************************************
@@ -275,6 +280,7 @@ enum {
 #define VNC_TIGHT_CCB_TYPE_MASK    (0x0f << 4)
 #define VNC_TIGHT_CCB_TYPE_FILL    (0x08 << 4)
 #define VNC_TIGHT_CCB_TYPE_JPEG    (0x09 << 4)
+#define VNC_TIGHT_CCB_TYPE_PNG     (0x0A << 4)
 #define VNC_TIGHT_CCB_BASIC_MAX    (0x07 << 4)
 #define VNC_TIGHT_CCB_BASIC_ZLIB   (0x03 << 4)
 #define VNC_TIGHT_CCB_BASIC_FILTER (0x04 << 4)
@@ -293,6 +299,7 @@ enum {
 #define VNC_FEATURE_ZLIB                     5
 #define VNC_FEATURE_COPYRECT                 6
 #define VNC_FEATURE_RICH_CURSOR              7
+#define VNC_FEATURE_TIGHT_PNG                8
 
 #define VNC_FEATURE_RESIZE_MASK              (1 << VNC_FEATURE_RESIZE)
 #define VNC_FEATURE_HEXTILE_MASK             (1 << VNC_FEATURE_HEXTILE)
@@ -302,6 +309,7 @@ enum {
 #define VNC_FEATURE_ZLIB_MASK                (1 << VNC_FEATURE_ZLIB)
 #define VNC_FEATURE_COPYRECT_MASK            (1 << VNC_FEATURE_COPYRECT)
 #define VNC_FEATURE_RICH_CURSOR_MASK         (1 << VNC_FEATURE_RICH_CURSOR)
+#define VNC_FEATURE_TIGHT_PNG_MASK           (1 << VNC_FEATURE_TIGHT_PNG)
 
 
 /* Client -> Server message IDs */
@@ -405,6 +413,10 @@ void buffer_append(Buffer *buffer, const void *data, size_t len);
 char *vnc_socket_local_addr(const char *format, int fd);
 char *vnc_socket_remote_addr(const char *format, int fd);
 
+static inline uint32_t vnc_has_feature(VncState *vs, int feature) {
+    return (vs->features & (1 << feature));
+}
+
 /* Framebuffer */
 void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
                             int32_t encoding);
@@ -423,8 +435,9 @@ void vnc_zlib_zfree(void *x, void *addr);
 int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
 void vnc_zlib_clear(VncState *vs);
 
-
 int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
+                                          int w, int h);
 void vnc_tight_clear(VncState *vs);
 
 #endif /* __QEMU_VNC_H */
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 09/18] vnc: tight: specific zlib level and filters for each compression level
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (7 preceding siblings ...)
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 08/18] vnc: tight add PNG encoding Corentin Chary
@ 2010-07-07 18:57 ` Corentin Chary
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 10/18] vnc: tight: stop using qdict for palette stuff Corentin Chary
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

Disable png filters for lower compression levels. This should lower
the CPU consumption and reduce encoding time.

This isn't in tight_conf because:
* tight_conf structure must not change, because it's shared with other
  tight implementations (libvncserver, etc..).
* it'd exceed the 80 col limit.
* PNG_ macros are only defined if CONFIG_VNC_PNG is defined

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 ui/vnc-enc-tight.c |   19 ++++++++++++++++++-
 1 files changed, 18 insertions(+), 1 deletions(-)

diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index cc57c26..e627e00 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -73,6 +73,21 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
                                          int w, int h);
 
 #ifdef CONFIG_VNC_PNG
+static const struct {
+    int png_zlib_level, png_filters;
+} tight_png_conf[] = {
+    { 0, PNG_NO_FILTERS },
+    { 1, PNG_NO_FILTERS },
+    { 2, PNG_NO_FILTERS },
+    { 3, PNG_NO_FILTERS },
+    { 4, PNG_NO_FILTERS },
+    { 5, PNG_ALL_FILTERS },
+    { 6, PNG_ALL_FILTERS },
+    { 7, PNG_ALL_FILTERS },
+    { 8, PNG_ALL_FILTERS },
+    { 9, PNG_ALL_FILTERS },
+};
+
 static int send_png_rect(VncState *vs, int x, int y, int w, int h,
                          QDict *palette);
 
@@ -1425,7 +1440,8 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
     png_infop info_ptr;
     png_colorp png_palette = NULL;
     size_t offset;
-    int level = tight_conf[vs->tight_compression].raw_zlib_level;
+    int level = tight_png_conf[vs->tight_compression].png_zlib_level;
+    int filters = tight_png_conf[vs->tight_compression].png_filters;
     uint8_t *buf;
     int dy;
 
@@ -1444,6 +1460,7 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
 
     png_set_write_fn(png_ptr, (void *) vs, png_write_data, png_flush_data);
     png_set_compression_level(png_ptr, level);
+    png_set_filter(png_ptr, PNG_FILTER_TYPE_DEFAULT, filters);
 
     if (palette) {
         color_type = PNG_COLOR_TYPE_PALETTE;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 10/18] vnc: tight: stop using qdict for palette stuff
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (8 preceding siblings ...)
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 09/18] vnc: tight: specific zlib level and filters for each compression level Corentin Chary
@ 2010-07-07 18:57 ` Corentin Chary
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 11/18] vnc: encapsulate encoding members Corentin Chary
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

Profiling with callgrind seems to show that a lot of time is spent
in the palette code (mostly due to memory allocation and qdict to int
conversion).

This patch adds a VncPalette implementation. The palette is stored
in a hash table, like qdict, but which does way less memory allocations,
and doesn't suffer from the QObject overhead.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 Makefile.objs      |    2 +-
 ui/vnc-enc-tight.c |  163 +++++++++++----------------------------------------
 ui/vnc-palette.c   |  136 +++++++++++++++++++++++++++++++++++++++++++
 ui/vnc-palette.h   |   63 ++++++++++++++++++++
 4 files changed, 235 insertions(+), 129 deletions(-)
 create mode 100644 ui/vnc-palette.c
 create mode 100644 ui/vnc-palette.h

diff --git a/Makefile.objs b/Makefile.objs
index a0b8200..bb9806c 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -107,7 +107,7 @@ ui-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
 ui-obj-$(CONFIG_CURSES) += curses.o
 ui-obj-y += vnc.o d3des.o
 ui-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o
-ui-obj-y += vnc-enc-tight.o
+ui-obj-y += vnc-enc-tight.o vnc-palette.o
 ui-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
 ui-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
 ui-obj-$(CONFIG_COCOA) += cocoa.o
diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index e627e00..49a456d 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -39,10 +39,10 @@
 #include "qemu-common.h"
 
 #include "bswap.h"
-#include "qdict.h"
 #include "qint.h"
 #include "vnc.h"
 #include "vnc-enc-tight.h"
+#include "vnc-palette.h"
 
 /* Compression level stuff. The following array contains various
    encoder parameters for each of 10 compression levels (0..9).
@@ -89,7 +89,7 @@ static const struct {
 };
 
 static int send_png_rect(VncState *vs, int x, int y, int w, int h,
-                         QDict *palette);
+                         VncPalette *palette);
 
 static bool tight_can_send_png_rect(VncState *vs, int w, int h)
 {
@@ -313,74 +313,13 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
 /*
  * Code to determine how many different colors used in rectangle.
  */
-
-static void tight_palette_rgb2buf(uint32_t rgb, int bpp, uint8_t buf[6])
-{
-    memset(buf, 0, 6);
-
-    if (bpp == 32) {
-        buf[0] = ((rgb >> 24) & 0xFF);
-        buf[1] = ((rgb >> 16) & 0xFF);
-        buf[2] = ((rgb >>  8) & 0xFF);
-        buf[3] = ((rgb >>  0) & 0xFF);
-        buf[4] = ((buf[0] & 1) == 0) << 3 | ((buf[1] & 1) == 0) << 2;
-        buf[4]|= ((buf[2] & 1) == 0) << 1 | ((buf[3] & 1) == 0) << 0;
-        buf[0] |= 1;
-        buf[1] |= 1;
-        buf[2] |= 1;
-        buf[3] |= 1;
-    }
-    if (bpp == 16) {
-        buf[0] = ((rgb >> 8) & 0xFF);
-        buf[1] = ((rgb >> 0) & 0xFF);
-        buf[2] = ((buf[0] & 1) == 0) << 1 | ((buf[1] & 1) == 0) << 0;
-        buf[0] |= 1;
-        buf[1] |= 1;
-    }
-}
-
-static uint32_t tight_palette_buf2rgb(int bpp, const uint8_t *buf)
-{
-    uint32_t rgb = 0;
-
-    if (bpp == 32) {
-        rgb |= ((buf[0] & ~1) | !((buf[4] >> 3) & 1)) << 24;
-        rgb |= ((buf[1] & ~1) | !((buf[4] >> 2) & 1)) << 16;
-        rgb |= ((buf[2] & ~1) | !((buf[4] >> 1) & 1)) <<  8;
-        rgb |= ((buf[3] & ~1) | !((buf[4] >> 0) & 1)) <<  0;
-    }
-    if (bpp == 16) {
-        rgb |= ((buf[0] & ~1) | !((buf[2] >> 1) & 1)) << 8;
-        rgb |= ((buf[1] & ~1) | !((buf[2] >> 0) & 1)) << 0;
-    }
-    return rgb;
-}
-
-
-static int tight_palette_insert(QDict *palette, uint32_t rgb, int bpp, int max)
-{
-    uint8_t key[6];
-    int idx = qdict_size(palette);
-    bool present;
-
-    tight_palette_rgb2buf(rgb, bpp, key);
-    present = qdict_haskey(palette, (char *)key);
-    if (idx >= max && !present) {
-        return 0;
-    }
-    if (!present) {
-        qdict_put(palette, (char *)key, qint_from_int(idx));
-    }
-    return qdict_size(palette);
-}
-
 #define DEFINE_FILL_PALETTE_FUNCTION(bpp)                               \
                                                                         \
     static int                                                          \
     tight_fill_palette##bpp(VncState *vs, int x, int y,                 \
                             int max, size_t count,                      \
                             uint32_t *bg, uint32_t *fg,                 \
-                            struct QDict **palette) {                   \
+                            VncPalette **palette) {                     \
         uint##bpp##_t *data;                                            \
         uint##bpp##_t c0, c1, ci;                                       \
         int i, n0, n1;                                                  \
@@ -427,24 +366,23 @@ static int tight_palette_insert(QDict *palette, uint32_t rgb, int bpp, int max)
             return 0;                                                   \
         }                                                               \
                                                                         \
-        *palette = qdict_new();                                         \
-        tight_palette_insert(*palette, c0, bpp, max);                   \
-        tight_palette_insert(*palette, c1, bpp, max);                   \
-        tight_palette_insert(*palette, ci, bpp, max);                   \
+        *palette = palette_new(max, bpp);                               \
+        palette_put(*palette, c0);                                      \
+        palette_put(*palette, c1);                                      \
+        palette_put(*palette, ci);                                      \
                                                                         \
         for (i++; i < count; i++) {                                     \
             if (data[i] == ci) {                                        \
                 continue;                                               \
             } else {                                                    \
                 ci = data[i];                                           \
-                if (!tight_palette_insert(*palette, (uint32_t)ci,       \
-                                          bpp, max)) {                  \
+                if (!palette_put(*palette, (uint32_t)ci)) {             \
                     return 0;                                           \
                 }                                                       \
             }                                                           \
         }                                                               \
                                                                         \
-        return qdict_size(*palette);                                    \
+        return palette_size(*palette);                                  \
     }
 
 DEFINE_FILL_PALETTE_FUNCTION(8)
@@ -453,7 +391,7 @@ DEFINE_FILL_PALETTE_FUNCTION(32)
 
 static int tight_fill_palette(VncState *vs, int x, int y,
                               size_t count, uint32_t *bg, uint32_t *fg,
-                              struct QDict **palette)
+                              VncPalette **palette)
 {
     int max;
 
@@ -478,20 +416,6 @@ static int tight_fill_palette(VncState *vs, int x, int y,
     return 0;
 }
 
-/* Callback to dump a palette with qdict_iter
-static void print_palette(const char *key, QObject *obj, void *opaque)
-{
-    uint8_t idx = qint_get_int(qobject_to_qint(obj));
-    uint32_t rgb = tight_palette_buf2rgb(32, (uint8_t *)key);
-
-    fprintf(stderr, "%.2x ", (unsigned char)*key);
-    while (*key++)
-        fprintf(stderr, "%.2x ", (unsigned char)*key);
-
-    fprintf(stderr, ": idx: %x rgb: %x\n", idx, rgb);
-}
-*/
-
 /*
  * Converting truecolor samples into palette indices.
  */
@@ -499,10 +423,9 @@ static void print_palette(const char *key, QObject *obj, void *opaque)
                                                                         \
     static void                                                         \
     tight_encode_indexed_rect##bpp(uint8_t *buf, int count,             \
-                                   struct QDict *palette) {             \
+                                   VncPalette *palette) {               \
         uint##bpp##_t *src;                                             \
         uint##bpp##_t rgb;                                              \
-        uint8_t key[6];                                                 \
         int i, rep;                                                     \
         uint8_t idx;                                                    \
                                                                         \
@@ -515,15 +438,13 @@ static void print_palette(const char *key, QObject *obj, void *opaque)
             while (i < count && *src == rgb) {                          \
                 rep++, src++, i++;                                      \
             }                                                           \
-            tight_palette_rgb2buf(rgb, bpp, key);                       \
-            if (!qdict_haskey(palette, (char *)key)) {                  \
-                /*                                                      \
-                 * Should never happen, but don't break everything      \
-                 * if it does, use the first color instead              \
-                 */                                                     \
+            idx = palette_idx(palette, rgb);                            \
+            /*                                                          \
+             * Should never happen, but don't break everything          \
+             * if it does, use the first color instead                  \
+             */                                                         \
+            if (idx == -1) {                                            \
                 idx = 0;                                                \
-            } else {                                                    \
-                idx = qdict_get_int(palette, (char *)key);              \
             }                                                           \
             while (rep >= 0) {                                          \
                 *buf++ = idx;                                           \
@@ -1035,13 +956,13 @@ 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;
-        QDict *palette = qdict_new();
         int bpp = vs->clientds.pf.bytes_per_pixel * 8;
+        VncPalette *palette = palette_new(2, bpp);
 
-        tight_palette_insert(palette, bg, bpp, 2);
-        tight_palette_insert(palette, fg, bpp, 2);
+        palette_put(palette, bg);
+        palette_put(palette, fg);
         ret = send_png_rect(vs, x, y, w, h, palette);
-        QDECREF(palette);
+        palette_destroy(palette);
         return ret;
     }
 #endif
@@ -1091,20 +1012,15 @@ struct palette_cb_priv {
 #endif
 };
 
-static void write_palette(const char *key, QObject *obj, void *opaque)
+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;
-    uint8_t idx = qint_get_int(qobject_to_qint(obj));
 
     if (bytes == 4) {
-        uint32_t color = tight_palette_buf2rgb(32, (uint8_t *)key);
-
         ((uint32_t*)priv->header)[idx] = color;
     } else {
-        uint16_t color = tight_palette_buf2rgb(16, (uint8_t *)key);
-
         ((uint16_t*)priv->header)[idx] = color;
     }
 }
@@ -1145,7 +1061,7 @@ static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
 }
 
 static int send_palette_rect(VncState *vs, int x, int y,
-                             int w, int h, struct QDict *palette)
+                             int w, int h, VncPalette *palette)
 {
     int stream = 2;
     int level = tight_conf[vs->tight_compression].idx_zlib_level;
@@ -1158,7 +1074,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
     }
 #endif
 
-    colors = qdict_size(palette);
+    colors = palette_size(palette);
 
     vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
     vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
@@ -1168,11 +1084,11 @@ static int send_palette_rect(VncState *vs, int x, int y,
     case 4:
     {
         size_t old_offset, offset;
-        uint32_t header[qdict_size(palette)];
+        uint32_t header[palette_size(palette)];
         struct palette_cb_priv priv = { vs, (uint8_t *)header };
 
         old_offset = vs->output.offset;
-        qdict_iter(palette, write_palette, &priv);
+        palette_iter(palette, write_palette, &priv);
         vnc_write(vs, header, sizeof(header));
 
         if (vs->tight_pixel24) {
@@ -1185,10 +1101,10 @@ static int send_palette_rect(VncState *vs, int x, int y,
     }
     case 2:
     {
-        uint16_t header[qdict_size(palette)];
+        uint16_t header[palette_size(palette)];
         struct palette_cb_priv priv = { vs, (uint8_t *)header };
 
-        qdict_iter(palette, write_palette, &priv);
+        palette_iter(palette, write_palette, &priv);
         vnc_write(vs, header, sizeof(header));
         tight_encode_indexed_rect16(vs->tight.buffer, w * h, palette);
         break;
@@ -1370,20 +1286,11 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
  * PNG compression stuff.
  */
 #ifdef CONFIG_VNC_PNG
-static void write_png_palette(const char *key, QObject *obj, void *opaque)
+static void write_png_palette(int idx, uint32_t pix, void *opaque)
 {
     struct palette_cb_priv *priv = opaque;
     VncState *vs = priv->vs;
-    uint32_t bytes = vs->clientds.pf.bytes_per_pixel;
-    uint8_t idx = qint_get_int(qobject_to_qint(obj));
     png_colorp color = &priv->png_palette[idx];
-    uint32_t pix;
-
-    if (bytes == 4) {
-        pix = tight_palette_buf2rgb(32, (uint8_t *)key);
-    } else {
-        pix = tight_palette_buf2rgb(16, (uint8_t *)key);
-    }
 
     if (vs->tight_pixel24)
     {
@@ -1433,7 +1340,7 @@ static void vnc_png_free(png_structp png_ptr, png_voidp ptr)
 }
 
 static int send_png_rect(VncState *vs, int x, int y, int w, int h,
-                         QDict *palette)
+                         VncPalette *palette)
 {
     png_byte color_type;
     png_structp png_ptr;
@@ -1476,13 +1383,13 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
         struct palette_cb_priv priv;
 
         png_palette = png_malloc(png_ptr, sizeof(*png_palette) *
-                                 qdict_size(palette));
+                                 palette_size(palette));
 
         priv.vs = vs;
         priv.png_palette = png_palette;
-        qdict_iter(palette, write_png_palette, &priv);
+        palette_iter(palette, write_png_palette, &priv);
 
-        png_set_PLTE(png_ptr, info_ptr, png_palette, qdict_size(palette));
+        png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette));
 
         offset = vs->tight.offset;
         if (vs->clientds.pf.bytes_per_pixel == 4) {
@@ -1542,7 +1449,7 @@ static void vnc_tight_stop(VncState *vs)
 
 static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
 {
-    struct QDict *palette = NULL;
+    VncPalette *palette = NULL;
     uint32_t bg = 0, fg = 0;
     int colors;
     int ret = 0;
@@ -1589,7 +1496,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
         ret = send_palette_rect(vs, x, y, w, h, palette);
 #endif
     }
-    QDECREF(palette);
+    palette_destroy(palette);
     return ret;
 }
 
diff --git a/ui/vnc-palette.c b/ui/vnc-palette.c
new file mode 100644
index 0000000..bff6445
--- /dev/null
+++ b/ui/vnc-palette.c
@@ -0,0 +1,136 @@
+/*
+ * QEMU VNC display driver: palette hash table
+ *
+ * From libvncserver/libvncserver/tight.c
+ * Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vnc-palette.h"
+
+static VncPaletteEntry *palette_find(const VncPalette *palette,
+                                     uint32_t color, unsigned int hash)
+{
+    VncPaletteEntry *entry;
+
+    QLIST_FOREACH(entry, &palette->table[hash], next) {
+        if (entry->color == color) {
+            return entry;
+        }
+    }
+
+    return NULL;
+}
+
+static unsigned int palette_hash(uint32_t rgb, int bpp)
+{
+    if (bpp == 16) {
+        return ((unsigned int)(((rgb >> 8) + rgb) & 0xFF));
+    } else {
+        return ((unsigned int)(((rgb >> 16) + (rgb >> 8)) & 0xFF));
+    }
+}
+
+VncPalette *palette_new(size_t max, int bpp)
+{
+    VncPalette *palette;
+
+    palette = qemu_mallocz(sizeof(*palette));
+    palette->max = max;
+    palette->bpp = bpp;
+    return palette;
+}
+
+void palette_destroy(VncPalette *palette)
+{
+    int i;
+
+    if (palette == NULL) {
+        return ;
+    }
+
+    for (i = 0; i < VNC_PALETTE_HASH_SIZE; i++) {
+        VncPaletteEntry *entry = QLIST_FIRST(&palette->table[i]);
+        while (entry) {
+            VncPaletteEntry *tmp = QLIST_NEXT(entry, next);
+            QLIST_REMOVE(entry, next);
+            qemu_free(entry);
+            entry = tmp;
+        }
+    }
+
+    qemu_free(palette);
+}
+
+int palette_put(VncPalette *palette, uint32_t color)
+{
+    unsigned int hash;
+    unsigned int idx = palette->size;
+    VncPaletteEntry *entry;
+
+    hash = palette_hash(color, palette->bpp) % VNC_PALETTE_HASH_SIZE;
+    entry = palette_find(palette, color, hash);
+
+    if (!entry && palette->size >= palette->max) {
+        return 0;
+    }
+    if (!entry) {
+        VncPaletteEntry *entry;
+
+        entry = qemu_mallocz(sizeof(*entry));
+        entry->color = color;
+        entry->idx = idx;
+        QLIST_INSERT_HEAD(&palette->table[hash], entry, next);
+        palette->size++;
+    }
+    return palette->size;
+}
+
+int palette_idx(const VncPalette *palette, uint32_t color)
+{
+    VncPaletteEntry *entry;
+    unsigned int hash;
+
+    hash = palette_hash(color, palette->bpp) % VNC_PALETTE_HASH_SIZE;
+    entry = palette_find(palette, color, hash);
+    return (entry == NULL ? -1 : entry->idx);
+}
+
+size_t palette_size(const VncPalette *palette)
+{
+    return palette->size;
+}
+
+void palette_iter(const VncPalette *palette,
+                  void (*iter)(int idx, uint32_t color, void *opaque),
+                  void *opaque)
+{
+    int i;
+    VncPaletteEntry *entry;
+
+    for (i = 0; i < VNC_PALETTE_HASH_SIZE; i++) {
+        QLIST_FOREACH(entry, &palette->table[i], next) {
+            iter(entry->idx, entry->color, opaque);
+        }
+    }
+}
diff --git a/ui/vnc-palette.h b/ui/vnc-palette.h
new file mode 100644
index 0000000..d0645eb
--- /dev/null
+++ b/ui/vnc-palette.h
@@ -0,0 +1,63 @@
+/*
+ * QEMU VNC display driver: palette hash table
+ *
+ * From libvncserver/libvncserver/tight.c
+ * Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef VNC_PALETTE_H
+#define VNC_PALETTE_H
+
+#include "qlist.h"
+#include "qemu-queue.h"
+#include <stdint.h>
+
+#define VNC_PALETTE_HASH_SIZE 256
+
+typedef struct VncPaletteEntry {
+    int idx;
+    uint32_t color;
+    QLIST_ENTRY(VncPaletteEntry) next;
+} VncPaletteEntry;
+
+typedef struct VncPalette {
+    QObject_HEAD;
+    size_t size;
+    size_t max;
+    int bpp;
+    QLIST_HEAD(,VncPaletteEntry) table[VNC_PALETTE_HASH_SIZE];
+} VncPalette;
+
+VncPalette *palette_new(size_t max, int bpp);
+void palette_destroy(VncPalette *palette);
+
+int palette_put(VncPalette *palette, uint32_t color);
+int palette_idx(const VncPalette *palette, uint32_t color);
+size_t palette_size(const VncPalette *palette);
+
+void palette_iter(const VncPalette *palette,
+                  void (*iter)(int idx, uint32_t color, void *opaque),
+                  void *opaque);
+
+#endif /* VNC_PALETTE_H */
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 11/18] vnc: encapsulate encoding members
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (9 preceding siblings ...)
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 10/18] vnc: tight: stop using qdict for palette stuff Corentin Chary
@ 2010-07-07 18:57 ` Corentin Chary
  2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 12/18] vnc: fix tight png memory leak Corentin Chary
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

This will allow to implement the threaded VNC server in a
more cleaner way.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 ui/vnc-enc-hextile.c |   14 ++--
 ui/vnc-enc-tight.c   |  204 +++++++++++++++++++++++++-------------------------
 ui/vnc-enc-zlib.c    |   34 ++++----
 ui/vnc.c             |    8 +-
 ui/vnc.h             |   59 ++++++++-------
 5 files changed, 163 insertions(+), 156 deletions(-)

diff --git a/ui/vnc-enc-hextile.c b/ui/vnc-enc-hextile.c
index fa4b264..364a491 100644
--- a/ui/vnc-enc-hextile.c
+++ b/ui/vnc-enc-hextile.c
@@ -75,7 +75,7 @@ int vnc_hextile_send_framebuffer_update(VncState *vs, int x,
     has_fg = has_bg = 0;
     for (j = y; j < (y + h); j += 16) {
         for (i = x; i < (x + w); i += 16) {
-            vs->send_hextile_tile(vs, i, j,
+            vs->hextile.send_tile(vs, i, j,
                                   MIN(16, x + w - i), MIN(16, y + h - j),
                                   last_bg, last_fg, &has_bg, &has_fg);
         }
@@ -91,25 +91,25 @@ void vnc_hextile_set_pixel_conversion(VncState *vs, int generic)
     if (!generic) {
         switch (vs->ds->surface->pf.bits_per_pixel) {
             case 8:
-                vs->send_hextile_tile = send_hextile_tile_8;
+                vs->hextile.send_tile = send_hextile_tile_8;
                 break;
             case 16:
-                vs->send_hextile_tile = send_hextile_tile_16;
+                vs->hextile.send_tile = send_hextile_tile_16;
                 break;
             case 32:
-                vs->send_hextile_tile = send_hextile_tile_32;
+                vs->hextile.send_tile = send_hextile_tile_32;
                 break;
         }
     } else {
         switch (vs->ds->surface->pf.bits_per_pixel) {
             case 8:
-                vs->send_hextile_tile = send_hextile_tile_generic_8;
+                vs->hextile.send_tile = send_hextile_tile_generic_8;
                 break;
             case 16:
-                vs->send_hextile_tile = send_hextile_tile_generic_16;
+                vs->hextile.send_tile = send_hextile_tile_generic_16;
                 break;
             case 32:
-                vs->send_hextile_tile = send_hextile_tile_generic_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 49a456d..52b81f3 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -93,7 +93,7 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
 
 static bool tight_can_send_png_rect(VncState *vs, int w, int h)
 {
-    if (vs->tight_type != VNC_ENCODING_TIGHT_PNG) {
+    if (vs->tight.type != VNC_ENCODING_TIGHT_PNG) {
         return false;
     }
 
@@ -121,7 +121,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
     int pixels = 0;
     int pix, left[3];
     uint errors;
-    unsigned char *buf = vs->tight.buffer;
+    unsigned char *buf = vs->tight.tight.buffer;
 
     /*
      * If client is big-endian, color samples begin from the second
@@ -188,7 +188,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
         int pixels = 0;                                                 \
         int sample, sum, left[3];                                       \
         uint errors;                                                    \
-        unsigned char *buf = vs->tight.buffer;                          \
+        unsigned char *buf = vs->tight.tight.buffer;                    \
                                                                         \
         endian = ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) !=        \
                   (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG));     \
@@ -268,8 +268,8 @@ static int
 tight_detect_smooth_image(VncState *vs, int w, int h)
 {
     uint errors;
-    int compression = vs->tight_compression;
-    int quality = vs->tight_quality;
+    int compression = vs->tight.compression;
+    int quality = vs->tight.quality;
 
     if (!vs->vd->lossy) {
         return 0;
@@ -281,7 +281,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
         return 0;
     }
 
-    if (vs->tight_quality != -1) {
+    if (vs->tight.quality != -1) {
         if (w * h < VNC_TIGHT_JPEG_MIN_RECT_SIZE) {
             return 0;
         }
@@ -292,9 +292,9 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
     }
 
     if (vs->clientds.pf.bytes_per_pixel == 4) {
-        if (vs->tight_pixel24) {
+        if (vs->tight.pixel24) {
             errors = tight_detect_smooth_image24(vs, w, h);
-            if (vs->tight_quality != -1) {
+            if (vs->tight.quality != -1) {
                 return (errors < tight_conf[quality].jpeg_threshold24);
             }
             return (errors < tight_conf[compression].gradient_threshold24);
@@ -324,7 +324,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
         uint##bpp##_t c0, c1, ci;                                       \
         int i, n0, n1;                                                  \
                                                                         \
-        data = (uint##bpp##_t *)vs->tight.buffer;                       \
+        data = (uint##bpp##_t *)vs->tight.tight.buffer;                 \
                                                                         \
         c0 = data[0];                                                   \
         i = 1;                                                          \
@@ -395,9 +395,9 @@ static int tight_fill_palette(VncState *vs, int x, int y,
 {
     int max;
 
-    max = count / tight_conf[vs->tight_compression].idx_max_colors_divisor;
+    max = count / tight_conf[vs->tight.compression].idx_max_colors_divisor;
     if (max < 2 &&
-        count >= tight_conf[vs->tight_compression].mono_min_rect_size) {
+        count >= tight_conf[vs->tight.compression].mono_min_rect_size) {
         max = 2;
     }
     if (max >= 256) {
@@ -529,7 +529,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
     int x, y, c;
 
     buf32 = (uint32_t *)buf;
-    memset(vs->tight_gradient.buffer, 0, w * 3 * sizeof(int));
+    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)) {
@@ -547,7 +547,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
             upper[c] = 0;
             here[c] = 0;
         }
-        prev = (int *)vs->tight_gradient.buffer;
+        prev = (int *)vs->tight.gradient.buffer;
         for (x = 0; x < w; x++) {
             pix32 = *buf32++;
             for (c = 0; c < 3; c++) {
@@ -587,7 +587,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
         int prediction;                                                 \
         int x, y, c;                                                    \
                                                                         \
-        memset (vs->tight_gradient.buffer, 0, w * 3 * sizeof(int));     \
+        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));     \
@@ -604,7 +604,7 @@ tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h)
                 upper[c] = 0;                                           \
                 here[c] = 0;                                            \
             }                                                           \
-            prev = (int *)vs->tight_gradient.buffer;                    \
+            prev = (int *)vs->tight.gradient.buffer;                    \
             for (x = 0; x < w; x++) {                                   \
                 pix = *buf;                                             \
                 if (endian) {                                           \
@@ -774,7 +774,7 @@ static void extend_solid_area(VncState *vs, int x, int y, int w, int h,
 static int tight_init_stream(VncState *vs, int stream_id,
                              int level, int strategy)
 {
-    z_streamp zstream = &vs->tight_stream[stream_id];
+    z_streamp zstream = &vs->tight.stream[stream_id];
 
     if (zstream->opaque == NULL) {
         int err;
@@ -792,15 +792,15 @@ static int tight_init_stream(VncState *vs, int stream_id,
             return -1;
         }
 
-        vs->tight_levels[stream_id] = level;
+        vs->tight.levels[stream_id] = level;
         zstream->opaque = vs;
     }
 
-    if (vs->tight_levels[stream_id] != level) {
+    if (vs->tight.levels[stream_id] != level) {
         if (deflateParams(zstream, level, strategy) != Z_OK) {
             return -1;
         }
-        vs->tight_levels[stream_id] = level;
+        vs->tight.levels[stream_id] = level;
     }
     return 0;
 }
@@ -828,11 +828,11 @@ static void tight_send_compact_size(VncState *vs, size_t len)
 static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
                                int level, int strategy)
 {
-    z_streamp zstream = &vs->tight_stream[stream_id];
+    z_streamp zstream = &vs->tight.stream[stream_id];
     int previous_out;
 
     if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) {
-        vnc_write(vs, vs->tight.buffer, vs->tight.offset);
+        vnc_write(vs, vs->tight.tight.buffer, vs->tight.tight.offset);
         return bytes;
     }
 
@@ -841,13 +841,13 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
     }
 
     /* reserve memory in output buffer */
-    buffer_reserve(&vs->tight_zlib, bytes + 64);
+    buffer_reserve(&vs->tight.zlib, bytes + 64);
 
     /* set pointers */
-    zstream->next_in = vs->tight.buffer;
-    zstream->avail_in = vs->tight.offset;
-    zstream->next_out = vs->tight_zlib.buffer + vs->tight_zlib.offset;
-    zstream->avail_out = vs->tight_zlib.capacity - vs->tight_zlib.offset;
+    zstream->next_in = vs->tight.tight.buffer;
+    zstream->avail_in = vs->tight.tight.offset;
+    zstream->next_out = vs->tight.zlib.buffer + vs->tight.zlib.offset;
+    zstream->avail_out = vs->tight.zlib.capacity - vs->tight.zlib.offset;
     zstream->data_type = Z_BINARY;
     previous_out = zstream->total_out;
 
@@ -857,13 +857,13 @@ static int tight_compress_data(VncState *vs, int stream_id, size_t bytes,
         return -1;
     }
 
-    vs->tight_zlib.offset = vs->tight_zlib.capacity - zstream->avail_out;
+    vs->tight.zlib.offset = vs->tight.zlib.capacity - zstream->avail_out;
     bytes = zstream->total_out - previous_out;
 
     tight_send_compact_size(vs, bytes);
-    vnc_write(vs, vs->tight_zlib.buffer, bytes);
+    vnc_write(vs, vs->tight.zlib.buffer, bytes);
 
-    buffer_reset(&vs->tight_zlib);
+    buffer_reset(&vs->tight.zlib);
 
     return bytes;
 }
@@ -915,15 +915,15 @@ static int send_full_color_rect(VncState *vs, int x, int y, int w, int h)
 
     vnc_write_u8(vs, stream << 4); /* no flushing, no filter */
 
-    if (vs->tight_pixel24) {
-        tight_pack24(vs, vs->tight.buffer, w * h, &vs->tight.offset);
+    if (vs->tight.pixel24) {
+        tight_pack24(vs, vs->tight.tight.buffer, w * h, &vs->tight.tight.offset);
         bytes = 3;
     } else {
         bytes = vs->clientds.pf.bytes_per_pixel;
     }
 
     bytes = tight_compress_data(vs, stream, w * h * bytes,
-                                tight_conf[vs->tight_compression].raw_zlib_level,
+                                tight_conf[vs->tight.compression].raw_zlib_level,
                                 Z_DEFAULT_STRATEGY);
 
     return (bytes >= 0);
@@ -935,14 +935,14 @@ static int send_solid_rect(VncState *vs)
 
     vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */
 
-    if (vs->tight_pixel24) {
-        tight_pack24(vs, vs->tight.buffer, 1, &vs->tight.offset);
+    if (vs->tight.pixel24) {
+        tight_pack24(vs, vs->tight.tight.buffer, 1, &vs->tight.tight.offset);
         bytes = 3;
     } else {
         bytes = vs->clientds.pf.bytes_per_pixel;
     }
 
-    vnc_write(vs, vs->tight.buffer, bytes);
+    vnc_write(vs, vs->tight.tight.buffer, bytes);
     return 1;
 }
 
@@ -951,7 +951,7 @@ static int send_mono_rect(VncState *vs, int x, int y,
 {
     size_t bytes;
     int stream = 1;
-    int level = tight_conf[vs->tight_compression].mono_zlib_level;
+    int level = tight_conf[vs->tight.compression].mono_zlib_level;
 
 #ifdef CONFIG_VNC_PNG
     if (tight_can_send_png_rect(vs, w, h)) {
@@ -979,26 +979,26 @@ static int send_mono_rect(VncState *vs, int x, int y,
         uint32_t buf[2] = {bg, fg};
         size_t ret = sizeof (buf);
 
-        if (vs->tight_pixel24) {
+        if (vs->tight.pixel24) {
             tight_pack24(vs, (unsigned char*)buf, 2, &ret);
         }
         vnc_write(vs, buf, ret);
 
-        tight_encode_mono_rect32(vs->tight.buffer, w, h, bg, fg);
+        tight_encode_mono_rect32(vs->tight.tight.buffer, w, h, bg, fg);
         break;
     }
     case 2:
         vnc_write(vs, &bg, 2);
         vnc_write(vs, &fg, 2);
-        tight_encode_mono_rect16(vs->tight.buffer, w, h, bg, fg);
+        tight_encode_mono_rect16(vs->tight.tight.buffer, w, h, bg, fg);
         break;
     default:
         vnc_write_u8(vs, bg);
         vnc_write_u8(vs, fg);
-        tight_encode_mono_rect8(vs->tight.buffer, w, h, bg, fg);
+        tight_encode_mono_rect8(vs->tight.tight.buffer, w, h, bg, fg);
         break;
     }
-    vs->tight.offset = bytes;
+    vs->tight.tight.offset = bytes;
 
     bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
     return (bytes >= 0);
@@ -1028,7 +1028,7 @@ static void write_palette(int idx, uint32_t color, void *opaque)
 static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
 {
     int stream = 3;
-    int level = tight_conf[vs->tight_compression].gradient_zlib_level;
+    int level = tight_conf[vs->tight.compression].gradient_zlib_level;
     size_t bytes;
 
     if (vs->clientds.pf.bytes_per_pixel == 1)
@@ -1037,23 +1037,23 @@ static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h)
     vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
     vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT);
 
-    buffer_reserve(&vs->tight_gradient, w * 3 * sizeof (int));
+    buffer_reserve(&vs->tight.gradient, w * 3 * sizeof (int));
 
-    if (vs->tight_pixel24) {
-        tight_filter_gradient24(vs, vs->tight.buffer, w, 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) {
-        tight_filter_gradient32(vs, (uint32_t *)vs->tight.buffer, w, h);
+        tight_filter_gradient32(vs, (uint32_t *)vs->tight.tight.buffer, w, h);
         bytes = 4;
     } else {
-        tight_filter_gradient16(vs, (uint16_t *)vs->tight.buffer, w, h);
+        tight_filter_gradient16(vs, (uint16_t *)vs->tight.tight.buffer, w, h);
         bytes = 2;
     }
 
-    buffer_reset(&vs->tight_gradient);
+    buffer_reset(&vs->tight.gradient);
 
     bytes = w * h * bytes;
-    vs->tight.offset = bytes;
+    vs->tight.tight.offset = bytes;
 
     bytes = tight_compress_data(vs, stream, bytes,
                                 level, Z_FILTERED);
@@ -1064,7 +1064,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
                              int w, int h, VncPalette *palette)
 {
     int stream = 2;
-    int level = tight_conf[vs->tight_compression].idx_zlib_level;
+    int level = tight_conf[vs->tight.compression].idx_zlib_level;
     int colors;
     size_t bytes;
 
@@ -1091,12 +1091,12 @@ static int send_palette_rect(VncState *vs, int x, int y,
         palette_iter(palette, write_palette, &priv);
         vnc_write(vs, header, sizeof(header));
 
-        if (vs->tight_pixel24) {
+        if (vs->tight.pixel24) {
             tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset);
             vs->output.offset = old_offset + offset;
         }
 
-        tight_encode_indexed_rect32(vs->tight.buffer, w * h, palette);
+        tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
         break;
     }
     case 2:
@@ -1106,7 +1106,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
 
         palette_iter(palette, write_palette, &priv);
         vnc_write(vs, header, sizeof(header));
-        tight_encode_indexed_rect16(vs->tight.buffer, w * h, palette);
+        tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
         break;
     }
     default:
@@ -1114,7 +1114,7 @@ static int send_palette_rect(VncState *vs, int x, int y,
         break;
     }
     bytes = w * h;
-    vs->tight.offset = bytes;
+    vs->tight.tight.offset = bytes;
 
     bytes = tight_compress_data(vs, stream, bytes,
                                 level, Z_DEFAULT_STRATEGY);
@@ -1180,7 +1180,7 @@ DEFINE_RGB_GET_ROW_FUNCTION(32)
 static void rgb_prepare_row(VncState *vs, uint8_t *dst, int x, int y,
                             int count)
 {
-    if (vs->tight_pixel24)
+    if (vs->tight.pixel24)
         rgb_prepare_row24(vs, dst, x, y, count);
     else if (ds_get_bytes_per_pixel(vs->ds) == 4)
         rgb_prepare_row32(vs, dst, x, y, count);
@@ -1201,7 +1201,7 @@ static void rgb_prepare_row(VncState *vs, uint8_t *dst, int x, int y,
 static void jpeg_init_destination(j_compress_ptr cinfo)
 {
     VncState *vs = cinfo->client_data;
-    Buffer *buffer = &vs->tight_jpeg;
+    Buffer *buffer = &vs->tight.jpeg;
 
     cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset;
     cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset);
@@ -1211,7 +1211,7 @@ static void jpeg_init_destination(j_compress_ptr cinfo)
 static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
 {
     VncState *vs = cinfo->client_data;
-    Buffer *buffer = &vs->tight_jpeg;
+    Buffer *buffer = &vs->tight.jpeg;
 
     buffer->offset = buffer->capacity;
     buffer_reserve(buffer, 2048);
@@ -1223,7 +1223,7 @@ static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo)
 static void jpeg_term_destination(j_compress_ptr cinfo)
 {
     VncState *vs = cinfo->client_data;
-    Buffer *buffer = &vs->tight_jpeg;
+    Buffer *buffer = &vs->tight.jpeg;
 
     buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer;
 }
@@ -1240,7 +1240,7 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
     if (ds_get_bytes_per_pixel(vs->ds) == 1)
         return send_full_color_rect(vs, x, y, w, h);
 
-    buffer_reserve(&vs->tight_jpeg, 2048);
+    buffer_reserve(&vs->tight.jpeg, 2048);
 
     cinfo.err = jpeg_std_error(&jerr);
     jpeg_create_compress(&cinfo);
@@ -1274,9 +1274,9 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality)
 
     vnc_write_u8(vs, VNC_TIGHT_JPEG << 4);
 
-    tight_send_compact_size(vs, vs->tight_jpeg.offset);
-    vnc_write(vs, vs->tight_jpeg.buffer, vs->tight_jpeg.offset);
-    buffer_reset(&vs->tight_jpeg);
+    tight_send_compact_size(vs, vs->tight.jpeg.offset);
+    vnc_write(vs, vs->tight.jpeg.buffer, vs->tight.jpeg.offset);
+    buffer_reset(&vs->tight.jpeg);
 
     return 1;
 }
@@ -1292,7 +1292,7 @@ static void write_png_palette(int idx, uint32_t pix, void *opaque)
     VncState *vs = priv->vs;
     png_colorp color = &priv->png_palette[idx];
 
-    if (vs->tight_pixel24)
+    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;
@@ -1319,10 +1319,10 @@ static void png_write_data(png_structp png_ptr, png_bytep data,
 {
     VncState *vs = png_get_io_ptr(png_ptr);
 
-    buffer_reserve(&vs->tight_png, vs->tight_png.offset + length);
-    memcpy(vs->tight_png.buffer + vs->tight_png.offset, data, length);
+    buffer_reserve(&vs->tight.png, vs->tight.png.offset + length);
+    memcpy(vs->tight.png.buffer + vs->tight.png.offset, data, length);
 
-    vs->tight_png.offset += length;
+    vs->tight.png.offset += length;
 }
 
 static void png_flush_data(png_structp png_ptr)
@@ -1347,8 +1347,8 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
     png_infop info_ptr;
     png_colorp png_palette = NULL;
     size_t offset;
-    int level = tight_png_conf[vs->tight_compression].png_zlib_level;
-    int filters = tight_png_conf[vs->tight_compression].png_filters;
+    int level = tight_png_conf[vs->tight.compression].png_zlib_level;
+    int filters = tight_png_conf[vs->tight.compression].png_filters;
     uint8_t *buf;
     int dy;
 
@@ -1391,22 +1391,22 @@ 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));
 
-        offset = vs->tight.offset;
+        offset = vs->tight.tight.offset;
         if (vs->clientds.pf.bytes_per_pixel == 4) {
-            tight_encode_indexed_rect32(vs->tight.buffer, w * h, palette);
+            tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette);
         } else {
-            tight_encode_indexed_rect16(vs->tight.buffer, w * h, palette);
+            tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette);
         }
     }
 
     png_write_info(png_ptr, info_ptr);
 
-    buffer_reserve(&vs->tight_png, 2048);
+    buffer_reserve(&vs->tight.png, 2048);
     buf = qemu_malloc(w * 3);
     for (dy = 0; dy < h; dy++)
     {
         if (color_type == PNG_COLOR_TYPE_PALETTE) {
-            memcpy(buf, vs->tight.buffer + (dy * w), w);
+            memcpy(buf, vs->tight.tight.buffer + (dy * w), w);
         } else {
             rgb_prepare_row(vs, buf, x, y + dy, w);
         }
@@ -1424,27 +1424,27 @@ static int send_png_rect(VncState *vs, int x, int y, int w, int h,
 
     vnc_write_u8(vs, VNC_TIGHT_PNG << 4);
 
-    tight_send_compact_size(vs, vs->tight_png.offset);
-    vnc_write(vs, vs->tight_png.buffer, vs->tight_png.offset);
-    buffer_reset(&vs->tight_png);
+    tight_send_compact_size(vs, vs->tight.png.offset);
+    vnc_write(vs, vs->tight.png.buffer, vs->tight.png.offset);
+    buffer_reset(&vs->tight.png);
     return 1;
 }
 #endif /* CONFIG_VNC_PNG */
 
 static void vnc_tight_start(VncState *vs)
 {
-    buffer_reset(&vs->tight);
+    buffer_reset(&vs->tight.tight);
 
     // make the output buffer be the zlib buffer, so we can compress it later
-    vs->tight_tmp = vs->output;
-    vs->output = vs->tight;
+    vs->tight.tmp = vs->output;
+    vs->output = vs->tight.tight;
 }
 
 static void vnc_tight_stop(VncState *vs)
 {
     // switch back to normal output/zlib buffers
-    vs->tight = vs->output;
-    vs->output = vs->tight_tmp;
+    vs->tight.tight = vs->output;
+    vs->output = vs->tight.tmp;
 }
 
 static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
@@ -1454,7 +1454,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
     int colors;
     int ret = 0;
 
-    vnc_framebuffer_update(vs, x, y, w, h, vs->tight_type);
+    vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
 
     vnc_tight_start(vs);
     vnc_raw_send_framebuffer_update(vs, x, y, w, h);
@@ -1464,11 +1464,11 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
 
     if (colors == 0) {
         if (tight_detect_smooth_image(vs, w, h)) {
-            if (vs->tight_quality == -1) {
+            if (vs->tight.quality == -1) {
                 ret = send_gradient_rect(vs, x, y, w, h);
             } else {
 #ifdef CONFIG_VNC_JPEG
-                int quality = tight_conf[vs->tight_quality].jpeg_quality;
+                int quality = tight_conf[vs->tight.quality].jpeg_quality;
 
                 ret = send_jpeg_rect(vs, x, y, w, h, quality);
 #else
@@ -1484,9 +1484,9 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
         ret = send_mono_rect(vs, x, y, w, h, bg, fg);
     } else if (colors <= 256) {
 #ifdef CONFIG_VNC_JPEG
-        if (colors > 96 && vs->tight_quality != -1 && vs->tight_quality <= 3 &&
+        if (colors > 96 && vs->tight.quality != -1 && vs->tight.quality <= 3 &&
             tight_detect_smooth_image(vs, w, h)) {
-            int quality = tight_conf[vs->tight_quality].jpeg_quality;
+            int quality = tight_conf[vs->tight.quality].jpeg_quality;
 
             ret = send_jpeg_rect(vs, x, y, w, h, quality);
         } else {
@@ -1502,7 +1502,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
 
 static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h)
 {
-    vnc_framebuffer_update(vs, x, y, w, h, vs->tight_type);
+    vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
 
     vnc_tight_start(vs);
     vnc_raw_send_framebuffer_update(vs, x, y, w, h);
@@ -1519,8 +1519,8 @@ static int send_rect_simple(VncState *vs, int x, int y, int w, int h)
     int rw, rh;
     int n = 0;
 
-    max_size = tight_conf[vs->tight_compression].max_rect_size;
-    max_width = tight_conf[vs->tight_compression].max_rect_width;
+    max_size = tight_conf[vs->tight.compression].max_rect_size;
+    max_width = tight_conf[vs->tight.compression].max_rect_width;
 
     if (w > max_width || w * h > max_size) {
         max_sub_width = (w > max_width) ? max_width : w;
@@ -1629,9 +1629,9 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
 
     if (vs->clientds.pf.bytes_per_pixel == 4 && vs->clientds.pf.rmax == 0xFF &&
         vs->clientds.pf.bmax == 0xFF && vs->clientds.pf.gmax == 0xFF) {
-        vs->tight_pixel24 = true;
+        vs->tight.pixel24 = true;
     } else {
-        vs->tight_pixel24 = false;
+        vs->tight.pixel24 = false;
     }
 
     if (w * h < VNC_TIGHT_MIN_SPLIT_RECT_SIZE)
@@ -1639,8 +1639,8 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
 
     /* Calculate maximum number of rows in one non-solid rectangle. */
 
-    max_rows = tight_conf[vs->tight_compression].max_rect_size;
-    max_rows /= MIN(tight_conf[vs->tight_compression].max_rect_width, w);
+    max_rows = tight_conf[vs->tight.compression].max_rect_size;
+    max_rows /= MIN(tight_conf[vs->tight.compression].max_rect_width, w);
 
     return find_large_solid_color_rect(vs, x, y, w, h, max_rows);
 }
@@ -1648,30 +1648,30 @@ static int tight_send_framebuffer_update(VncState *vs, int x, int y,
 int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y,
                                       int w, int h)
 {
-    vs->tight_type = VNC_ENCODING_TIGHT;
+    vs->tight.type = VNC_ENCODING_TIGHT;
     return tight_send_framebuffer_update(vs, x, y, w, h);
 }
 
 int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y,
                                           int w, int h)
 {
-    vs->tight_type = VNC_ENCODING_TIGHT_PNG;
+    vs->tight.type = VNC_ENCODING_TIGHT_PNG;
     return tight_send_framebuffer_update(vs, x, y, w, h);
 }
 
 void vnc_tight_clear(VncState *vs)
 {
     int i;
-    for (i=0; i<ARRAY_SIZE(vs->tight_stream); i++) {
-        if (vs->tight_stream[i].opaque) {
-            deflateEnd(&vs->tight_stream[i]);
+    for (i=0; i<ARRAY_SIZE(vs->tight.stream); i++) {
+        if (vs->tight.stream[i].opaque) {
+            deflateEnd(&vs->tight.stream[i]);
         }
     }
 
-    buffer_free(&vs->tight);
-    buffer_free(&vs->tight_zlib);
-    buffer_free(&vs->tight_gradient);
+    buffer_free(&vs->tight.tight);
+    buffer_free(&vs->tight.zlib);
+    buffer_free(&vs->tight.gradient);
 #ifdef CONFIG_VNC_JPEG
-    buffer_free(&vs->tight_jpeg);
+    buffer_free(&vs->tight.jpeg);
 #endif
 }
diff --git a/ui/vnc-enc-zlib.c b/ui/vnc-enc-zlib.c
index a99bc38..3c6e6ab 100644
--- a/ui/vnc-enc-zlib.c
+++ b/ui/vnc-enc-zlib.c
@@ -47,21 +47,21 @@ void vnc_zlib_zfree(void *x, void *addr)
 
 static void vnc_zlib_start(VncState *vs)
 {
-    buffer_reset(&vs->zlib);
+    buffer_reset(&vs->zlib.zlib);
 
     // make the output buffer be the zlib buffer, so we can compress it later
-    vs->zlib_tmp = vs->output;
-    vs->output = vs->zlib;
+    vs->zlib.tmp = vs->output;
+    vs->output = vs->zlib.zlib;
 }
 
 static int vnc_zlib_stop(VncState *vs)
 {
-    z_streamp zstream = &vs->zlib_stream;
+    z_streamp zstream = &vs->zlib.stream;
     int previous_out;
 
     // switch back to normal output/zlib buffers
-    vs->zlib = vs->output;
-    vs->output = vs->zlib_tmp;
+    vs->zlib.zlib = vs->output;
+    vs->output = vs->zlib.tmp;
 
     // compress the zlib buffer
 
@@ -75,7 +75,7 @@ static int vnc_zlib_stop(VncState *vs)
         zstream->zalloc = vnc_zlib_zalloc;
         zstream->zfree = vnc_zlib_zfree;
 
-        err = deflateInit2(zstream, vs->tight_compression, Z_DEFLATED, MAX_WBITS,
+        err = deflateInit2(zstream, vs->tight.compression, Z_DEFLATED, MAX_WBITS,
                            MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
 
         if (err != Z_OK) {
@@ -83,24 +83,24 @@ static int vnc_zlib_stop(VncState *vs)
             return -1;
         }
 
-        vs->zlib_level = vs->tight_compression;
+        vs->zlib.level = vs->tight.compression;
         zstream->opaque = vs;
     }
 
-    if (vs->tight_compression != vs->zlib_level) {
-        if (deflateParams(zstream, vs->tight_compression,
+    if (vs->tight.compression != vs->zlib.level) {
+        if (deflateParams(zstream, vs->tight.compression,
                           Z_DEFAULT_STRATEGY) != Z_OK) {
             return -1;
         }
-        vs->zlib_level = vs->tight_compression;
+        vs->zlib.level = vs->tight.compression;
     }
 
     // reserve memory in output buffer
-    buffer_reserve(&vs->output, vs->zlib.offset + 64);
+    buffer_reserve(&vs->output, vs->zlib.zlib.offset + 64);
 
     // set pointers
-    zstream->next_in = vs->zlib.buffer;
-    zstream->avail_in = vs->zlib.offset;
+    zstream->next_in = vs->zlib.zlib.buffer;
+    zstream->avail_in = vs->zlib.zlib.offset;
     zstream->next_out = vs->output.buffer + vs->output.offset;
     zstream->avail_out = vs->output.capacity - vs->output.offset;
     zstream->data_type = Z_BINARY;
@@ -145,8 +145,8 @@ int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
 
 void vnc_zlib_clear(VncState *vs)
 {
-    if (vs->zlib_stream.opaque) {
-        deflateEnd(&vs->zlib_stream);
+    if (vs->zlib.stream.opaque) {
+        deflateEnd(&vs->zlib.stream);
     }
-    buffer_free(&vs->zlib);
+    buffer_free(&vs->zlib.zlib);
 }
diff --git a/ui/vnc.c b/ui/vnc.c
index 1fc6d38..d0a4b75 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1642,8 +1642,8 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
 
     vs->features = 0;
     vs->vnc_encoding = 0;
-    vs->tight_compression = 9;
-    vs->tight_quality = -1; /* Lossless by default */
+    vs->tight.compression = 9;
+    vs->tight.quality = -1; /* Lossless by default */
     vs->absolute = -1;
 
     /*
@@ -1695,10 +1695,10 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
             vs->features |= VNC_FEATURE_WMVI_MASK;
             break;
         case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
-            vs->tight_compression = (enc & 0x0F);
+            vs->tight.compression = (enc & 0x0F);
             break;
         case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9:
-            vs->tight_quality = (enc & 0x0F);
+            vs->tight.quality = (enc & 0x0F);
             break;
         default:
             VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
diff --git a/ui/vnc.h b/ui/vnc.h
index 3b8b911..344a686 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -122,6 +122,36 @@ struct VncDisplay
 #endif
 };
 
+typedef struct VncTight {
+    int type;
+    uint8_t quality;
+    uint8_t compression;
+    uint8_t pixel24;
+    Buffer tight;
+    Buffer tmp;
+    Buffer zlib;
+    Buffer gradient;
+#ifdef CONFIG_VNC_JPEG
+    Buffer jpeg;
+#endif
+#ifdef CONFIG_VNC_PNG
+    Buffer png;
+#endif
+    int levels[4];
+    z_stream stream[4];
+} VncTight;
+
+typedef struct VncHextile {
+    VncSendHextileTile *send_tile;
+} VncHextile;
+
+typedef struct VncZlib {
+    Buffer zlib;
+    Buffer tmp;
+    z_stream stream;
+    int level;
+} VncZlib;
+
 struct VncState
 {
     int csock;
@@ -170,33 +200,10 @@ struct VncState
     QEMUPutLEDEntry *led;
 
     /* Encoding specific */
+    VncTight tight;
+    VncZlib zlib;
+    VncHextile hextile;
 
-    /* Tight */
-    int tight_type;
-    uint8_t tight_quality;
-    uint8_t tight_compression;
-    uint8_t tight_pixel24;
-    Buffer tight;
-    Buffer tight_tmp;
-    Buffer tight_zlib;
-    Buffer tight_gradient;
-#ifdef CONFIG_VNC_JPEG
-    Buffer tight_jpeg;
-#endif
-#ifdef CONFIG_VNC_PNG
-    Buffer tight_png;
-#endif
-    int tight_levels[4];
-    z_stream tight_stream[4];
-
-    /* Hextile */
-    VncSendHextileTile *send_hextile_tile;
-
-    /* Zlib */
-    Buffer zlib;
-    Buffer zlib_tmp;
-    z_stream zlib_stream;
-    int zlib_level;
 
     Notifier mouse_mode_notifier;
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 12/18] vnc: fix tight png memory leak
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (10 preceding siblings ...)
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 11/18] vnc: encapsulate encoding members Corentin Chary
@ 2010-07-07 18:58 ` Corentin Chary
  2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 13/18] qemu-thread: add qemu_mutex/cond_destroy and qemu_mutex_exit Corentin Chary
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

The tight.png buffer was never released.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 ui/vnc-enc-tight.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index 52b81f3..3f19df2 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -1674,4 +1674,7 @@ void vnc_tight_clear(VncState *vs)
 #ifdef CONFIG_VNC_JPEG
     buffer_free(&vs->tight.jpeg);
 #endif
+#ifdef CONFIG_VNC_PNG
+    buffer_free(&vs->tight.png);
+#endif
 }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 13/18] qemu-thread: add qemu_mutex/cond_destroy and qemu_mutex_exit
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (11 preceding siblings ...)
  2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 12/18] vnc: fix tight png memory leak Corentin Chary
@ 2010-07-07 18:58 ` Corentin Chary
  2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 14/18] vnc: threaded VNC server Corentin Chary
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

Add some missing functions in qemu-thread. Currently qemu-thread
is only used for io-thread but it will used by the vnc server soon
and we need those functions instead of calling pthread directly.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 qemu-thread.c |   22 ++++++++++++++++++++++
 qemu-thread.h |    4 ++++
 2 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/qemu-thread.c b/qemu-thread.c
index faf4061..fbc78fe 100644
--- a/qemu-thread.c
+++ b/qemu-thread.c
@@ -34,6 +34,15 @@ void qemu_mutex_init(QemuMutex *mutex)
         error_exit(err, __func__);
 }
 
+void qemu_mutex_destroy(QemuMutex *mutex)
+{
+    int err;
+
+    err = pthread_mutex_destroy(&mutex->lock);
+    if (err)
+        error_exit(err, __func__);
+}
+
 void qemu_mutex_lock(QemuMutex *mutex)
 {
     int err;
@@ -90,6 +99,15 @@ void qemu_cond_init(QemuCond *cond)
         error_exit(err, __func__);
 }
 
+void qemu_cond_destroy(QemuCond *cond)
+{
+    int err;
+
+    err = pthread_cond_destroy(&cond->cond);
+    if (err)
+        error_exit(err, __func__);
+}
+
 void qemu_cond_signal(QemuCond *cond)
 {
     int err;
@@ -168,3 +186,7 @@ int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2)
    return pthread_equal(thread1->thread, thread2->thread);
 }
 
+void qemu_thread_exit(void *retval)
+{
+    pthread_exit(retval);
+}
diff --git a/qemu-thread.h b/qemu-thread.h
index 5ef4a3a..19bb30c 100644
--- a/qemu-thread.h
+++ b/qemu-thread.h
@@ -20,12 +20,14 @@ typedef struct QemuCond QemuCond;
 typedef struct QemuThread QemuThread;
 
 void qemu_mutex_init(QemuMutex *mutex);
+void qemu_mutex_destroy(QemuMutex *mutex);
 void qemu_mutex_lock(QemuMutex *mutex);
 int qemu_mutex_trylock(QemuMutex *mutex);
 int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs);
 void qemu_mutex_unlock(QemuMutex *mutex);
 
 void qemu_cond_init(QemuCond *cond);
+void qemu_cond_destroy(QemuCond *cond);
 void qemu_cond_signal(QemuCond *cond);
 void qemu_cond_broadcast(QemuCond *cond);
 void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex);
@@ -37,4 +39,6 @@ void qemu_thread_create(QemuThread *thread,
 void qemu_thread_signal(QemuThread *thread, int sig);
 void qemu_thread_self(QemuThread *thread);
 int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2);
+void qemu_thread_exit(void *retval);
+
 #endif
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 14/18] vnc: threaded VNC server
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (12 preceding siblings ...)
  2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 13/18] qemu-thread: add qemu_mutex/cond_destroy and qemu_mutex_exit Corentin Chary
@ 2010-07-07 18:58 ` Corentin Chary
  2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 15/18] vnc: add missing lock for vnc_cursor_define() Corentin Chary
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

Implement a threaded VNC server using the producer-consumer model.
The main thread will push encoding jobs (a list a rectangles to update)
in a queue, and the VNC worker thread will consume that queue and send
framebuffer updates to the output buffer.

The threaded VNC server can be enabled with ./configure --enable-vnc-thread.

If you don't want it, just use ./configure --disable-vnc-thread and a syncrhonous
queue of job will be used (which as exactly the same behavior as the old queue).
If you disable the VNC thread, all thread related code will not be built and there will
be no overhead.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 Makefile.objs       |    7 +-
 configure           |   13 ++
 ui/vnc-jobs-async.c |  331 +++++++++++++++++++++++++++++++++++++++++++++++++++
 ui/vnc-jobs-sync.c  |   73 +++++++++++
 ui/vnc-jobs.h       |   87 ++++++++++++++
 ui/vnc.c            |  144 +++++++++++++++++++----
 ui/vnc.h            |   53 ++++++++-
 7 files changed, 682 insertions(+), 26 deletions(-)
 create mode 100644 ui/vnc-jobs-async.c
 create mode 100644 ui/vnc-jobs-sync.c
 create mode 100644 ui/vnc-jobs.h

diff --git a/Makefile.objs b/Makefile.objs
index bb9806c..4a1eaa1 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -111,10 +111,15 @@ ui-obj-y += vnc-enc-tight.o vnc-palette.o
 ui-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
 ui-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
 ui-obj-$(CONFIG_COCOA) += cocoa.o
+ifdef CONFIG_VNC_THREAD
+ui-obj-y += vnc-jobs-async.o
+else
+ui-obj-y += vnc-jobs-sync.o
+endif
 common-obj-y += $(addprefix ui/, $(ui-obj-y))
 
 common-obj-y += iov.o acl.o
-common-obj-$(CONFIG_IOTHREAD) += qemu-thread.o
+common-obj-$(CONFIG_THREAD) += qemu-thread.o
 common-obj-y += notify.o event_notifier.o
 common-obj-y += qemu-timer.o
 
diff --git a/configure b/configure
index eba9606..c292a33 100755
--- a/configure
+++ b/configure
@@ -270,6 +270,7 @@ vnc_tls=""
 vnc_sasl=""
 vnc_jpeg=""
 vnc_png=""
+vnc_thread=""
 xen=""
 linux_aio=""
 attr=""
@@ -585,6 +586,10 @@ for opt do
   ;;
   --enable-vnc-png) vnc_png="yes"
   ;;
+  --disable-vnc-thread) vnc_thread="no"
+  ;;
+  --enable-vnc-thread) vnc_thread="yes"
+  ;;
   --disable-slirp) slirp="no"
   ;;
   --disable-uuid) uuid="no"
@@ -839,6 +844,8 @@ echo "  --disable-vnc-jpeg       disable JPEG lossy compression for VNC server"
 echo "  --enable-vnc-jpeg        enable JPEG lossy compression for VNC server"
 echo "  --disable-vnc-png        disable PNG compression for VNC server"
 echo "  --enable-vnc-png         enable PNG compression for VNC server"
+echo "  --disable-vnc-thread     disable threaded VNC server"
+echo "  --enable-vnc-thread      enable threaded VNC server"
 echo "  --disable-curses         disable curses output"
 echo "  --enable-curses          enable curses output"
 echo "  --disable-curl           disable curl connectivity"
@@ -2156,6 +2163,7 @@ echo "VNC TLS support   $vnc_tls"
 echo "VNC SASL support  $vnc_sasl"
 echo "VNC JPEG support  $vnc_jpeg"
 echo "VNC PNG support   $vnc_png"
+echo "VNC thread        $vnc_thread"
 if test -n "$sparc_cpu"; then
     echo "Target Sparc Arch $sparc_cpu"
 fi
@@ -2301,6 +2309,10 @@ if test "$vnc_png" = "yes" ; then
   echo "CONFIG_VNC_PNG=y" >> $config_host_mak
   echo "VNC_PNG_CFLAGS=$vnc_png_cflags" >> $config_host_mak
 fi
+if test "$vnc_thread" = "yes" ; then
+  echo "CONFIG_VNC_THREAD=y" >> $config_host_mak
+  echo "CONFIG_THREAD=y" >> $config_host_mak
+fi
 if test "$fnmatch" = "yes" ; then
   echo "CONFIG_FNMATCH=y" >> $config_host_mak
 fi
@@ -2377,6 +2389,7 @@ if test "$xen" = "yes" ; then
 fi
 if test "$io_thread" = "yes" ; then
   echo "CONFIG_IOTHREAD=y" >> $config_host_mak
+  echo "CONFIG_THREAD=y" >> $config_host_mak
 fi
 if test "$linux_aio" = "yes" ; then
   echo "CONFIG_LINUX_AIO=y" >> $config_host_mak
diff --git a/ui/vnc-jobs-async.c b/ui/vnc-jobs-async.c
new file mode 100644
index 0000000..6e9cf08
--- /dev/null
+++ b/ui/vnc-jobs-async.c
@@ -0,0 +1,331 @@
+/*
+ * QEMU VNC display driver
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include "vnc.h"
+#include "vnc-jobs.h"
+
+/*
+ * Locking:
+ *
+ * There is 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.
+ * - 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
+ *
+ * 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
+ * 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;
+    QemuMutex mutex;
+    QemuThread thread;
+    Buffer buffer;
+    bool exit;
+    QTAILQ_HEAD(, VncJob) jobs;
+};
+
+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
+ */
+static VncJobQueue *queue;
+
+static void vnc_lock_queue(VncJobQueue *queue)
+{
+    qemu_mutex_lock(&queue->mutex);
+}
+
+static void vnc_unlock_queue(VncJobQueue *queue)
+{
+    qemu_mutex_unlock(&queue->mutex);
+}
+
+VncJob *vnc_job_new(VncState *vs)
+{
+    VncJob *job = qemu_mallocz(sizeof(VncJob));
+
+    job->vs = vs;
+    vnc_lock_queue(queue);
+    QLIST_INIT(&job->rectangles);
+    vnc_unlock_queue(queue);
+    return job;
+}
+
+int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h)
+{
+    VncRectEntry *entry = qemu_mallocz(sizeof(VncRectEntry));
+
+    entry->rect.x = x;
+    entry->rect.y = y;
+    entry->rect.w = w;
+    entry->rect.h = h;
+
+    vnc_lock_queue(queue);
+    QLIST_INSERT_HEAD(&job->rectangles, entry, next);
+    vnc_unlock_queue(queue);
+    return 1;
+}
+
+void vnc_job_push(VncJob *job)
+{
+    vnc_lock_queue(queue);
+    if (queue->exit || QLIST_EMPTY(&job->rectangles)) {
+        qemu_free(job);
+    } else {
+        QTAILQ_INSERT_TAIL(&queue->jobs, job, next);
+        qemu_cond_broadcast(&queue->cond);
+    }
+    vnc_unlock_queue(queue);
+}
+
+static bool vnc_has_job_locked(VncState *vs)
+{
+    VncJob *job;
+
+    QTAILQ_FOREACH(job, &queue->jobs, next) {
+        if (job->vs == vs || !vs) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool vnc_has_job(VncState *vs)
+{
+    bool ret;
+
+    vnc_lock_queue(queue);
+    ret = vnc_has_job_locked(vs);
+    vnc_unlock_queue(queue);
+    return ret;
+}
+
+void vnc_jobs_clear(VncState *vs)
+{
+    VncJob *job, *tmp;
+
+    vnc_lock_queue(queue);
+    QTAILQ_FOREACH_SAFE(job, &queue->jobs, next, tmp) {
+        if (job->vs == vs || !vs) {
+            QTAILQ_REMOVE(&queue->jobs, job, next);
+        }
+    }
+    vnc_unlock_queue(queue);
+}
+
+void vnc_jobs_join(VncState *vs)
+{
+    vnc_lock_queue(queue);
+    while (vnc_has_job_locked(vs)) {
+        qemu_cond_wait(&queue->cond, &queue->mutex);
+    }
+    vnc_unlock_queue(queue);
+}
+
+/*
+ * Copy data for local use
+ */
+static void vnc_async_encoding_start(VncState *orig, VncState *local)
+{
+    local->vnc_encoding = orig->vnc_encoding;
+    local->features = orig->features;
+    local->ds = orig->ds;
+    local->vd = orig->vd;
+    local->write_pixels = orig->write_pixels;
+    local->clientds = orig->clientds;
+    local->tight = orig->tight;
+    local->zlib = orig->zlib;
+    local->hextile = orig->hextile;
+    local->output =  queue->buffer;
+    local->csock = -1; /* Don't do any network work on this thread */
+
+    buffer_reset(&local->output);
+}
+
+static void vnc_async_encoding_end(VncState *orig, VncState *local)
+{
+    orig->tight = local->tight;
+    orig->zlib = local->zlib;
+    orig->hextile = local->hextile;
+}
+
+static int vnc_worker_thread_loop(VncJobQueue *queue)
+{
+    VncJob *job;
+    VncRectEntry *entry, *tmp;
+    VncState vs;
+    int n_rectangles;
+    int saved_offset;
+    bool flush;
+
+    vnc_lock_queue(queue);
+    while (QTAILQ_EMPTY(&queue->jobs) && !queue->exit) {
+        qemu_cond_wait(&queue->cond, &queue->mutex);
+    }
+    /* Here job can only be NULL if queue->exit is true */
+    job = QTAILQ_FIRST(&queue->jobs);
+    vnc_unlock_queue(queue);
+
+    if (queue->exit) {
+        return -1;
+    }
+
+    vnc_lock_output(job->vs);
+    if (job->vs->csock == -1 || job->vs->abort == true) {
+        goto disconnected;
+    }
+    vnc_unlock_output(job->vs);
+
+    /* Make a local copy of vs and switch output buffers */
+    vnc_async_encoding_start(job->vs, &vs);
+
+    /* Start sending rectangles */
+    n_rectangles = 0;
+    vnc_write_u8(&vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+    vnc_write_u8(&vs, 0);
+    saved_offset = vs.output.offset;
+    vnc_write_u16(&vs, 0);
+
+    vnc_lock_display(job->vs->vd);
+    QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) {
+        int n;
+
+        if (job->vs->csock == -1) {
+            vnc_unlock_display(job->vs->vd);
+            goto disconnected;
+        }
+
+        n = vnc_send_framebuffer_update(&vs, entry->rect.x, entry->rect.y,
+                                        entry->rect.w, entry->rect.h);
+
+        if (n >= 0) {
+            n_rectangles += n;
+        }
+        qemu_free(entry);
+    }
+    vnc_unlock_display(job->vs->vd);
+
+    /* Put n_rectangles at the beginning of the message */
+    vs.output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
+    vs.output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
+
+    /* Switch back buffers */
+    vnc_lock_output(job->vs);
+    if (job->vs->csock == -1) {
+        goto disconnected;
+    }
+
+    vnc_write(job->vs, vs.output.buffer, vs.output.offset);
+
+disconnected:
+    /* Copy persistent encoding data */
+    vnc_async_encoding_end(job->vs, &vs);
+    flush = (job->vs->csock != -1 && job->vs->abort != true);
+    vnc_unlock_output(job->vs);
+
+    if (flush) {
+        vnc_flush(job->vs);
+    }
+
+    vnc_lock_queue(queue);
+    QTAILQ_REMOVE(&queue->jobs, job, next);
+    vnc_unlock_queue(queue);
+    qemu_cond_broadcast(&queue->cond);
+    qemu_free(job);
+    return 0;
+}
+
+static VncJobQueue *vnc_queue_init(void)
+{
+    VncJobQueue *queue = qemu_mallocz(sizeof(VncJobQueue));
+
+    qemu_cond_init(&queue->cond);
+    qemu_mutex_init(&queue->mutex);
+    QTAILQ_INIT(&queue->jobs);
+    return queue;
+}
+
+static void vnc_queue_clear(VncJobQueue *q)
+{
+    qemu_cond_destroy(&queue->cond);
+    qemu_mutex_destroy(&queue->mutex);
+    buffer_free(&queue->buffer);
+    qemu_free(q);
+    queue = NULL; /* Unset global queue */
+}
+
+static void *vnc_worker_thread(void *arg)
+{
+    VncJobQueue *queue = arg;
+
+    qemu_thread_self(&queue->thread);
+
+    while (!vnc_worker_thread_loop(queue)) ;
+    vnc_queue_clear(queue);
+    return NULL;
+}
+
+void vnc_start_worker_thread(void)
+{
+    VncJobQueue *q;
+
+    if (vnc_worker_thread_running())
+        return ;
+
+    q = vnc_queue_init();
+    qemu_thread_create(&q->thread, vnc_worker_thread, q);
+    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())
+        return ;
+
+    /* Remove all jobs and wake up the thread */
+    vnc_lock_queue(queue);
+    queue->exit = true;
+    vnc_unlock_queue(queue);
+    vnc_jobs_clear(NULL);
+    qemu_cond_broadcast(&queue->cond);
+}
diff --git a/ui/vnc-jobs-sync.c b/ui/vnc-jobs-sync.c
new file mode 100644
index 0000000..49b77af
--- /dev/null
+++ b/ui/vnc-jobs-sync.c
@@ -0,0 +1,73 @@
+/*
+ * QEMU VNC display driver
+ *
+ * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2009 Red Hat, Inc
+ * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vnc.h"
+#include "vnc-jobs.h"
+
+void vnc_jobs_clear(VncState *vs)
+{
+}
+
+void vnc_jobs_join(VncState *vs)
+{
+}
+
+VncJob *vnc_job_new(VncState *vs)
+{
+    vs->job.vs = vs;
+    vs->job.rectangles = 0;
+
+    vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
+    vnc_write_u8(vs, 0);
+    vs->job.saved_offset = vs->output.offset;
+    vnc_write_u16(vs, 0);
+    return &vs->job;
+}
+
+void vnc_job_push(VncJob *job)
+{
+    VncState *vs = job->vs;
+
+    vs->output.buffer[job->saved_offset] = (job->rectangles >> 8) & 0xFF;
+    vs->output.buffer[job->saved_offset + 1] = job->rectangles & 0xFF;
+    vnc_flush(job->vs);
+}
+
+int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h)
+{
+    int n;
+
+    n = vnc_send_framebuffer_update(job->vs, x, y, w, h);
+    if (n >= 0)
+        job->rectangles += n;
+    return n;
+}
+
+bool vnc_has_job(VncState *vs)
+{
+    return false;
+}
diff --git a/ui/vnc-jobs.h b/ui/vnc-jobs.h
new file mode 100644
index 0000000..b8dab81
--- /dev/null
+++ b/ui/vnc-jobs.h
@@ -0,0 +1,87 @@
+/*
+ * QEMU VNC display driver
+ *
+ * From libvncserver/rfb/rfbproto.h
+ * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
+ * Copyright (C) 2000-2002 Constantin Kaplinsky.  All Rights Reserved.
+ * Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef VNC_JOBS_H
+#define VNC_JOBS_H
+
+/* Jobs */
+VncJob *vnc_job_new(VncState *vs);
+int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h);
+void vnc_job_push(VncJob *job);
+bool vnc_has_job(VncState *vs);
+void vnc_jobs_clear(VncState *vs);
+void vnc_jobs_join(VncState *vs);
+
+#ifdef CONFIG_VNC_THREAD
+
+void vnc_start_worker_thread(void);
+bool vnc_worker_thread_running(void);
+void vnc_stop_worker_thread(void);
+
+#endif /* CONFIG_VNC_THREAD */
+
+/* Locks */
+static inline int vnc_trylock_display(VncDisplay *vd)
+{
+#ifdef CONFIG_VNC_THREAD
+    return qemu_mutex_trylock(&vd->mutex);
+#else
+    return 0;
+#endif
+}
+
+static inline void vnc_lock_display(VncDisplay *vd)
+{
+#ifdef CONFIG_VNC_THREAD
+    qemu_mutex_lock(&vd->mutex);
+#endif
+}
+
+static inline void vnc_unlock_display(VncDisplay *vd)
+{
+#ifdef CONFIG_VNC_THREAD
+    qemu_mutex_unlock(&vd->mutex);
+#endif
+}
+
+static inline void vnc_lock_output(VncState *vs)
+{
+#ifdef CONFIG_VNC_THREAD
+    qemu_mutex_lock(&vs->output_mutex);
+#endif
+}
+
+static inline void vnc_unlock_output(VncState *vs)
+{
+#ifdef CONFIG_VNC_THREAD
+    qemu_mutex_unlock(&vs->output_mutex);
+#endif
+}
+
+#endif /* VNC_JOBS_H */
diff --git a/ui/vnc.c b/ui/vnc.c
index d0a4b75..7330b2c 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -25,6 +25,7 @@
  */
 
 #include "vnc.h"
+#include "vnc-jobs.h"
 #include "sysemu.h"
 #include "qemu_socket.h"
 #include "qemu-timer.h"
@@ -45,7 +46,6 @@
     } \
 }
 
-
 static VncDisplay *vnc_display; /* needed for info vnc */
 static DisplayChangeListener *dcl;
 
@@ -359,6 +359,7 @@ void do_info_vnc(Monitor *mon, QObject **ret_data)
 */
 
 static int vnc_update_client(VncState *vs, int has_dirty);
+static int vnc_update_client_sync(VncState *vs, int has_dirty);
 static void vnc_disconnect_start(VncState *vs);
 static void vnc_disconnect_finish(VncState *vs);
 static void vnc_init_timer(VncDisplay *vd);
@@ -502,19 +503,48 @@ static void vnc_desktop_resize(VncState *vs)
     }
     vs->client_width = ds_get_width(ds);
     vs->client_height = ds_get_height(ds);
+    vnc_lock_output(vs);
     vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
     vnc_write_u8(vs, 0);
     vnc_write_u16(vs, 1); /* number of rects */
     vnc_framebuffer_update(vs, 0, 0, vs->client_width, vs->client_height,
                            VNC_ENCODING_DESKTOPRESIZE);
+    vnc_unlock_output(vs);
     vnc_flush(vs);
 }
 
+#ifdef CONFIG_VNC_THREAD
+static void vnc_abort_display_jobs(VncDisplay *vd)
+{
+    VncState *vs;
+
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        vnc_lock_output(vs);
+        vs->abort = true;
+        vnc_unlock_output(vs);
+    }
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        vnc_jobs_join(vs);
+    }
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        vnc_lock_output(vs);
+        vs->abort = false;
+        vnc_unlock_output(vs);
+    }
+}
+#else
+static void vnc_abort_display_jobs(VncDisplay *vd)
+{
+}
+#endif
+
 static void vnc_dpy_resize(DisplayState *ds)
 {
     VncDisplay *vd = ds->opaque;
     VncState *vs;
 
+    vnc_abort_display_jobs(vd);
+
     /* server surface */
     if (!vd->server)
         vd->server = qemu_mallocz(sizeof(*vd->server));
@@ -642,7 +672,7 @@ int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
     return 1;
 }
 
-static int send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
+int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
 {
     int n = 0;
 
@@ -671,12 +701,14 @@ static int send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
 static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
 {
     /* send bitblit op to the vnc client */
+    vnc_lock_output(vs);
     vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
     vnc_write_u8(vs, 0);
     vnc_write_u16(vs, 1); /* number of rects */
     vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
     vnc_write_u16(vs, src_x);
     vnc_write_u16(vs, src_y);
+    vnc_unlock_output(vs);
     vnc_flush(vs);
 }
 
@@ -693,7 +725,7 @@ static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int
     QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
         if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
             vs->force_update = 1;
-            vnc_update_client(vs, 1);
+            vnc_update_client_sync(vs, 1);
             /* vs might be free()ed here */
         }
     }
@@ -813,15 +845,29 @@ static int find_and_clear_dirty_height(struct VncState *vs,
     return h;
 }
 
+#ifdef CONFIG_VNC_THREAD
+static int vnc_update_client_sync(VncState *vs, int has_dirty)
+{
+    int ret = vnc_update_client(vs, has_dirty);
+    vnc_jobs_join(vs);
+    return ret;
+}
+#else
+static int vnc_update_client_sync(VncState *vs, int has_dirty)
+{
+    return vnc_update_client(vs, has_dirty);
+}
+#endif
+
 static int vnc_update_client(VncState *vs, int has_dirty)
 {
     if (vs->need_update && vs->csock != -1) {
         VncDisplay *vd = vs->vd;
+        VncJob *job;
         int y;
-        int n_rectangles;
-        int saved_offset;
         int width, height;
-        int n;
+        int n = 0;
+
 
         if (vs->output.offset && !vs->audio_cap && !vs->force_update)
             /* kernel send buffers are full -> drop frames to throttle */
@@ -836,11 +882,7 @@ static int vnc_update_client(VncState *vs, int has_dirty)
          * happening in parallel don't disturb us, the next pass will
          * send them to the client.
          */
-        n_rectangles = 0;
-        vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
-        vnc_write_u8(vs, 0);
-        saved_offset = vs->output.offset;
-        vnc_write_u16(vs, 0);
+        job = vnc_job_new(vs);
 
         width = MIN(vd->server->width, vs->client_width);
         height = MIN(vd->server->height, vs->client_height);
@@ -857,25 +899,23 @@ static int vnc_update_client(VncState *vs, int has_dirty)
                 } else {
                     if (last_x != -1) {
                         int h = find_and_clear_dirty_height(vs, y, last_x, x);
-                        n = send_framebuffer_update(vs, last_x * 16, y,
-                                                    (x - last_x) * 16, h);
-                        n_rectangles += n;
+
+                        n += vnc_job_add_rect(job, last_x * 16, y,
+                                              (x - last_x) * 16, h);
                     }
                     last_x = -1;
                 }
             }
             if (last_x != -1) {
                 int h = find_and_clear_dirty_height(vs, y, last_x, x);
-                n = send_framebuffer_update(vs, last_x * 16, y,
-                                            (x - last_x) * 16, h);
-                n_rectangles += n;
+                n += vnc_job_add_rect(job, last_x * 16, y,
+                                      (x - last_x) * 16, h);
             }
         }
-        vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
-        vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
-        vnc_flush(vs);
+
+        vnc_job_push(job);
         vs->force_update = 0;
-        return n_rectangles;
+        return n;
     }
 
     if (vs->csock == -1)
@@ -891,16 +931,20 @@ static void audio_capture_notify(void *opaque, audcnotification_e cmd)
 
     switch (cmd) {
     case AUD_CNOTIFY_DISABLE:
+        vnc_lock_output(vs);
         vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
         vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
         vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END);
+        vnc_unlock_output(vs);
         vnc_flush(vs);
         break;
 
     case AUD_CNOTIFY_ENABLE:
+        vnc_lock_output(vs);
         vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
         vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
         vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN);
+        vnc_unlock_output(vs);
         vnc_flush(vs);
         break;
     }
@@ -914,11 +958,13 @@ static void audio_capture(void *opaque, void *buf, int size)
 {
     VncState *vs = opaque;
 
+    vnc_lock_output(vs);
     vnc_write_u8(vs, VNC_MSG_SERVER_QEMU);
     vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO);
     vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA);
     vnc_write_u32(vs, size);
     vnc_write(vs, buf, size);
+    vnc_unlock_output(vs);
     vnc_flush(vs);
 }
 
@@ -960,6 +1006,9 @@ static void vnc_disconnect_start(VncState *vs)
 
 static void vnc_disconnect_finish(VncState *vs)
 {
+    vnc_jobs_join(vs); /* Wait encoding jobs */
+
+    vnc_lock_output(vs);
     vnc_qmp_event(vs, QEVENT_VNC_DISCONNECTED);
 
     buffer_free(&vs->input);
@@ -988,6 +1037,11 @@ static void vnc_disconnect_finish(VncState *vs)
     vnc_remove_timer(vs->vd);
     if (vs->vd->lock_key_sync)
         qemu_remove_led_event_handler(vs->led);
+    vnc_unlock_output(vs);
+
+#ifdef CONFIG_VNC_THREAD
+    qemu_mutex_destroy(&vs->output_mutex);
+#endif
     qemu_free(vs);
 }
 
@@ -1107,7 +1161,7 @@ static long vnc_client_write_plain(VncState *vs)
  * the client socket. Will delegate actual work according to whether
  * SASL SSF layers are enabled (thus requiring encryption calls)
  */
-void vnc_client_write(void *opaque)
+static void vnc_client_write_locked(void *opaque)
 {
     VncState *vs = opaque;
 
@@ -1121,6 +1175,19 @@ void vnc_client_write(void *opaque)
         vnc_client_write_plain(vs);
 }
 
+void vnc_client_write(void *opaque)
+{
+    VncState *vs = opaque;
+
+    vnc_lock_output(vs);
+    if (vs->output.offset) {
+        vnc_client_write_locked(opaque);
+    } else {
+        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
+    }
+    vnc_unlock_output(vs);
+}
+
 void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting)
 {
     vs->read_handler = func;
@@ -1272,8 +1339,11 @@ void vnc_write_u8(VncState *vs, uint8_t value)
 
 void vnc_flush(VncState *vs)
 {
-    if (vs->csock != -1 && vs->output.offset)
-        vnc_client_write(vs);
+    vnc_lock_output(vs);
+    if (vs->csock != -1 && vs->output.offset) {
+        vnc_client_write_locked(vs);
+    }
+    vnc_unlock_output(vs);
 }
 
 uint8_t read_u8(uint8_t *data, size_t offset)
@@ -1308,12 +1378,14 @@ static void check_pointer_type_change(Notifier *notifier)
     int absolute = kbd_mouse_is_absolute();
 
     if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
+        vnc_lock_output(vs);
         vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
         vnc_write_u8(vs, 0);
         vnc_write_u16(vs, 1);
         vnc_framebuffer_update(vs, absolute, 0,
                                ds_get_width(vs->ds), ds_get_height(vs->ds),
                                VNC_ENCODING_POINTER_TYPE_CHANGE);
+        vnc_unlock_output(vs);
         vnc_flush(vs);
     }
     vs->absolute = absolute;
@@ -1617,21 +1689,25 @@ static void framebuffer_update_request(VncState *vs, int incremental,
 
 static void send_ext_key_event_ack(VncState *vs)
 {
+    vnc_lock_output(vs);
     vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
     vnc_write_u8(vs, 0);
     vnc_write_u16(vs, 1);
     vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
                            VNC_ENCODING_EXT_KEY_EVENT);
+    vnc_unlock_output(vs);
     vnc_flush(vs);
 }
 
 static void send_ext_audio_ack(VncState *vs)
 {
+    vnc_lock_output(vs);
     vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
     vnc_write_u8(vs, 0);
     vnc_write_u16(vs, 1);
     vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds),
                            VNC_ENCODING_AUDIO);
+    vnc_unlock_output(vs);
     vnc_flush(vs);
 }
 
@@ -1794,12 +1870,14 @@ static void vnc_colordepth(VncState *vs)
 {
     if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
         /* Sending a WMVi message to notify the client*/
+        vnc_lock_output(vs);
         vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
         vnc_write_u8(vs, 0);
         vnc_write_u16(vs, 1); /* number of rects */
         vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), 
                                ds_get_height(vs->ds), VNC_ENCODING_WMVi);
         pixel_format_message(vs);
+        vnc_unlock_output(vs);
         vnc_flush(vs);
     } else {
         set_pixel_conversion(vs);
@@ -2227,12 +2305,21 @@ static void vnc_refresh(void *opaque)
 
     vga_hw_update();
 
+    if (vnc_trylock_display(vd)) {
+        vd->timer_interval = VNC_REFRESH_INTERVAL_BASE;
+        qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) +
+                       vd->timer_interval);
+        return;
+    }
+
     has_dirty = vnc_refresh_server_surface(vd);
+    vnc_unlock_display(vd);
 
     QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
         rects += vnc_update_client(vs, has_dirty);
         /* vs might be free()ed here */
     }
+
     /* vd->timer could be NULL now if the last client disconnected,
      * in this case don't update the timer */
     if (vd->timer == NULL)
@@ -2291,6 +2378,10 @@ static void vnc_connect(VncDisplay *vd, int csock)
     vs->as.fmt = AUD_FMT_S16;
     vs->as.endianness = 0;
 
+#ifdef CONFIG_VNC_THREAD
+    qemu_mutex_init(&vs->output_mutex);
+#endif
+
     QTAILQ_INSERT_HEAD(&vd->clients, vs, next);
 
     vga_hw_update();
@@ -2348,6 +2439,11 @@ void vnc_display_init(DisplayState *ds)
     if (!vs->kbd_layout)
         exit(1);
 
+#ifdef CONFIG_VNC_THREAD
+    qemu_mutex_init(&vs->mutex);
+    vnc_start_worker_thread();
+#endif
+
     dcl->dpy_copy = vnc_dpy_copy;
     dcl->dpy_update = vnc_dpy_update;
     dcl->dpy_resize = vnc_dpy_resize;
diff --git a/ui/vnc.h b/ui/vnc.h
index 344a686..9619b24 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -29,6 +29,9 @@
 
 #include "qemu-common.h"
 #include "qemu-queue.h"
+#ifdef CONFIG_VNC_THREAD
+#include "qemu-thread.h"
+#endif
 #include "console.h"
 #include "monitor.h"
 #include "audio/audio.h"
@@ -59,6 +62,9 @@ typedef struct Buffer
 } Buffer;
 
 typedef struct VncState VncState;
+typedef struct VncJob VncJob;
+typedef struct VncRect VncRect;
+typedef struct VncRectEntry VncRectEntry;
 
 typedef int VncReadEvent(VncState *vs, uint8_t *data, size_t len);
 
@@ -101,6 +107,9 @@ struct VncDisplay
     DisplayState *ds;
     kbd_layout_t *kbd_layout;
     int lock_key_sync;
+#ifdef CONFIG_VNC_THREAD
+    QemuMutex mutex;
+#endif
 
     QEMUCursor *cursor;
     int cursor_msize;
@@ -152,6 +161,37 @@ typedef struct VncZlib {
     int level;
 } VncZlib;
 
+#ifdef CONFIG_VNC_THREAD
+struct VncRect
+{
+    int x;
+    int y;
+    int w;
+    int h;
+};
+
+struct VncRectEntry
+{
+    struct VncRect rect;
+    QLIST_ENTRY(VncRectEntry) next;
+};
+
+struct VncJob
+{
+    VncState *vs;
+
+    QLIST_HEAD(, VncRectEntry) rectangles;
+    QTAILQ_ENTRY(VncJob) next;
+};
+#else
+struct VncJob
+{
+    VncState *vs;
+    int rectangles;
+    size_t saved_offset;
+};
+#endif
+
 struct VncState
 {
     int csock;
@@ -199,7 +239,16 @@ struct VncState
     uint8_t modifiers_state[256];
     QEMUPutLEDEntry *led;
 
-    /* Encoding specific */
+    bool abort;
+#ifndef CONFIG_VNC_THREAD
+    VncJob job;
+#else
+    QemuMutex output_mutex;
+#endif
+
+    /* Encoding specific, if you add something here, don't forget to
+     *  update vnc_async_encoding_start()
+     */
     VncTight tight;
     VncZlib zlib;
     VncHextile hextile;
@@ -431,6 +480,8 @@ void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
 void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v);
 
 /* Encodings */
+int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+
 int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
 
 int vnc_hextile_send_framebuffer_update(VncState *vs, int x,
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 15/18] vnc: add missing lock for vnc_cursor_define()
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (13 preceding siblings ...)
  2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 14/18] vnc: threaded VNC server Corentin Chary
@ 2010-07-07 18:58 ` Corentin Chary
  2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 16/18] vnc: tight: fix rgb_prepare_row Corentin Chary
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

All vnc_write() calls must be locked (except the ones present before
the protocol initialization).

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 ui/vnc.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/ui/vnc.c b/ui/vnc.c
index 7330b2c..7fc40ac 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -796,6 +796,7 @@ static int vnc_cursor_define(VncState *vs)
     int isize;
 
     if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) {
+        vnc_lock_output(vs);
         vnc_write_u8(vs,  VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
         vnc_write_u8(vs,  0);  /*  padding     */
         vnc_write_u16(vs, 1);  /*  # of rects  */
@@ -804,6 +805,7 @@ static int vnc_cursor_define(VncState *vs)
         isize = c->width * c->height * vs->clientds.pf.bytes_per_pixel;
         vnc_write_pixels_generic(vs, &pf, c->data, isize);
         vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize);
+        vnc_unlock_output(vs);
         return 0;
     }
     return -1;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 16/18] vnc: tight: fix rgb_prepare_row
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (14 preceding siblings ...)
  2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 15/18] vnc: add missing lock for vnc_cursor_define() Corentin Chary
@ 2010-07-07 18:58 ` Corentin Chary
  2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 17/18] vnc: tight: split send_sub_rect Corentin Chary
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

rgb_prepare_row bpp depends on the server display surface, not
the client.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 ui/vnc-enc-tight.c |   15 ++++++++++-----
 1 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index 3f19df2..eaa88ce 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -1180,12 +1180,17 @@ DEFINE_RGB_GET_ROW_FUNCTION(32)
 static void rgb_prepare_row(VncState *vs, uint8_t *dst, int x, int y,
                             int count)
 {
-    if (vs->tight.pixel24)
-        rgb_prepare_row24(vs, dst, x, y, count);
-    else if (ds_get_bytes_per_pixel(vs->ds) == 4)
-        rgb_prepare_row32(vs, dst, x, y, count);
-    else
+    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 */
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 17/18] vnc: tight: split send_sub_rect
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (15 preceding siblings ...)
  2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 16/18] vnc: tight: fix rgb_prepare_row Corentin Chary
@ 2010-07-07 18:58 ` Corentin Chary
  2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 18/18] vnc: better default values for VNC options Corentin Chary
  2010-07-13 17:47 ` [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Rick Vernam
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

Split send_sub_rect in send_sub_rect_jpeg and send_sub_rect_nojpeg to
remove all these #ifdef CONFIG_JPEG.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 ui/vnc-enc-tight.c |   80 +++++++++++++++++++++++++++++++++++----------------
 1 files changed, 55 insertions(+), 25 deletions(-)

diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index eaa88ce..86bb49a 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -1452,34 +1452,39 @@ static void vnc_tight_stop(VncState *vs)
     vs->output = vs->tight.tmp;
 }
 
-static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
+static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h,
+                                int bg, int fg, int colors, VncPalette *palette)
 {
-    VncPalette *palette = NULL;
-    uint32_t bg = 0, fg = 0;
-    int colors;
-    int ret = 0;
-
-    vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
+    int ret;
 
-    vnc_tight_start(vs);
-    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
-    vnc_tight_stop(vs);
+    if (colors == 0) {
+        if (tight_detect_smooth_image(vs, w, h)) {
+            ret = send_gradient_rect(vs, x, y, w, h);
+        } else {
+            ret = send_full_color_rect(vs, x, y, w, h);
+        }
+    } else if (colors == 1) {
+        ret = send_solid_rect(vs);
+    } else if (colors == 2) {
+        ret = send_mono_rect(vs, x, y, w, h, bg, fg);
+    } else if (colors <= 256) {
+        ret = send_palette_rect(vs, x, y, w, h, palette);
+    }
+    return ret;
+}
 
-    colors = tight_fill_palette(vs, x, y, w * h, &fg, &bg, &palette);
+#ifdef CONFIG_VNC_JPEG
+static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h,
+                              int bg, int fg, int colors,
+                              VncPalette *palette)
+{
+    int ret;
 
     if (colors == 0) {
         if (tight_detect_smooth_image(vs, w, h)) {
-            if (vs->tight.quality == -1) {
-                ret = send_gradient_rect(vs, x, y, w, h);
-            } else {
-#ifdef CONFIG_VNC_JPEG
-                int quality = tight_conf[vs->tight.quality].jpeg_quality;
+            int quality = tight_conf[vs->tight.quality].jpeg_quality;
 
-                ret = send_jpeg_rect(vs, x, y, w, h, quality);
-#else
-                ret = send_full_color_rect(vs, x, y, w, h);
-#endif
-            }
+            ret = send_jpeg_rect(vs, x, y, w, h, quality);
         } else {
             ret = send_full_color_rect(vs, x, y, w, h);
         }
@@ -1488,8 +1493,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
     } else if (colors == 2) {
         ret = send_mono_rect(vs, x, y, w, h, bg, fg);
     } else if (colors <= 256) {
-#ifdef CONFIG_VNC_JPEG
-        if (colors > 96 && vs->tight.quality != -1 && vs->tight.quality <= 3 &&
+        if (colors > 96 &&
             tight_detect_smooth_image(vs, w, h)) {
             int quality = tight_conf[vs->tight.quality].jpeg_quality;
 
@@ -1497,10 +1501,36 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
         } else {
             ret = send_palette_rect(vs, x, y, w, h, palette);
         }
-#else
-        ret = send_palette_rect(vs, x, y, w, h, palette);
+    }
+    return ret;
+}
 #endif
+
+static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
+{
+    VncPalette *palette = NULL;
+    uint32_t bg = 0, fg = 0;
+    int colors;
+    int ret = 0;
+
+    vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type);
+
+    vnc_tight_start(vs);
+    vnc_raw_send_framebuffer_update(vs, x, y, w, h);
+    vnc_tight_stop(vs);
+
+    colors = tight_fill_palette(vs, x, y, w * h, &fg, &bg, &palette);
+
+#ifdef CONFIG_VNC_JPEG
+    if (vs->tight.quality != -1) {
+        ret = send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors, palette);
+    } else {
+        ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors, palette);
     }
+#else
+    ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors, palette);
+#endif
+
     palette_destroy(palette);
     return ret;
 }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PATCH v2 18/18] vnc: better default values for VNC options
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (16 preceding siblings ...)
  2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 17/18] vnc: tight: split send_sub_rect Corentin Chary
@ 2010-07-07 18:58 ` Corentin Chary
  2010-07-13 17:47 ` [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Rick Vernam
  18 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-07 18:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: Corentin Chary, Anthony Liguori, Alexander Graf

vnc_jpeg and vnc_png are now "auto" by default, this means that
if the dependencies are installed (libjpeg or libpng), then they
will be enabled.

vnc_thread is disabled by default. It should be enabled by default
as soon as it's stable enougth.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
---
 configure |   14 +++++++-------
 1 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/configure b/configure
index c292a33..1f0b39e 100755
--- a/configure
+++ b/configure
@@ -270,7 +270,7 @@ vnc_tls=""
 vnc_sasl=""
 vnc_jpeg=""
 vnc_png=""
-vnc_thread=""
+vnc_thread="no"
 xen=""
 linux_aio=""
 attr=""
@@ -842,7 +842,7 @@ echo "  --disable-vnc-sasl       disable SASL encryption for VNC server"
 echo "  --enable-vnc-sasl        enable SASL encryption for VNC server"
 echo "  --disable-vnc-jpeg       disable JPEG lossy compression for VNC server"
 echo "  --enable-vnc-jpeg        enable JPEG lossy compression for VNC server"
-echo "  --disable-vnc-png        disable PNG compression for VNC server"
+echo "  --disable-vnc-png        disable PNG compression for VNC server (default)"
 echo "  --enable-vnc-png         enable PNG compression for VNC server"
 echo "  --disable-vnc-thread     disable threaded VNC server"
 echo "  --enable-vnc-thread      enable threaded VNC server"
@@ -1268,7 +1268,7 @@ fi
 
 ##########################################
 # VNC JPEG detection
-if test "$vnc_jpeg" = "yes" ; then
+if test "$vnc_jpeg" != "no" ; then
 cat > $TMPC <<EOF
 #include <stdio.h>
 #include <jpeglib.h>
@@ -1289,7 +1289,7 @@ fi
 
 ##########################################
 # VNC PNG detection
-if test "$vnc_png" = "yes" ; then
+if test "$vnc_png" != "no" ; then
 cat > $TMPC <<EOF
 //#include <stdio.h>
 #include <png.h>
@@ -2301,15 +2301,15 @@ if test "$vnc_sasl" = "yes" ; then
   echo "CONFIG_VNC_SASL=y" >> $config_host_mak
   echo "VNC_SASL_CFLAGS=$vnc_sasl_cflags" >> $config_host_mak
 fi
-if test "$vnc_jpeg" = "yes" ; then
+if test "$vnc_jpeg" != "no" ; then
   echo "CONFIG_VNC_JPEG=y" >> $config_host_mak
   echo "VNC_JPEG_CFLAGS=$vnc_jpeg_cflags" >> $config_host_mak
 fi
-if test "$vnc_png" = "yes" ; then
+if test "$vnc_png" != "no" ; then
   echo "CONFIG_VNC_PNG=y" >> $config_host_mak
   echo "VNC_PNG_CFLAGS=$vnc_png_cflags" >> $config_host_mak
 fi
-if test "$vnc_thread" = "yes" ; then
+if test "$vnc_thread" != "no" ; then
   echo "CONFIG_VNC_THREAD=y" >> $config_host_mak
   echo "CONFIG_THREAD=y" >> $config_host_mak
 fi
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v2 08/18] vnc: tight add PNG encoding
  2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 08/18] vnc: tight add PNG encoding Corentin Chary
@ 2010-07-08  9:48   ` Daniel P. Berrange
  2010-07-08 13:10     ` Corentin Chary
  0 siblings, 1 reply; 26+ messages in thread
From: Daniel P. Berrange @ 2010-07-08  9:48 UTC (permalink / raw)
  To: Corentin Chary; +Cc: Anthony Liguori, qemu-devel, Alexander Graf

On Wed, Jul 07, 2010 at 08:57:56PM +0200, Corentin Chary wrote:
> Introduce a new encoding: VNC_ENCODING_TIGHT_PNG [1] (-269) with a new
> tight filter VNC_TIGHT_PNG (0x0A). When the client tells it supports the Tight PNG
> encoding, the server will use tight, but will always send encoding pixels using
> PNG instead of zlib. If the client also told it support JPEG, then the server can
> send JPEG, because PNG will only be used in the cases zlib was used in normal tight.

I know that VNC_ENCODING_TIGHT_PNG / -260 is already allocated to
QEMU in the RFB specification. Who is the authority for allocating
tight filter numbers, and have they recorded/approved use of 0x0A
for this PNG capability ?


Regards,
Daniel
-- 
|: Red Hat, Engineering, London    -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org        -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v2 08/18] vnc: tight add PNG encoding
  2010-07-08  9:48   ` Daniel P. Berrange
@ 2010-07-08 13:10     ` Corentin Chary
  2010-07-08 13:19       ` Daniel P. Berrange
  0 siblings, 1 reply; 26+ messages in thread
From: Corentin Chary @ 2010-07-08 13:10 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Anthony Liguori, qemu-devel, Alexander Graf

On Thu, Jul 8, 2010 at 11:48 AM, Daniel P. Berrange <berrange@redhat.com> wrote:
> On Wed, Jul 07, 2010 at 08:57:56PM +0200, Corentin Chary wrote:
>> Introduce a new encoding: VNC_ENCODING_TIGHT_PNG [1] (-269) with a new
>> tight filter VNC_TIGHT_PNG (0x0A). When the client tells it supports the Tight PNG
>> encoding, the server will use tight, but will always send encoding pixels using
>> PNG instead of zlib. If the client also told it support JPEG, then the server can
>> send JPEG, because PNG will only be used in the cases zlib was used in normal tight.
>
> I know that VNC_ENCODING_TIGHT_PNG / -260 is already allocated to
> QEMU in the RFB specification. Who is the authority for allocating
> tight filter numbers, and have they recorded/approved use of 0x0A
> for this PNG capability ?
>

Tight PNG should considered as a new encoding, not as a tight pseudo encoding.
When using Tight PNG, the server will send rect updates with -260, not 7.

We discussed that issue on #qemu-gsoc, and Anthony told me htat:
"if it gets sent with a different encoding, then you don't need
anyone's approval, you just need an encoding number
but if it's a pseudo-encoding that modifies an existing encoding, then
the author of the existing encoding must be on board"

Thanks,
-- 
Corentin Chary
http://xf.iksaif.net

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v2 08/18] vnc: tight add PNG encoding
  2010-07-08 13:10     ` Corentin Chary
@ 2010-07-08 13:19       ` Daniel P. Berrange
  2010-07-08 13:35         ` Corentin Chary
  0 siblings, 1 reply; 26+ messages in thread
From: Daniel P. Berrange @ 2010-07-08 13:19 UTC (permalink / raw)
  To: Corentin Chary; +Cc: Anthony Liguori, qemu-devel, Alexander Graf

On Thu, Jul 08, 2010 at 03:10:31PM +0200, Corentin Chary wrote:
> On Thu, Jul 8, 2010 at 11:48 AM, Daniel P. Berrange <berrange@redhat.com> wrote:
> > On Wed, Jul 07, 2010 at 08:57:56PM +0200, Corentin Chary wrote:
> >> Introduce a new encoding: VNC_ENCODING_TIGHT_PNG [1] (-269) with a new
> >> tight filter VNC_TIGHT_PNG (0x0A). When the client tells it supports the Tight PNG
> >> encoding, the server will use tight, but will always send encoding pixels using
> >> PNG instead of zlib. If the client also told it support JPEG, then the server can
> >> send JPEG, because PNG will only be used in the cases zlib was used in normal tight.
> >
> > I know that VNC_ENCODING_TIGHT_PNG / -260 is already allocated to
> > QEMU in the RFB specification. Who is the authority for allocating
> > tight filter numbers, and have they recorded/approved use of 0x0A
> > for this PNG capability ?
> >
> 
> Tight PNG should considered as a new encoding, not as a tight pseudo encoding.
> When using Tight PNG, the server will send rect updates with -260, not 7.

Why layer this into the rest of the Tight protocol decoding then ? What
benefit does it offer over a more straightforward standalone "PNG" encoding,
that was completely independant of any tight based encoding.

Regards,
Daniel
-- 
|: Red Hat, Engineering, London    -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org        -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v2 08/18] vnc: tight add PNG encoding
  2010-07-08 13:19       ` Daniel P. Berrange
@ 2010-07-08 13:35         ` Corentin Chary
  2010-07-08 13:37           ` Corentin Chary
  0 siblings, 1 reply; 26+ messages in thread
From: Corentin Chary @ 2010-07-08 13:35 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Anthony Liguori, qemu-devel, Alexander Graf

On Thu, Jul 8, 2010 at 3:19 PM, Daniel P. Berrange <berrange@redhat.com> wrote:
> On Thu, Jul 08, 2010 at 03:10:31PM +0200, Corentin Chary wrote:
>> On Thu, Jul 8, 2010 at 11:48 AM, Daniel P. Berrange <berrange@redhat.com> wrote:
>> > On Wed, Jul 07, 2010 at 08:57:56PM +0200, Corentin Chary wrote:
>> >> Introduce a new encoding: VNC_ENCODING_TIGHT_PNG [1] (-269) with a new
>> >> tight filter VNC_TIGHT_PNG (0x0A). When the client tells it supports the Tight PNG
>> >> encoding, the server will use tight, but will always send encoding pixels using
>> >> PNG instead of zlib. If the client also told it support JPEG, then the server can
>> >> send JPEG, because PNG will only be used in the cases zlib was used in normal tight.
>> >
>> > I know that VNC_ENCODING_TIGHT_PNG / -260 is already allocated to
>> > QEMU in the RFB specification. Who is the authority for allocating
>> > tight filter numbers, and have they recorded/approved use of 0x0A
>> > for this PNG capability ?
>> >
>>
>> Tight PNG should considered as a new encoding, not as a tight pseudo encoding.
>> When using Tight PNG, the server will send rect updates with -260, not 7.
>
> Why layer this into the rest of the Tight protocol decoding then ? What
> benefit does it offer over a more straightforward standalone "PNG" encoding,
> that was completely independant of any tight based encoding.
>

Because:
- we also want a lossy encoding (Jpeg) for some parts (adaptive choice
between jpeg and png/zlib based on update frequency is comming soon).
- we want the "fill" encoding for solid color rectangles

A standalone "PNG" encoding would work for some use case, and could be
added later, but Tight PNG is more than that.




-- 
Corentin Chary
http://xf.iksaif.net

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v2 08/18] vnc: tight add PNG encoding
  2010-07-08 13:35         ` Corentin Chary
@ 2010-07-08 13:37           ` Corentin Chary
  0 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-08 13:37 UTC (permalink / raw)
  To: Daniel P. Berrange; +Cc: Anthony Liguori, qemu-devel, Alexander Graf

> - we also want a lossy encoding (Jpeg) for some parts (adaptive choice
> between jpeg and png/zlib based on update frequency is comming soon).

Please note that Tight PNG can already switch from PNG to JPEG like the original
Tight was able to switch from Basic/Indexed to Jpeg (if lossy encoding
are enabled,
and if the client sent a Tight quality).

-- 
Corentin Chary
http://xf.iksaif.net

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13
  2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
                   ` (17 preceding siblings ...)
  2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 18/18] vnc: better default values for VNC options Corentin Chary
@ 2010-07-13 17:47 ` Rick Vernam
  2010-07-15 13:48   ` Corentin Chary
  18 siblings, 1 reply; 26+ messages in thread
From: Rick Vernam @ 2010-07-13 17:47 UTC (permalink / raw)
  To: qemu-devel

On Wednesday 07 July 2010 13:57:48 Corentin Chary wrote:
> This set contains all my patchs related to tight and threaded vnc server.
> 
> Since v1:
> * Add a fix for jpeg and png with non-24bpp displays
> * Better default values for vnc options in ./configure
> * Fixed Tight PNG to use its own encoding number (-260)
> * Cleaned tight send_sub_rect()
[ snip ]

Can anybody comment on the likelihood of this being committed in 0.13?

I'd like to evaluate some particular use cases with these VNC changes, however 
if it is not likely to be in 0.13 I will, unfortunately, have to bump my 
evaluations to a lower priority.

Thanks,
-Rick

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13
  2010-07-13 17:47 ` [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Rick Vernam
@ 2010-07-15 13:48   ` Corentin Chary
  0 siblings, 0 replies; 26+ messages in thread
From: Corentin Chary @ 2010-07-15 13:48 UTC (permalink / raw)
  To: rickv; +Cc: qemu-devel

On Tue, Jul 13, 2010 at 7:47 PM, Rick Vernam <rickv@hobi.com> wrote:
> On Wednesday 07 July 2010 13:57:48 Corentin Chary wrote:
>> This set contains all my patchs related to tight and threaded vnc server.
>>
>> Since v1:
>> * Add a fix for jpeg and png with non-24bpp displays
>> * Better default values for vnc options in ./configure
>> * Fixed Tight PNG to use its own encoding number (-260)
>> * Cleaned tight send_sub_rect()
> [ snip ]
>
> Can anybody comment on the likelihood of this being committed in 0.13?
>
> I'd like to evaluate some particular use cases with these VNC changes, however
> if it is not likely to be in 0.13 I will, unfortunately, have to bump my
> evaluations to a lower priority.
>
> Thanks,
> -Rick
>
>

Anthony told me that it'll be there for 0.13.

-- 
Corentin Chary
http://xf.iksaif.net

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2010-07-15 13:48 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-07-07 18:57 [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Corentin Chary
2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 01/18] vnc: tight: add JPEG and gradient subencoding with smooth image detection Corentin Chary
2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 02/18] vnc: JPEG should be disabled if the client don't set tight quality Corentin Chary
2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 03/18] vnc: add lossy option Corentin Chary
2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 04/18] ui: move all ui components in ui/ Corentin Chary
2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 05/18] vnc: rename vnc-encoding-* vnc-enc-* Corentin Chary
2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 06/18] vnc: tight: don't forget do at the last color Corentin Chary
2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 07/18] vnc: tight: remove a memleak in send_jpeg_rect() Corentin Chary
2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 08/18] vnc: tight add PNG encoding Corentin Chary
2010-07-08  9:48   ` Daniel P. Berrange
2010-07-08 13:10     ` Corentin Chary
2010-07-08 13:19       ` Daniel P. Berrange
2010-07-08 13:35         ` Corentin Chary
2010-07-08 13:37           ` Corentin Chary
2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 09/18] vnc: tight: specific zlib level and filters for each compression level Corentin Chary
2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 10/18] vnc: tight: stop using qdict for palette stuff Corentin Chary
2010-07-07 18:57 ` [Qemu-devel] [PATCH v2 11/18] vnc: encapsulate encoding members Corentin Chary
2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 12/18] vnc: fix tight png memory leak Corentin Chary
2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 13/18] qemu-thread: add qemu_mutex/cond_destroy and qemu_mutex_exit Corentin Chary
2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 14/18] vnc: threaded VNC server Corentin Chary
2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 15/18] vnc: add missing lock for vnc_cursor_define() Corentin Chary
2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 16/18] vnc: tight: fix rgb_prepare_row Corentin Chary
2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 17/18] vnc: tight: split send_sub_rect Corentin Chary
2010-07-07 18:58 ` [Qemu-devel] [PATCH v2 18/18] vnc: better default values for VNC options Corentin Chary
2010-07-13 17:47 ` [Qemu-devel] [PATCH v2 00/18] [PATCH v2 00/18] VNC Updates for 0.13 Rick Vernam
2010-07-15 13:48   ` Corentin Chary

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.