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.
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.
21 static int lzoBeforeBufSize = 0;
22 static char *lzoBeforeBuf = NULL;
24 static int lzoAfterBufSize = 0;
25 static char *lzoAfterBuf = NULL;
26 static int lzoAfterBufLen = 0;
29 * rfbSendOneRectEncodingZlib - send a given rectangle using one Zlib
33 #define MAX_WRKMEM ((LZO1X_1_MEM_COMPRESS) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t)
35 void rfbUltraCleanup(rfbScreenInfoPtr screen)
37 if (lzoBeforeBufSize) {
41 if (lzoAfterBufSize) {
47 void rfbFreeUltraData(rfbClientPtr cl) {
48 if (cl->compStreamInitedLZO) {
50 cl->compStreamInitedLZO=FALSE;
56 rfbSendOneRectEncodingUltra(rfbClientPtr cl,
62 rfbFramebufferUpdateRectHeader rect;
66 char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y)
67 + (x * (cl->scaledScreen->bitsPerPixel / 8)));
72 maxRawSize = (w * h * (cl->format.bitsPerPixel / 8));
74 if (lzoBeforeBufSize < maxRawSize) {
75 lzoBeforeBufSize = maxRawSize;
76 if (lzoBeforeBuf == NULL)
77 lzoBeforeBuf = (char *)malloc(lzoBeforeBufSize);
79 lzoBeforeBuf = (char *)realloc(lzoBeforeBuf, lzoBeforeBufSize);
83 * lzo requires output buffer to be slightly larger than the input
84 * buffer, in the worst case.
86 maxCompSize = (maxRawSize + maxRawSize / 16 + 64 + 3);
88 if (lzoAfterBufSize < maxCompSize) {
89 lzoAfterBufSize = maxCompSize;
90 if (lzoAfterBuf == NULL)
91 lzoAfterBuf = (char *)malloc(lzoAfterBufSize);
93 lzoAfterBuf = (char *)realloc(lzoAfterBuf, lzoAfterBufSize);
97 * Convert pixel data to client format.
99 (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,
100 &cl->format, fbptr, lzoBeforeBuf,
101 cl->scaledScreen->paddedWidthInBytes, w, h);
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.
108 cl->lzoWrkMem = malloc(sizeof(lzo_align_t) * (((LZO1X_1_MEM_COMPRESS) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t)));
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 */
115 /* Find the total size of the resulting compressed data. */
116 lzoAfterBufLen = maxCompSize;
118 if ( deflateResult != LZO_E_OK ) {
119 rfbErr("lzo deflation error: %d\n", deflateResult);
124 rfbStatRecordEncodingSent(cl, rfbEncodingUltra, sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader + lzoAfterBufLen, maxRawSize);
126 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
129 if (!rfbSendUpdateBuf(cl))
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);
139 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
140 sz_rfbFramebufferUpdateRectHeader);
141 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
143 hdr.nBytes = Swap32IfLE(lzoAfterBufLen);
145 memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbZlibHeader);
146 cl->ublen += sz_rfbZlibHeader;
148 /* We might want to try sending the data directly... */
149 for (i = 0; i < lzoAfterBufLen;) {
151 int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
153 if (i + bytesToCopy > lzoAfterBufLen) {
154 bytesToCopy = lzoAfterBufLen - i;
157 memcpy(&cl->updateBuf[cl->ublen], &lzoAfterBuf[i], bytesToCopy);
159 cl->ublen += bytesToCopy;
162 if (cl->ublen == UPDATE_BUF_SIZE) {
163 if (!rfbSendUpdateBuf(cl))
173 * rfbSendRectEncodingUltra - send a given rectangle using one or more
174 * LZO encoding rectangles.
178 rfbSendRectEncodingUltra(rfbClientPtr cl,
186 rfbRectangle partialRect;
193 /* Determine maximum pixel/scan lines allowed per rectangle. */
194 maxLines = ( ULTRA_MAX_SIZE(w) / w );
196 /* Initialize number of scan lines left to do. */
199 /* Loop until all work is done. */
200 while ( linesRemaining > 0 ) {
204 if ( maxLines < linesRemaining )
205 linesToComp = maxLines;
207 linesToComp = linesRemaining;
209 partialRect.h = linesToComp;
211 /* Encode (compress) and send the next rectangle. */
212 if ( ! rfbSendOneRectEncodingUltra( cl,
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
229 * Since, lzo is most useful for slow networks, this flush
230 * is appropriate for the desired behavior of the lzo encoding.
232 if (( cl->ublen > 0 ) &&
233 ( linesToComp == maxLines )) {
234 if (!rfbSendUpdateBuf(cl)) {
240 /* Update remaining and incremental rectangle location. */
241 linesRemaining -= linesToComp;
242 partialRect.y += linesToComp;