summaryrefslogtreecommitdiffstats
path: root/libvncserver/ultra.c
diff options
context:
space:
mode:
Diffstat (limited to 'libvncserver/ultra.c')
-rw-r--r--libvncserver/ultra.c229
1 files changed, 229 insertions, 0 deletions
diff --git a/libvncserver/ultra.c b/libvncserver/ultra.c
new file mode 100644
index 0000000..5825d5b
--- /dev/null
+++ b/libvncserver/ultra.c
@@ -0,0 +1,229 @@
+/*
+ * ultra.c
+ *
+ * Routines to implement ultra based encoding (minilzo).
+ * ultrazip supports packed rectangles if the rects are tiny...
+ * This improves performance as lzo has more data to work with at once
+ * This is 'UltraZip' and is currently not implemented.
+ */
+
+#include <rfb/rfb.h>
+#include "minilzo.h"
+
+/*
+ * lzoBeforeBuf contains pixel data in the client's format.
+ * lzoAfterBuf contains the lzo (deflated) encoding version.
+ * If the lzo compressed/encoded version is
+ * larger than the raw data or if it exceeds lzoAfterBufSize then
+ * raw encoding is used instead.
+ */
+
+static int lzoBeforeBufSize = 0;
+static char *lzoBeforeBuf = NULL;
+
+static int lzoAfterBufSize = 0;
+static char *lzoAfterBuf = NULL;
+static int lzoAfterBufLen;
+
+/*
+ * rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib
+ * rectangle encoding.
+ */
+
+#define MAX_WRKMEM ((LZO1X_1_MEM_COMPRESS) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t)
+
+static rfbBool
+rfbSendOneRectEncodingUltra(rfbClientPtr cl,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ rfbFramebufferUpdateRectHeader rect;
+ rfbZlibHeader hdr;
+ int deflateResult;
+ int i;
+ char *fbptr = (cl->screen->frameBuffer + (cl->screen->paddedWidthInBytes * y)
+ + (x * (cl->screen->bitsPerPixel / 8)));
+
+ int maxRawSize;
+ int maxCompSize;
+
+ maxRawSize = (w * h * (cl->format.bitsPerPixel / 8));
+
+ if (lzoBeforeBufSize < maxRawSize) {
+ lzoBeforeBufSize = maxRawSize;
+ if (lzoBeforeBuf == NULL)
+ lzoBeforeBuf = (char *)malloc(lzoBeforeBufSize);
+ else
+ lzoBeforeBuf = (char *)realloc(lzoBeforeBuf, lzoBeforeBufSize);
+ }
+
+ /*
+ * lzo requires output buffer to be slightly larger than the input
+ * buffer, in the worst case.
+ */
+ maxCompSize = (maxRawSize + maxRawSize / 16 + 64 + 3);
+
+ if (lzoAfterBufSize < maxCompSize) {
+ lzoAfterBufSize = maxCompSize;
+ if (lzoAfterBuf == NULL)
+ lzoAfterBuf = (char *)malloc(lzoAfterBufSize);
+ else
+ lzoAfterBuf = (char *)realloc(lzoAfterBuf, lzoAfterBufSize);
+ }
+
+ /*
+ * Convert pixel data to client format.
+ */
+ (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,
+ &cl->format, fbptr, lzoBeforeBuf,
+ cl->screen->paddedWidthInBytes, w, h);
+
+ if ( cl->compStreamInitedLZO == FALSE ) {
+ cl->compStreamInitedLZO = TRUE;
+ /* Work-memory needed for compression. Allocate memory in units
+ * of `lzo_align_t' (instead of `char') to make sure it is properly aligned.
+ */
+ cl->lzoWrkMem = malloc(sizeof(lzo_align_t) * (((LZO1X_1_MEM_COMPRESS) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t)));
+ }
+
+ /* Perform the compression here. */
+ deflateResult = lzo1x_1_compress((unsigned char *)lzoBeforeBuf, (lzo_uint)(w * h * (cl->format.bitsPerPixel / 8)), (unsigned char *)lzoAfterBuf, (lzo_uint *)&maxCompSize, cl->lzoWrkMem);
+ /* maxCompSize now contains the compressed size */
+
+ /* Find the total size of the resulting compressed data. */
+ lzoAfterBufLen = maxCompSize;
+
+ if ( deflateResult != LZO_E_OK ) {
+ rfbErr("lzo deflation error: %d\n", deflateResult);
+ return FALSE;
+ }
+
+ /* Update statics */
+ cl->rectanglesSent[rfbEncodingUltra]++;
+ cl->bytesSent[rfbEncodingUltra] += (sz_rfbFramebufferUpdateRectHeader
+ + sz_rfbZlibHeader + lzoAfterBufLen);
+
+ if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
+ > UPDATE_BUF_SIZE)
+ {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+
+ rect.r.x = Swap16IfLE(x);
+ rect.r.y = Swap16IfLE(y);
+ rect.r.w = Swap16IfLE(w);
+ rect.r.h = Swap16IfLE(h);
+ rect.encoding = Swap32IfLE(rfbEncodingUltra);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
+ sz_rfbFramebufferUpdateRectHeader);
+ cl->ublen += sz_rfbFramebufferUpdateRectHeader;
+
+ hdr.nBytes = Swap32IfLE(lzoAfterBufLen);
+
+ memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbZlibHeader);
+ cl->ublen += sz_rfbZlibHeader;
+
+ for (i = 0; i < lzoAfterBufLen;) {
+
+ int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
+
+ if (i + bytesToCopy > lzoAfterBufLen) {
+ bytesToCopy = lzoAfterBufLen - i;
+ }
+
+ memcpy(&cl->updateBuf[cl->ublen], &lzoAfterBuf[i], bytesToCopy);
+
+ cl->ublen += bytesToCopy;
+ i += bytesToCopy;
+
+ if (cl->ublen == UPDATE_BUF_SIZE) {
+ if (!rfbSendUpdateBuf(cl))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+
+}
+
+/*
+ * rfbSendRectEncodingUltra - send a given rectangle using one or more
+ * LZO encoding rectangles.
+ */
+
+rfbBool
+rfbSendRectEncodingUltra(rfbClientPtr cl,
+ int x,
+ int y,
+ int w,
+ int h)
+{
+ int maxLines;
+ int linesRemaining;
+ rfbRectangle partialRect;
+
+ partialRect.x = x;
+ partialRect.y = y;
+ partialRect.w = w;
+ partialRect.h = h;
+
+ /* Determine maximum pixel/scan lines allowed per rectangle. */
+ maxLines = ( ULTRA_MAX_SIZE(w) / w );
+
+ /* Initialize number of scan lines left to do. */
+ linesRemaining = h;
+
+ /* Loop until all work is done. */
+ while ( linesRemaining > 0 ) {
+
+ int linesToComp;
+
+ if ( maxLines < linesRemaining )
+ linesToComp = maxLines;
+ else
+ linesToComp = linesRemaining;
+
+ partialRect.h = linesToComp;
+
+ /* Encode (compress) and send the next rectangle. */
+ if ( ! rfbSendOneRectEncodingUltra( cl,
+ partialRect.x,
+ partialRect.y,
+ partialRect.w,
+ partialRect.h )) {
+
+ return FALSE;
+ }
+
+ /* Technically, flushing the buffer here is not extrememly
+ * efficient. However, this improves the overall throughput
+ * of the system over very slow networks. By flushing
+ * the buffer with every maximum size lzo rectangle, we
+ * improve the pipelining usage of the server CPU, network,
+ * and viewer CPU components. Insuring that these components
+ * are working in parallel actually improves the performance
+ * seen by the user.
+ * Since, lzo is most useful for slow networks, this flush
+ * is appropriate for the desired behavior of the lzo encoding.
+ */
+ if (( cl->ublen > 0 ) &&
+ ( linesToComp == maxLines )) {
+ if (!rfbSendUpdateBuf(cl)) {
+
+ return FALSE;
+ }
+ }
+
+ /* Update remaining and incremental rectangle location. */
+ linesRemaining -= linesToComp;
+ partialRect.y += linesToComp;
+
+ }
+
+ return TRUE;
+
+}