Commit 7124b5fb authored by DRC's avatar DRC Committed by Christian Beier

Replace TightVNC encoder with TurboVNC encoder. This patch is the result of...

Replace TightVNC encoder with TurboVNC encoder. This patch is the result of further research and discussion that revealed the following:

-- TightPng encoding and the rfbTightNoZlib extension need not conflict.  Since
   TightPng is a separate encoding type, not supported by TurboVNC-compatible
   viewers, then the rfbTightNoZlib extension can be used solely whenever the
   encoding type is Tight and disabled with the encoding type is TightPng.

-- In the TightVNC encoder, compression levels above 5 are basically useless.
   On the set of 20 low-level datasets that were used to design the TurboVNC
   encoder (these include the eight 2D application captures that were also used
   when designing the TightVNC encoder, as well as 12 3D application captures
   provided by the VirtualGL Project--
   see http://www.virtualgl.org/pmwiki/uploads/About/tighttoturbo.pdf), moving
   from Compression Level (CL) 5 to CL 9 in the TightVNC encoder did not
   increase the compression ratio of any datasets more than 10%, and the
   compression ratio only increased by more than 5% on four of them.  The
   compression ratio actually decreased a few percent on five of them.  In
   exchange for this paltry increase in compression ratio, the CPU usage, on
   average, went up by a factor of 5.  Thus, for all intents and purposes,
   TightVNC CL 5 provides the "best useful compression" for that encoder.

-- TurboVNC's best compression level (CL 2) compresses 3D and video workloads
   significantly more "tightly" than TightVNC CL 5 (~70% better, in the
   aggregate) but does not quite achieve the same level of compression with 2D
   workloads (~20% worse, in the aggregate.) This decrease in compression ratio
   may or may not be noticeable, since many of the datasets it affects are not
   performance-critical (such as the console output of a compilation, etc.)
   However, for peace of mind, it was still desirable to have a mode that
   compressed with equal "tightness" to TightVNC CL 5, since we proposed to
   replace that encoder entirely.

-- A new mode was discovered in the TurboVNC encoder that produces, in the
   aggregate, similar compression ratios on 2D datasets as TightVNC CL 5.  That
   new mode involves using Zlib level 7 (the same level used by TightVNC CL 5)
   but setting the "palette threshold" to 256, so that indexed color encoding
   is used whenever possible.  This mode reduces bandwidth only marginally
   (typically 10-20%) relative to TurboVNC CL 2 on low-color workloads, in
   exchange for nearly doubling CPU usage, and it does not benefit high-color
   workloads at all (since those are usually encoded with JPEG.)  However, it
   provides a means of reproducing the same "tightness" as the TightVNC
   encoder on 2D workloads without sacrificing any compression for 3D/video
   workloads, and without using any more CPU time than necessary.

-- The TurboVNC encoder still performs as well or better than the TightVNC
   encoder when plain libjpeg is used instead of libjpeg-turbo.

Specific notes follow:

common/turbojpeg.c common/turbojpeg.h:
Added code to emulate the libjpeg-turbo colorspace extensions, so that the
TurboJPEG wrapper can be used with plain libjpeg as well.  This required
updating the TurboJPEG wrapper to the latest code from libjpeg-turbo 1.2.0,
mainly because the TurboJPEG 1.2 API handles pixel formats in a much cleaner
way, which made the conversion code easier to write.  It also eases the
maintenance to have the wrapper synced as much as possible with the upstream
code base (so I can merge any relevant bug fixes that are discovered upstream.)
The libvncserver version of the TurboJPEG wrapper is a "lite" version,
containing only the JPEG compression/decompression code and not the lossless
transform, YUV encoding/decoding, and dynamic buffer allocation features from
TurboJPEG 1.2.

configure.ac:
Removed the --with-turbovnc option.  configure still checks for the presence of
libjpeg-turbo, but only for the purposes of printing a performance warning if
it isn't available.

rfb/rfb.h:
Fix a bug introduced with the initial TurboVNC encoder patch.  We cannot use
tightQualityLevel for the TurboVNC 1-100 quality level, because
tightQualityLevel is also used by ZRLE.  Thus, a new parameter
(turboQualityLevel) was created.

rfb/rfbproto.h:
Remove TurboVNC-specific #ifdefs and language

libvncserver/rfbserver.c:
Remove TurboVNC-specific #ifdefs.  Fix afore-mentioned tightQualityLevel bug.

libvncserver/tight.c:
Replaced the TightVNC encoder with the TurboVNC encoder.  Relative to the
initial TurboVNC encoder patch, this patch also:
-- Adds TightPng support to the TurboVNC encoder
-- Adds the afore-mentioned low-bandwidth mode, which is mapped externally to
   Compression Level 9

test/*:
Included TJUnitTest (a regression test for the TurboJPEG wrapper) as well as
TJBench (a benchmark for same.)  These are useful for ensuring that the wrapper
still functions correctly and performantly if it needs to be modified for
whatever reason.  Both of these programs are derived from libjpeg-turbo 1.2.0.
As with the TurboJPEG wrapper, they do not contain the more advanced features
of TurboJPEG 1.2, such as YUV encoding/decoding and lossless transforms.
parent 5f2794f3
This diff is collapsed.
This diff is collapsed.
......@@ -612,31 +612,18 @@ A copy of libjpeg may be obtained from: http://ijg.org/files/
[AC_MSG_RESULT(no)])
fi
fi
fi
AC_ARG_WITH(turbovnc,
[ --with-turbovnc use TurboVNC encoder instead of TightVNC encoder],,)
AC_MSG_CHECKING(whether to enable TurboVNC encoder)
if test "x$with_turbovnc" = "xyes"; then
if test "x$HAVE_LIBJPEG_TURBO" != "xtrue"; then
AC_MSG_ERROR([
AC_MSG_WARN([
==========================================================================
*** The TurboVNC encoder requires libjpeg-turbo, which was not detected.
You can obtain libjpeg-turbo from:
https://sourceforge.net/projects/libjpeg-turbo/files/
Optionally, you can pass --without-turbovnc to configure to use the
TightVNC encoder instead. ***
*** The libjpeg library you are building against is not libjpeg-turbo.
Performance will be reduced. You can obtain libjpeg-turbo from:
https://sourceforge.net/projects/libjpeg-turbo/files/ ***
==========================================================================
])
fi
AC_DEFINE(HAVE_TURBOVNC, 1, TurboVNC support enabled)
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
fi
AM_CONDITIONAL(HAVE_TURBOVNC, test "x$with_turbovnc" = "xyes" )
fi
AC_ARG_WITH(png,
[ --without-png disable support for png]
......@@ -648,7 +635,7 @@ AC_ARG_WITH(png,
# -without-png with_png="no"
# -with-png=/foo/dir with_png="/foo/dir"
if test "x$with_png" != "xno" -a "x$with_turbovnc" != "xyes"; then
if test "x$with_png" != "xno"; then
if test ! -z "$with_png" -a "x$with_png" != "xyes"; then
# add user supplied directory to flags:
saved_CPPFLAGS="$CPPFLAGS"
......
......@@ -46,11 +46,7 @@ EXTRA_DIST=tableinit24.c tableinittctemplate.c tabletranstemplate.c \
if HAVE_LIBZ
ZLIBSRCS = zlib.c zrle.c zrleoutstream.c zrlepalettehelper.c ../common/zywrletemplate.c
if HAVE_LIBJPEG
if HAVE_TURBOVNC
TIGHTSRCS = turbo.c ../common/turbojpeg.c
else
TIGHTSRCS = tight.c
endif
TIGHTSRCS = tight.c ../common/turbojpeg.c
endif
endif
......
......@@ -3,7 +3,7 @@
*/
/*
* Copyright (C) 2011 D. R. Commander
* Copyright (C) 2011-2012 D. R. Commander
* Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
* Copyright (C) 2002 RealVNC Ltd.
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
......@@ -86,10 +86,10 @@ static int compat_mkdir(const char *path, int mode)
#define mkdir compat_mkdir
#endif
#ifdef LIBVNCSERVER_HAVE_TURBOVNC
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
/*
* Map of quality levels to provide compatibility with TightVNC/TigerVNC
* clients
* clients. This emulates the behavior of the TigerVNC Server.
*/
static const int tight2turbo_qual[10] = {
......@@ -383,10 +383,8 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
#if defined(LIBVNCSERVER_HAVE_LIBJPEG) || defined(LIBVNCSERVER_HAVE_LIBPNG)
cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
#endif
#ifdef LIBVNCSERVER_HAVE_TURBOVNC
cl->tightSubsampLevel = TIGHT_DEFAULT_SUBSAMP;
#endif
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
cl->turboSubsampLevel = TURBO_DEFAULT_SUBSAMP;
{
int i;
for (i = 0; i < 4; i++)
......@@ -1969,11 +1967,12 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
cl->enableServerIdentity = FALSE;
#if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
cl->tightQualityLevel = -1;
#if defined(LIBVNCSERVER_HAVE_LIBJPEG) || defined(LIBVNCSERVER_HAVE_TURBOVNC) || defined(LIBVNCSERVER_HAVE_LIBPNG)
#if defined(LIBVNCSERVER_HAVE_LIBJPEG) || defined(LIBVNCSERVER_HAVE_LIBPNG)
cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION;
#endif
#ifdef LIBVNCSERVER_HAVE_TURBOVNC
cl->tightSubsampLevel = TIGHT_DEFAULT_SUBSAMP;
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
cl->turboSubsampLevel = TURBO_DEFAULT_SUBSAMP;
cl->turboQualityLevel = -1;
#endif
#endif
......@@ -2105,29 +2104,26 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
rfbLog("Using compression level %d for client %s\n",
cl->tightCompressLevel, cl->host);
#endif
#ifdef LIBVNCSERVER_HAVE_TURBOVNC
} else if ( enc >= (uint32_t)rfbEncodingSubsamp1X &&
enc <= (uint32_t)rfbEncodingSubsampGray ) {
cl->tightSubsampLevel = enc & 0xFF;
rfbLog("Using JPEG subsampling %d for client %s\n",
cl->tightSubsampLevel, cl->host);
} else if ( enc >= (uint32_t)rfbEncodingQualityLevel0 &&
enc <= (uint32_t)rfbEncodingQualityLevel9 ) {
cl->tightQualityLevel = tight2turbo_qual[enc & 0x0F];
cl->tightSubsampLevel = tight2turbo_subsamp[enc & 0x0F];
rfbLog("Using JPEG subsampling %d, Q%d for client %s\n",
cl->tightSubsampLevel, cl->tightQualityLevel, cl->host);
} else if ( enc >= (uint32_t)rfbEncodingFineQualityLevel0 + 1 &&
enc <= (uint32_t)rfbEncodingFineQualityLevel100 ) {
cl->tightQualityLevel = enc & 0xFF;
rfbLog("Using image quality level %d for client %s\n",
cl->tightQualityLevel, cl->host);
#else
} else if ( enc >= (uint32_t)rfbEncodingQualityLevel0 &&
enc <= (uint32_t)rfbEncodingQualityLevel9 ) {
cl->tightQualityLevel = enc & 0x0F;
rfbLog("Using image quality level %d for client %s\n",
cl->tightQualityLevel, cl->host);
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
cl->turboQualityLevel = tight2turbo_qual[enc & 0x0F];
cl->turboSubsampLevel = tight2turbo_subsamp[enc & 0x0F];
rfbLog("Using JPEG subsampling %d, Q%d for client %s\n",
cl->turboSubsampLevel, cl->turboQualityLevel, cl->host);
} else if ( enc >= (uint32_t)rfbEncodingFineQualityLevel0 + 1 &&
enc <= (uint32_t)rfbEncodingFineQualityLevel100 ) {
cl->turboQualityLevel = enc & 0xFF;
rfbLog("Using fine quality level %d for client %s\n",
cl->turboQualityLevel, cl->host);
} else if ( enc >= (uint32_t)rfbEncodingSubsamp1X &&
enc <= (uint32_t)rfbEncodingSubsampGray ) {
cl->turboSubsampLevel = enc & 0xFF;
rfbLog("Using subsampling level %d for client %s\n",
cl->turboSubsampLevel, cl->host);
#endif
} else
#endif
......
This diff is collapsed.
This diff is collapsed.
......@@ -673,9 +673,10 @@ typedef struct _rfbClientRec {
int afterEncBufLen;
#if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
uint32_t tightEncoding; /* rfbEncodingTight or rfbEncodingTightPng */
#ifdef LIBVNCSERVER_HAVE_TURBOVNC
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
/* TurboVNC Encoding support (extends TightVNC) */
int tightSubsampLevel;
int turboSubsampLevel;
int turboQualityLevel; // 1-100 scale
#endif
#endif
......@@ -875,8 +876,8 @@ extern rfbBool rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w,
#define TIGHT_DEFAULT_COMPRESSION 6
#ifdef LIBVNCSERVER_HAVE_TURBOVNC
#define TIGHT_DEFAULT_SUBSAMP 0
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
#define TURBO_DEFAULT_SUBSAMP 0
#endif
extern rfbBool rfbTightDisableGradient;
......
......@@ -469,7 +469,6 @@ typedef struct {
* 0xFFFFFFF0 .. 0xFFFFFFFF -- cross-encoding compression levels.
*/
#ifdef LIBVNCSERVER_HAVE_TURBOVNC
#define rfbEncodingFineQualityLevel0 0xFFFFFE00
#define rfbEncodingFineQualityLevel100 0xFFFFFE64
#define rfbEncodingSubsamp1X 0xFFFFFD00
......@@ -478,7 +477,6 @@ typedef struct {
#define rfbEncodingSubsampGray 0xFFFFFD03
#define rfbEncodingSubsamp8X 0xFFFFFD04
#define rfbEncodingSubsamp16X 0xFFFFFD05
#endif
#define rfbEncodingCompressLevel0 0xFFFFFF00
#define rfbEncodingCompressLevel1 0xFFFFFF01
......@@ -734,12 +732,13 @@ typedef struct {
* 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",
* (TurboVNC) if 1010 (0x0A), then the compression type is "basic"
* and no Zlib compression was used,
* (TurboVNC) if 1110 (0x0E), then the compression type is "basic",
* no Zlib compression was used, and a "filter id" byte follows
* this byte,
* (TightVNC) if 1010 (0x0A), then the compression type is "png",
* (Tight only) if 1010 (0x0A), then the compression type is
* "basic" and no Zlib compression was used,
* (Tight only) if 1110 (0x0E), then the compression type is
* "basic", no Zlib compression was used, and a "filter id" byte
* follows this byte,
* (TightPng only) if 1010 (0x0A), then the compression type is
* "png",
* if 0xxx, then the compression type is "basic" and Zlib
* compression was used,
* values greater than 1010 are not valid.
......@@ -858,11 +857,8 @@ typedef struct {
#define rfbTightExplicitFilter 0x04
#define rfbTightFill 0x08
#define rfbTightJpeg 0x09
#ifdef LIBVNCSERVER_HAVE_TURBOVNC
#define rfbTightNoZlib 0x0A
#else
#define rfbTightPng 0x0A
#endif
#define rfbTightMaxSubencoding 0x0A
/* Filters to improve compression efficiency */
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment