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