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