PageRenderTime 812ms CodeModel.GetById 192ms app.highlight 324ms RepoModel.GetById 181ms app.codeStats 0ms

/apps/desktop/libvncserver/ultra.c

http://ftk.googlecode.com/
C | 248 lines | 143 code | 51 blank | 54 comment | 26 complexity | 42893e3dbbf4a89236c185561655eb9b MD5 | raw file
  1/*
  2 * ultra.c
  3 *
  4 * Routines to implement ultra based encoding (minilzo).
  5 * ultrazip supports packed rectangles if the rects are tiny...
  6 * This improves performance as lzo has more data to work with at once
  7 * This is 'UltraZip' and is currently not implemented.
  8 */
  9
 10#include <rfb/rfb.h>
 11#include "minilzo.h"
 12
 13/*
 14 * lzoBeforeBuf contains pixel data in the client's format.
 15 * lzoAfterBuf contains the lzo (deflated) encoding version.
 16 * If the lzo compressed/encoded version is
 17 * larger than the raw data or if it exceeds lzoAfterBufSize then
 18 * raw encoding is used instead.
 19 */
 20
 21static int lzoBeforeBufSize = 0;
 22static char *lzoBeforeBuf = NULL;
 23
 24static int lzoAfterBufSize = 0;
 25static char *lzoAfterBuf = NULL;
 26static int lzoAfterBufLen = 0;
 27
 28/*
 29 * rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib
 30 *                              rectangle encoding.
 31 */
 32
 33#define MAX_WRKMEM ((LZO1X_1_MEM_COMPRESS) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t)
 34
 35void rfbUltraCleanup(rfbScreenInfoPtr screen)
 36{
 37  if (lzoBeforeBufSize) {
 38    free(lzoBeforeBuf);
 39    lzoBeforeBufSize=0;
 40  }
 41  if (lzoAfterBufSize) {
 42    free(lzoAfterBuf);
 43    lzoAfterBufSize=0;
 44  }
 45}
 46
 47void rfbFreeUltraData(rfbClientPtr cl) {
 48  if (cl->compStreamInitedLZO) {
 49    free(cl->lzoWrkMem);
 50    cl->compStreamInitedLZO=FALSE;
 51  }
 52}
 53
 54
 55static rfbBool
 56rfbSendOneRectEncodingUltra(rfbClientPtr cl,
 57                           int x,
 58                           int y,
 59                           int w,
 60                           int h)
 61{
 62    rfbFramebufferUpdateRectHeader rect;
 63    rfbZlibHeader hdr;
 64    int deflateResult;
 65    int i;
 66    char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)
 67    	   + (x * (cl->scaledScreen->bitsPerPixel / 8)));
 68
 69    int maxRawSize;
 70    int maxCompSize;
 71
 72    maxRawSize = (w * h * (cl->format.bitsPerPixel / 8));
 73
 74    if (lzoBeforeBufSize < maxRawSize) {
 75	lzoBeforeBufSize = maxRawSize;
 76	if (lzoBeforeBuf == NULL)
 77	    lzoBeforeBuf = (char *)malloc(lzoBeforeBufSize);
 78	else
 79	    lzoBeforeBuf = (char *)realloc(lzoBeforeBuf, lzoBeforeBufSize);
 80    }
 81
 82    /*
 83     * lzo requires output buffer to be slightly larger than the input
 84     * buffer, in the worst case.
 85     */
 86    maxCompSize = (maxRawSize + maxRawSize / 16 + 64 + 3);
 87
 88    if (lzoAfterBufSize < maxCompSize) {
 89	lzoAfterBufSize = maxCompSize;
 90	if (lzoAfterBuf == NULL)
 91	    lzoAfterBuf = (char *)malloc(lzoAfterBufSize);
 92	else
 93	    lzoAfterBuf = (char *)realloc(lzoAfterBuf, lzoAfterBufSize);
 94    }
 95
 96    /* 
 97     * Convert pixel data to client format.
 98     */
 99    (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,
100		       &cl->format, fbptr, lzoBeforeBuf,
101		       cl->scaledScreen->paddedWidthInBytes, w, h);
102
103    if ( cl->compStreamInitedLZO == FALSE ) {
104        cl->compStreamInitedLZO = TRUE;
105        /* Work-memory needed for compression. Allocate memory in units
106         * of `lzo_align_t' (instead of `char') to make sure it is properly aligned.
107         */  
108        cl->lzoWrkMem = malloc(sizeof(lzo_align_t) * (((LZO1X_1_MEM_COMPRESS) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t)));
109    }
110
111    /* Perform the compression here. */
112    deflateResult = lzo1x_1_compress((unsigned char *)lzoBeforeBuf, (lzo_uint)(w * h * (cl->format.bitsPerPixel / 8)), (unsigned char *)lzoAfterBuf, (lzo_uint *)&maxCompSize, cl->lzoWrkMem);
113    /* maxCompSize now contains the compressed size */
114
115    /* Find the total size of the resulting compressed data. */
116    lzoAfterBufLen = maxCompSize;
117
118    if ( deflateResult != LZO_E_OK ) {
119        rfbErr("lzo deflation error: %d\n", deflateResult);
120        return FALSE;
121    }
122
123    /* Update statics */
124    rfbStatRecordEncodingSent(cl, rfbEncodingUltra, sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader + lzoAfterBufLen, maxRawSize);
125
126    if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
127	> UPDATE_BUF_SIZE)
128    {
129	if (!rfbSendUpdateBuf(cl))
130	    return FALSE;
131    }
132
133    rect.r.x = Swap16IfLE(x);
134    rect.r.y = Swap16IfLE(y);
135    rect.r.w = Swap16IfLE(w);
136    rect.r.h = Swap16IfLE(h);
137    rect.encoding = Swap32IfLE(rfbEncodingUltra);
138
139    memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
140	   sz_rfbFramebufferUpdateRectHeader);
141    cl->ublen += sz_rfbFramebufferUpdateRectHeader;
142
143    hdr.nBytes = Swap32IfLE(lzoAfterBufLen);
144
145    memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbZlibHeader);
146    cl->ublen += sz_rfbZlibHeader;
147
148    /* We might want to try sending the data directly... */
149    for (i = 0; i < lzoAfterBufLen;) {
150
151	int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
152
153	if (i + bytesToCopy > lzoAfterBufLen) {
154	    bytesToCopy = lzoAfterBufLen - i;
155	}
156
157	memcpy(&cl->updateBuf[cl->ublen], &lzoAfterBuf[i], bytesToCopy);
158
159	cl->ublen += bytesToCopy;
160	i += bytesToCopy;
161
162	if (cl->ublen == UPDATE_BUF_SIZE) {
163	    if (!rfbSendUpdateBuf(cl))
164		return FALSE;
165	}
166    }
167
168    return TRUE;
169
170}
171
172/*
173 * rfbSendRectEncodingUltra - send a given rectangle using one or more
174 *                           LZO encoding rectangles.
175 */
176
177rfbBool
178rfbSendRectEncodingUltra(rfbClientPtr cl,
179                        int x,
180                        int y,
181                        int w,
182                        int h)
183{
184    int  maxLines;
185    int  linesRemaining;
186    rfbRectangle partialRect;
187
188    partialRect.x = x;
189    partialRect.y = y;
190    partialRect.w = w;
191    partialRect.h = h;
192
193    /* Determine maximum pixel/scan lines allowed per rectangle. */
194    maxLines = ( ULTRA_MAX_SIZE(w) / w );
195
196    /* Initialize number of scan lines left to do. */
197    linesRemaining = h;
198
199    /* Loop until all work is done. */
200    while ( linesRemaining > 0 ) {
201
202        int linesToComp;
203
204        if ( maxLines < linesRemaining )
205            linesToComp = maxLines;
206        else
207            linesToComp = linesRemaining;
208
209        partialRect.h = linesToComp;
210
211        /* Encode (compress) and send the next rectangle. */
212        if ( ! rfbSendOneRectEncodingUltra( cl,
213                                           partialRect.x,
214                                           partialRect.y,
215                                           partialRect.w,
216                                           partialRect.h )) {
217
218            return FALSE;
219        }
220
221        /* Technically, flushing the buffer here is not extrememly
222         * efficient.  However, this improves the overall throughput
223         * of the system over very slow networks.  By flushing
224         * the buffer with every maximum size lzo rectangle, we
225         * improve the pipelining usage of the server CPU, network,
226         * and viewer CPU components.  Insuring that these components
227         * are working in parallel actually improves the performance
228         * seen by the user.
229         * Since, lzo is most useful for slow networks, this flush
230         * is appropriate for the desired behavior of the lzo encoding.
231         */
232        if (( cl->ublen > 0 ) &&
233            ( linesToComp == maxLines )) {
234            if (!rfbSendUpdateBuf(cl)) {
235
236                return FALSE;
237            }
238        }
239
240        /* Update remaining and incremental rectangle location. */
241        linesRemaining -= linesToComp;
242        partialRect.y += linesToComp;
243
244    }
245
246    return TRUE;
247
248}