]> source.dussan.org Git - tigervnc.git/commitdiff
Further optimizations to the Tight encoder to eliminate getImage() overhead. The...
authorDRC <dcommander@users.sourceforge.net>
Wed, 17 Aug 2011 02:27:59 +0000 (02:27 +0000)
committerDRC <dcommander@users.sourceforge.net>
Wed, 17 Aug 2011 02:27:59 +0000 (02:27 +0000)
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4631 3789f03b-4d11-0410-bbf8-ca57d06f2519

23 files changed:
common/rfb/Encoder.h
common/rfb/HextileEncoder.cxx
common/rfb/HextileEncoder.h
common/rfb/JpegCompressor.cxx
common/rfb/JpegCompressor.h
common/rfb/PixelBuffer.h
common/rfb/PixelFormat.cxx
common/rfb/PixelFormat.h
common/rfb/PixelTransformer.cxx
common/rfb/PixelTransformer.h
common/rfb/RREEncoder.cxx
common/rfb/RREEncoder.h
common/rfb/RawEncoder.cxx
common/rfb/RawEncoder.h
common/rfb/SMsgWriter.cxx
common/rfb/SMsgWriter.h
common/rfb/TightEncoder.cxx
common/rfb/TightEncoder.h
common/rfb/TransImageGetter.cxx
common/rfb/TransImageGetter.h
common/rfb/ZRLEEncoder.cxx
common/rfb/ZRLEEncoder.h
common/rfb/tightEncode.h

index 2a6e2f6bc15bbf1341e7964f821fc4261f597fcb..893c013800cca57767759fde24b8dbd426ccfb3b 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <rfb/Rect.h>
 #include <rfb/encodings.h>
+#include <rfb/TransImageGetter.h>
 
 namespace rfb {
   class SMsgWriter;
@@ -38,7 +39,8 @@ namespace rfb {
     // writeRect() tries to write the given rectangle.  If it is unable to
     // write the whole rectangle it returns false and sets actual to the actual
     // rectangle which was updated.
-    virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual)=0;
+    virtual bool writeRect(const Rect& r, TransImageGetter* ig,
+                           Rect* actual)=0;
 
     static bool supported(int encoding);
     static Encoder* createEncoder(int encoding, SMsgWriter* writer);
index ba71d56d95b0efef990b41ff8b675285a45caa5c..73f1f5751441d9b0c7631d2af1490c027a061b35 100644 (file)
@@ -58,7 +58,8 @@ HextileEncoder::~HextileEncoder()
 {
 }
 
-bool HextileEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+bool HextileEncoder::writeRect(const Rect& r, TransImageGetter* ig,
+                               Rect* actual)
 {
   writer->startRect(r, encodingHextile);
   rdr::OutStream* os = writer->getOutStream();
index c78107a4cf1bd929003bee9702a6f99025e0b863..6b89643dd969b01c37e2a3f3f352b6705e13b332 100644 (file)
@@ -25,7 +25,7 @@ namespace rfb {
   class HextileEncoder : public Encoder {
   public:
     static Encoder* create(SMsgWriter* writer);
-    virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+    virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual);
     virtual ~HextileEncoder();
   private:
     HextileEncoder(SMsgWriter* writer);
index e203560a4c27c3122dd6a90e5bec3ba463331d24..a55fee7ed735081dfc21225737de0431df25a13e 100644 (file)
@@ -114,7 +114,7 @@ JpegCompressor::~JpegCompressor(void)
   jpeg_destroy_compress(&cinfo);
 }
 
-void JpegCompressor::compress(rdr::U8 *buf, const Rect& r,
+void JpegCompressor::compress(rdr::U8 *buf, int pitch, const Rect& r,
   const PixelFormat& pf, int quality, JPEG_SUBSAMP subsamp)
 {
   int w = r.width();
@@ -168,10 +168,13 @@ void JpegCompressor::compress(rdr::U8 *buf, const Rect& r,
   }
 #endif
 
+  if (pitch == 0) pitch = w * pixelsize;
+
   if (cinfo.in_color_space == JCS_RGB) {
     srcBuf = new rdr::U8[w * h * pixelsize];
     srcBufIsTemp = true;
-    pf.rgbFromBuffer(srcBuf, (const rdr::U8 *)buf, w * h);
+    pf.rgbFromBuffer(srcBuf, (const rdr::U8 *)buf, w, pitch, h);
+    pitch = w * pixelsize;
   }
 
   cinfo.input_components = pixelsize;
@@ -197,7 +200,7 @@ void JpegCompressor::compress(rdr::U8 *buf, const Rect& r,
 
   rowPointer = new JSAMPROW[h];
   for (int dy = 0; dy < h; dy++)
-    rowPointer[dy] = (JSAMPROW)(&srcBuf[dy * w * pixelsize]);
+    rowPointer[dy] = (JSAMPROW)(&srcBuf[dy * pitch]);
 
   jpeg_start_compress(&cinfo, TRUE);
   while (cinfo.next_scanline < cinfo.image_height)
index 5a9c2fd58d88b0575a16456f4418e170eab0fc8b..6860b415d0bbd4ade6385fe65256ae409aae5215 100644 (file)
@@ -63,7 +63,7 @@ namespace rfb {
     JpegCompressor(int bufferLen = 128*1024);
     virtual ~JpegCompressor();
 
-    void compress(rdr::U8 *, const Rect&, const PixelFormat&, int,
+    void compress(rdr::U8 *, int, const Rect&, const PixelFormat&, int,
       JPEG_SUBSAMP);
 
     void writeBytes(const void*, int);
index 4a13923c5b469ff9b8ce2b797860797ae5155425..fc35a7d7142f46138bb98d4b0c332a9aab3c6766 100644 (file)
@@ -68,6 +68,7 @@ namespace rfb {
     //   The pointer is to the top-left pixel of the specified Rect.
     //   The buffer stride (in pixels) is returned.
     virtual const rdr::U8* getPixelsR(const Rect& r, int* stride) = 0;
+    virtual rdr::U8* getPixelsRW(const Rect& r, int* stride) = 0;
 
     // Get pixel data for a given part of the buffer
     //   Data is copied into the supplied buffer, with the specified
@@ -107,7 +108,7 @@ namespace rfb {
     virtual int getStride() const;
 
     // Get a pointer to specified pixel data
-    virtual rdr::U8* getPixelsRW(const Rect& r, int* stride);
+    rdr::U8* getPixelsRW(const Rect& r, int* stride);
     virtual const rdr::U8* getPixelsR(const Rect& r, int* stride) {
       return getPixelsRW(r, stride);
     }
index 11c2d7ab548802bed38384474a955e162c000dba..013cceb2c4ae53211aacbaf245b388183f2ea1d6 100644 (file)
@@ -1,5 +1,6 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
  * Copyright 2009 Pierre Ossman for Cendio AB
+ * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -295,6 +296,51 @@ void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int pixels, Co
 }
 
 
+void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src,
+                                int w, int pitch, int h, ColourMap* cm) const
+{
+  rdr::U8 *rowptr, *colptr;
+
+  if (is888()) {
+    // Optimised common case
+    int rindex, gindex, bindex;
+
+    if (bigEndian) {
+      rindex = (24 - redShift)/8;
+      gindex = (24 - greenShift)/8;
+      bindex = (24 - blueShift)/8;
+    } else {
+      rindex = redShift/8;
+      gindex = greenShift/8;
+      bindex = blueShift/8;
+    }
+
+    for(rowptr = (rdr::U8 *)src; rowptr < &src[pitch * h]; rowptr += pitch) {
+      for(colptr = rowptr; colptr < &rowptr[w * 4]; colptr += 4) {
+        *(dst++) = colptr[rindex];
+        *(dst++) = colptr[gindex];
+        *(dst++) = colptr[bindex];
+      }
+    }
+  } else {
+    // Generic code
+    Pixel p;
+    rdr::U8 r, g, b;
+
+    for(rowptr = (rdr::U8 *)src; rowptr < &src[pitch * h]; rowptr += pitch) {
+      for(colptr = rowptr; colptr < &rowptr[w * bpp/8]; colptr += bpp/8) {
+        p = pixelFromBuffer(colptr);
+
+        rgbFromPixel(p, cm, &r, &g, &b);
+        *(dst++) = r;
+        *(dst++) = g;
+        *(dst++) = b;
+      }
+    }
+  }
+}
+
+
 void PixelFormat::print(char* str, int len) const
 {
   // Unfortunately snprintf is not widely available so we build the string up
index c1de09a98bfbee014d2eb14c7dd8519ba198f3d6..6566e38b4b9b3a8d3e7587fbe52924c2f7f654cf 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -59,6 +60,8 @@ namespace rfb {
 
     void rgbFromBuffer(rdr::U16* dst, const rdr::U8* src, int pixels, ColourMap* cm=0) const;
     void rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int pixels, ColourMap* cm=0) const;
+    void rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int w, int pitch,
+                       int h, ColourMap* cm=0) const;
 
     void print(char* str, int len) const;
     bool parse(const char* str);
index ea43d9c73ce1ddcb88f9fbe26d79a49ce9842846..c737f4d9dee94f4029f94131252c3b8e650dec14 100644 (file)
@@ -1,5 +1,6 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
  * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -320,3 +321,8 @@ void PixelTransformer::translateRect(void* inPtr, int inStride,
              outPF, out, outStride,
              inRect.width(), inRect.height());
 }
+
+bool PixelTransformer::willTransform(void)
+{
+  return transFn != NULL && transFn != noTransFn;
+}
index 54b05a5b96b3acf4769223de792108fe4e50c834..a368b63a7dd1e7d986bf8ccddd2bbec349af7b65 100644 (file)
@@ -1,5 +1,6 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
  * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,6 +21,7 @@
 #ifndef __RFB_PIXELTRANSFORMER_H__
 #define __RFB_PIXELTRANSFORMER_H__
 
+#include <stdlib.h>
 #include <rfb/Rect.h>
 #include <rfb/PixelFormat.h>
 
@@ -83,6 +85,8 @@ namespace rfb {
     void translateRect(void* inPtr, int inStride, Rect inRect,
                        void* outPtr, int outStride, Point outCoord) const;
 
+    bool willTransform(void);
+
   private:
     bool economic;
 
index b000e9d3ff3fced127a5248718dd8729d556bffb..1b86986fe061f8cfbfeccc2fa968fbb820ba71a7 100644 (file)
@@ -46,7 +46,7 @@ RREEncoder::~RREEncoder()
 {
 }
 
-bool RREEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+bool RREEncoder::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual)
 {
   int w = r.width();
   int h = r.height();
index 1281410d63047ebbff68f1051d24707a0a5ee016..6178d57f49b774f0113f7b8b111d808757725d61 100644 (file)
@@ -26,7 +26,7 @@ namespace rfb {
   class RREEncoder : public Encoder {
   public:
     static Encoder* create(SMsgWriter* writer);
-    virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+    virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual);
     virtual ~RREEncoder();
   private:
     RREEncoder(SMsgWriter* writer);
index a2545b6163652dda90a38e3bb463a31e776a7ae8..5612cb8d99adad0d504736abb9c3c6221011651c 100644 (file)
@@ -36,7 +36,7 @@ RawEncoder::~RawEncoder()
 {
 }
 
-bool RawEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+bool RawEncoder::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual)
 {
   int x = r.tl.x;
   int y = r.tl.y;
index 1b9ad9294a1075ef46b3a60398e1e7303f636124..34dba0b56a8922189f4ae5befb2d92770e32ac8f 100644 (file)
@@ -25,7 +25,7 @@ namespace rfb {
   class RawEncoder : public Encoder {
   public:
     static Encoder* create(SMsgWriter* writer);
-    virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+    virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual);
     virtual ~RawEncoder();
   private:
     RawEncoder(SMsgWriter* writer);
index 2262be09dccfb99f6f3013e660443e2ae059c2bd..f0a97c595523761a22fa71152699e973f68f760f 100644 (file)
@@ -142,7 +142,7 @@ void SMsgWriter::writeNoDataUpdate()
   vlog.error("writeNoDataUpdate() called");
 }
 
-void SMsgWriter::writeRects(const UpdateInfo& ui, ImageGetter* ig,
+void SMsgWriter::writeRects(const UpdateInfo& ui, TransImageGetter* ig,
                             Region* updatedRegion)
 {
   std::vector<Rect> rects;
@@ -164,13 +164,13 @@ void SMsgWriter::writeRects(const UpdateInfo& ui, ImageGetter* ig,
   }
 }
 
-bool SMsgWriter::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+bool SMsgWriter::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual)
 {
   return writeRect(r, cp->currentEncoding(), ig, actual);
 }
 
 bool SMsgWriter::writeRect(const Rect& r, int encoding,
-                           ImageGetter* ig, Rect* actual)
+                           TransImageGetter* ig, Rect* actual)
 {
   if (!encoders[encoding]) {
     encoders[encoding] = Encoder::createEncoder(encoding, this);
index 007d7580b410526c5432fe5f397194b0f69da681..8112d010734be20c262e56231f0519672d653d50 100644 (file)
@@ -129,7 +129,7 @@ namespace rfb {
     // before the first writeRects() call and writeFrameBufferUpdateEnd() after
     // the last one.  It returns the actual region sent to the client, which
     // may be smaller than the update passed in.
-    virtual void writeRects(const UpdateInfo& update, ImageGetter* ig,
+    virtual void writeRects(const UpdateInfo& update, TransImageGetter* ig,
                             Region* updatedRegion);
 
     // To construct a framebuffer update you can call
@@ -144,9 +144,9 @@ namespace rfb {
     // writeRect() tries to write the given rectangle.  If it is unable to
     // write the whole rectangle it returns false and sets actual to the actual
     // rectangle which was updated.
-    virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+    virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual);
     virtual bool writeRect(const Rect& r, int encoding,
-                           ImageGetter* ig, Rect* actual);
+                           TransImageGetter* ig, Rect* actual);
 
     virtual void writeCopyRect(const Rect& r, int srcX, int srcY);
 
index 52673a6d3cd717d826fa30890bd4f90a4cbc955b..fa7ee9a7491b662fe1b2b5f20f91aeb19e2aa8ee 100644 (file)
@@ -17,7 +17,6 @@
  * USA.
  */
 #include <rdr/OutStream.h>
-#include <rfb/ImageGetter.h>
 #include <rfb/encodings.h>
 #include <rfb/ConnParams.h>
 #include <rfb/SMsgWriter.h>
@@ -77,16 +76,10 @@ const TIGHT_CONF TightEncoder::conf[10] = {
 };
 const int TightEncoder::defaultCompressLevel = 1;
 
-// FIXME: Not good to mirror TightEncoder's members here.
-static const TIGHT_CONF* s_pconf;
-static const TIGHT_CONF* s_pjconf;
-
 //
 // Including BPP-dependent implementation of the encoder.
 //
 
-#define EXTRA_ARGS ImageGetter* ig
-#define GET_IMAGE_INTO_BUF(r,buf) ig->getImage(buf, r);
 #define BPP 8
 #include <rfb/tightEncode.h>
 #undef BPP
@@ -130,21 +123,20 @@ void TightEncoder::setQualityLevel(int level)
   }
 }
 
-bool TightEncoder::checkSolidTile(Rect& r, ImageGetter *ig, rdr::U32* colorPtr,
+bool TightEncoder::checkSolidTile(Rect& r, rdr::U32* colorPtr,
                                   bool needSameColor)
 {
-  switch (writer->bpp()) {
+  switch (serverpf.bpp) {
   case 32:
-    return checkSolidTile32(r, ig, writer, colorPtr, needSameColor);
+    return checkSolidTile32(r, colorPtr, needSameColor);
   case 16:
-    return checkSolidTile16(r, ig, writer, colorPtr, needSameColor);
+    return checkSolidTile16(r, colorPtr, needSameColor);
   default:
-    return checkSolidTile8(r, ig, writer, colorPtr, needSameColor);
+    return checkSolidTile8(r, colorPtr, needSameColor);
   }
 }
 
-void TightEncoder::findBestSolidArea(Rect& r, ImageGetter *ig,
-                                     rdr::U32 colorValue, Rect& bestr)
+void TightEncoder::findBestSolidArea(Rect& r, rdr::U32 colorValue, Rect& bestr)
 {
   int dx, dy, dw, dh;
   int w_prev;
@@ -164,16 +156,16 @@ void TightEncoder::findBestSolidArea(Rect& r, ImageGetter *ig,
       TIGHT_MAX_SPLIT_TILE_SIZE : w_prev;
 
     sr.setXYWH(r.tl.x, dy, dw, dh);
-    if (!checkSolidTile(sr, ig, &colorValue, true))
+    if (!checkSolidTile(sr, &colorValue, true))
       break;
 
     for (dx = r.tl.x + dw; dx < r.tl.x + w_prev;) {
       dw = (dx + TIGHT_MAX_SPLIT_TILE_SIZE <= r.tl.x + w_prev) ?
         TIGHT_MAX_SPLIT_TILE_SIZE : (r.tl.x + w_prev - dx);
       sr.setXYWH(dx, dy, dw, dh);
-      if (!checkSolidTile(sr, ig, &colorValue, true))
+      if (!checkSolidTile(sr, &colorValue, true))
         break;
-           dx += dw;
+      dx += dw;
     }
 
     w_prev = dx - r.tl.x;
@@ -187,8 +179,8 @@ void TightEncoder::findBestSolidArea(Rect& r, ImageGetter *ig,
   bestr.br.y = bestr.tl.y + h_best;
 }
 
-void TightEncoder::extendSolidArea(const Rect& r, ImageGetter *ig,
-                                   rdr::U32 colorValue, Rect& er)
+void TightEncoder::extendSolidArea(const Rect& r, rdr::U32 colorValue,
+                                   Rect& er)
 {
   int cx, cy;
   Rect sr;
@@ -196,7 +188,7 @@ void TightEncoder::extendSolidArea(const Rect& r, ImageGetter *ig,
   // Try to extend the area upwards.
   for (cy = er.tl.y - 1; ; cy--) {
     sr.setXYWH(er.tl.x, cy, er.width(), 1);
-    if (cy < r.tl.y || !checkSolidTile(sr, ig, &colorValue, true))
+    if (cy < r.tl.y || !checkSolidTile(sr, &colorValue, true))
       break;
   }
   er.tl.y = cy + 1;
@@ -204,7 +196,7 @@ void TightEncoder::extendSolidArea(const Rect& r, ImageGetter *ig,
   // ... downwards.
   for (cy = er.br.y; ; cy++) {
     sr.setXYWH(er.tl.x, cy, er.width(), 1);
-    if (cy >= r.br.y || !checkSolidTile(sr, ig, &colorValue, true))
+    if (cy >= r.br.y || !checkSolidTile(sr, &colorValue, true))
       break;
   }
   er.br.y = cy;
@@ -212,7 +204,7 @@ void TightEncoder::extendSolidArea(const Rect& r, ImageGetter *ig,
   // ... to the left.
   for (cx = er.tl.x - 1; ; cx--) {
     sr.setXYWH(cx, er.tl.y, 1, er.height());
-    if (cx < r.tl.x || !checkSolidTile(sr, ig, &colorValue, true))
+    if (cx < r.tl.x || !checkSolidTile(sr, &colorValue, true))
       break;
   }
   er.tl.x = cx + 1;
@@ -220,7 +212,7 @@ void TightEncoder::extendSolidArea(const Rect& r, ImageGetter *ig,
   // ... to the right.
   for (cx = er.br.x; ; cx++) {
     sr.setXYWH(cx, er.tl.y, 1, er.height());
-    if (cx >= r.br.x || !checkSolidTile(sr, ig, &colorValue, true))
+    if (cx >= r.br.x || !checkSolidTile(sr, &colorValue, true))
       break;
   }
   er.br.x = cx;
@@ -254,7 +246,7 @@ int TightEncoder::getNumRects(const Rect &r)
           ((h - 1) / subrectMaxHeight + 1));
 }
 
-void TightEncoder::sendRectSimple(const Rect& r, ImageGetter* ig)
+void TightEncoder::sendRectSimple(const Rect& r)
 {
   // Shortcuts to rectangle coordinates and dimensions.
   const int x = r.tl.x;
@@ -265,7 +257,7 @@ void TightEncoder::sendRectSimple(const Rect& r, ImageGetter* ig)
   // Encode small rects as is.
   bool rectTooBig = w > pconf->maxRectWidth || w * h > pconf->maxRectSize;
   if (!rectTooBig) {
-    writeSubrect(r, ig);
+    writeSubrect(r);
     return;
   }
 
@@ -283,14 +275,18 @@ void TightEncoder::sendRectSimple(const Rect& r, ImageGetter* ig)
       sw = (dx + pconf->maxRectWidth < w) ? pconf->maxRectWidth : w - dx;
       sh = (dy + subrectMaxHeight < h) ? subrectMaxHeight : h - dy;
       sr.setXYWH(x + dx, y + dy, sw, sh);
-      writeSubrect(sr, ig);
+      writeSubrect(sr);
     }
   }
 }
 
-bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual)
+bool TightEncoder::writeRect(const Rect& _r, TransImageGetter* _ig,
+                             Rect* actual)
 {
+  ig = _ig;
+  serverpf = ig->getPixelBuffer()->getPF();
   ConnParams* cp = writer->getConnParams();
+  clientpf = cp->pf();
 
   // Shortcuts to rectangle coordinates and dimensions.
   Rect r = _r;
@@ -299,13 +295,9 @@ bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual)
   unsigned int w = r.width();
   unsigned int h = r.height();
 
-  // Copy members of current TightEncoder instance to static variables.
-  s_pconf = pconf;
-  s_pjconf = pjconf;
-
   // Encode small rects as is.
   if (!cp->supportsLastRect || w * h < TIGHT_MIN_SPLIT_RECT_SIZE) {
-    sendRectSimple(r, ig);
+    sendRectSimple(r);
     return true;
   }
 
@@ -313,10 +305,10 @@ bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual)
   Rect sr, bestr;
   unsigned int dx, dy, dw, dh;
   rdr::U32 colorValue;
-  int maxRectSize = s_pconf->maxRectSize;
-  int maxRectWidth = s_pconf->maxRectWidth;
+  int maxRectSize = pconf->maxRectSize;
+  int maxRectWidth = pconf->maxRectWidth;
   int nMaxWidth = (w > maxRectWidth) ? maxRectWidth : w;
-  int nMaxRows = s_pconf->maxRectSize / nMaxWidth;
+  int nMaxRows = pconf->maxRectSize / nMaxWidth;
 
   // Try to find large solid-color areas and send them separately.
   for (dy = y; dy < y + h; dy += TIGHT_MAX_SPLIT_TILE_SIZE) {
@@ -324,7 +316,7 @@ bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual)
     // If a rectangle becomes too large, send its upper part now.
     if (dy - y >= nMaxRows) {
       sr.setXYWH(x, y, w, nMaxRows);
-      sendRectSimple(sr, ig);
+      sendRectSimple(sr);
       r.tl.y += nMaxRows;
       y = r.tl.y;
       h = r.height();
@@ -339,11 +331,11 @@ bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual)
         TIGHT_MAX_SPLIT_TILE_SIZE : (x + w - dx);
  
       sr.setXYWH(dx, dy, dw, dh);
-      if (checkSolidTile(sr, ig, &colorValue, false)) {
+      if (checkSolidTile(sr, &colorValue, false)) {
 
         // Get dimensions of solid-color area.
         sr.setXYWH(dx, dy, r.br.x - dx, r.br.y - dy);
-        findBestSolidArea(sr, ig, colorValue, bestr);
+        findBestSolidArea(sr, colorValue, bestr);
 
         // Make sure a solid rectangle is large enough
         // (or the whole rectangle is of the same color).
@@ -352,30 +344,30 @@ bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual)
           continue;
 
         // Try to extend solid rectangle to maximum size.
-        extendSolidArea(r, ig, colorValue, bestr);
+        extendSolidArea(r, colorValue, bestr);
  
         // Send rectangles at top and left to solid-color area.
         if (bestr.tl.y != y) {
           sr.setXYWH(x, y, w, bestr.tl.y - y);
-          sendRectSimple(sr, ig);
+          sendRectSimple(sr);
         }
         if (bestr.tl.x != x) {
           sr.setXYWH(x, bestr.tl.y, bestr.tl.x - x, bestr.height());
-          writeRect(sr, ig, NULL);
+          writeRect(sr, _ig, NULL);
         }
 
         // Send solid-color rectangle.
-        writeSubrect(bestr, ig, true);
+        writeSubrect(bestr, true);
 
         // Send remaining rectangles (at right and bottom).
         if (bestr.br.x != r.br.x) {
           sr.setXYWH(bestr.br.x, bestr.tl.y, r.br.x - bestr.br.x,
             bestr.height());
-          writeRect(sr, ig, NULL);
+          writeRect(sr, _ig, NULL);
         }
         if (bestr.br.y != r.br.y) {
           sr.setXYWH(x, bestr.br.y, w, r.br.y - bestr.br.y);
-          writeRect(sr, ig, NULL);
+          writeRect(sr, _ig, NULL);
         }
 
         return true;
@@ -384,24 +376,21 @@ bool TightEncoder::writeRect(const Rect& _r, ImageGetter* ig, Rect* actual)
   }
 
   // No suitable solid-color rectangles found.
-  sendRectSimple(r, ig);
+  sendRectSimple(r);
   return true;
 }
 
-void TightEncoder::writeSubrect(const Rect& r, ImageGetter* ig,
-  bool forceSolid)
+void TightEncoder::writeSubrect(const Rect& r, bool forceSolid)
 {
-  rdr::U8* imageBuf = writer->getImageBuf(r.area());
-  ConnParams* cp = writer->getConnParams();
   mos.clear();
 
-  switch (writer->bpp()) {
+  switch (clientpf.bpp) {
   case 8:
-    tightEncode8(r, &mos, zos, jc, imageBuf, cp, ig, forceSolid);  break;
+    tightEncode8(r, &mos, forceSolid);  break;
   case 16:
-    tightEncode16(r, &mos, zos, jc, imageBuf, cp, ig, forceSolid); break;
+    tightEncode16(r, &mos, forceSolid); break;
   case 32:
-    tightEncode32(r, &mos, zos, jc, imageBuf, cp, ig, forceSolid); break;
+    tightEncode32(r, &mos, forceSolid); break;
   }
 
   writer->startRect(r, encodingTight);
index 064a8343e1078ee8ce6ef37bfdb6eabb94f7f37a..ae9672c048e25fe2f7365a9c191ee5024a4771d5 100644 (file)
@@ -22,6 +22,7 @@
 #include <rdr/MemOutStream.h>
 #include <rdr/ZlibOutStream.h>
 #include <rfb/JpegCompressor.h>
+#include <rfb/TransImageGetter.h>
 #include <rfb/Encoder.h>
 
 // FIXME: Check if specifying extern "C" is really necessary.
@@ -42,6 +43,28 @@ namespace rfb {
     JPEG_SUBSAMP jpegSubSample;
   };
 
+  //
+  // C-style structures to store palette entries and compression paramentes.
+  // Such code probably should be converted into C++ classes.
+  //
+
+  struct TIGHT_COLOR_LIST {
+    TIGHT_COLOR_LIST *next;
+    int idx;
+    rdr::U32 rgb;
+  };
+
+  struct TIGHT_PALETTE_ENTRY {
+    TIGHT_COLOR_LIST *listNode;
+    int numPixels;
+  };
+
+  struct TIGHT_PALETTE {
+    TIGHT_PALETTE_ENTRY entry[256];
+    TIGHT_COLOR_LIST *hash[256];
+    TIGHT_COLOR_LIST list[256];
+  };
+
   //
   // Compression level stuff. The following array contains various
   // encoder parameters for each of 10 compression levels (0..9).
@@ -59,24 +82,72 @@ namespace rfb {
     virtual void setCompressLevel(int level);
     virtual void setQualityLevel(int level);
     virtual int getNumRects(const Rect &r);
-    virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+    virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual);
     virtual ~TightEncoder();
 
   private:
     TightEncoder(SMsgWriter* writer);
-    bool checkSolidTile(Rect& r, ImageGetter *ig, rdr::U32* colorPtr,
-                        bool needSameColor);
-    void extendSolidArea(const Rect& r, ImageGetter *ig,
-                         rdr::U32 colorValue, Rect& er);
-    void findBestSolidArea(Rect& r, ImageGetter* ig, rdr::U32 colorValue,
-                           Rect& bestr);
-    void sendRectSimple(const Rect& r, ImageGetter* ig);
-    void writeSubrect(const Rect& r, ImageGetter* ig, bool forceSolid = false);
+    bool checkSolidTile(Rect& r, rdr::U32* colorPtr, bool needSameColor);
+    void extendSolidArea(const Rect& r, rdr::U32 colorValue, Rect& er);
+    void findBestSolidArea(Rect& r, rdr::U32 colorValue, Rect& bestr);
+    void sendRectSimple(const Rect& r);
+    void writeSubrect(const Rect& r, bool forceSolid = false);
+
+    void compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos,
+                      const void *buf, unsigned int length, int zlibLevel);
+
+    int paletteInsert(rdr::U32 rgb, int numPixels, int bpp);
+    void paletteReset(void);
+
+    void fastFillPalette8(const Rect &r, rdr::U8 *data, int stride);
+    void fastFillPalette16(const Rect &r, rdr::U16 *data, int stride);
+    void fastFillPalette32(const Rect &r, rdr::U32 *data, int stride);
+
+    void fillPalette8(rdr::U8 *data, int count);
+    void fillPalette16(rdr::U16 *data, int count);
+    void fillPalette32(rdr::U32 *data, int count);
+
+    unsigned int packPixels8(rdr::U8 *buf, unsigned int count);
+    unsigned int packPixels16(rdr::U16 *buf, unsigned int count);
+    unsigned int packPixels32(rdr::U32 *buf, unsigned int count);
+
+    void tightEncode8(const Rect& r, rdr::OutStream *os, bool forceSolid);
+    void tightEncode16(const Rect& r, rdr::OutStream *os, bool forceSolid);
+    void tightEncode32(const Rect& r, rdr::OutStream *os, bool forceSolid);
+
+    bool checkSolidTile8(Rect& r, rdr::U32 *colorPtr, bool needSameColor);
+    bool checkSolidTile16(Rect& r, rdr::U32 *colorPtr, bool needSameColor);
+    bool checkSolidTile32(Rect& r, rdr::U32 *colorPtr, bool needSameColor);
+
+    void encodeSolidRect8(rdr::OutStream *os, rdr::U8 *buf);
+    void encodeSolidRect16(rdr::OutStream *os, rdr::U16 *buf);
+    void encodeSolidRect32(rdr::OutStream *os, rdr::U32 *buf);
+
+    void encodeFullColorRect8(rdr::OutStream *os, rdr::U8 *buf, const Rect& r);
+    void encodeFullColorRect16(rdr::OutStream *os, rdr::U16 *buf, const Rect& r);
+    void encodeFullColorRect32(rdr::OutStream *os, rdr::U32 *buf, const Rect& r);
+
+    void encodeMonoRect8(rdr::OutStream *os, rdr::U8 *buf, const Rect& r);
+    void encodeMonoRect16(rdr::OutStream *os, rdr::U16 *buf, const Rect& r);
+    void encodeMonoRect32(rdr::OutStream *os, rdr::U32 *buf, const Rect& r);
+
+    void encodeIndexedRect16(rdr::OutStream *os, rdr::U16 *buf, const Rect& r);
+    void encodeIndexedRect32(rdr::OutStream *os, rdr::U32 *buf, const Rect& r);
+
+    void encodeJpegRect16(rdr::OutStream *os, rdr::U16 *buf, int, const Rect& r);
+    void encodeJpegRect32(rdr::OutStream *os, rdr::U32 *buf, int, const Rect& r);
 
     SMsgWriter* writer;
     rdr::MemOutStream mos;
     rdr::ZlibOutStream zos[4];
     JpegCompressor jc;
+    TransImageGetter *ig;
+    PixelFormat serverpf, clientpf;
+
+    bool pack24;
+    int palMaxColors, palNumColors;
+    rdr::U32 monoBackground, monoForeground;
+    TIGHT_PALETTE palette;
 
     static const int defaultCompressLevel;
     static const TIGHT_CONF conf[];
index f415455492244f0013f5c25246089c03e990a8bb..e0c60a40582b54200e8b7535d655b10295488f2b 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -55,6 +56,14 @@ void TransImageGetter::setColourMapEntries(int firstCol, int nCols)
   PixelTransformer::setColourMapEntries(firstCol, nCols);
 }
 
+rdr::U8 *TransImageGetter::getPixelsRW(const Rect &r, int *stride)
+{
+  if (!offset.equals(Point(0, 0)))
+    return pb->getPixelsRW(r.translate(offset.negate()), stride);
+  else
+    return pb->getPixelsRW(r, stride);
+}
+
 void TransImageGetter::getImage(void* outPtr, const Rect& r, int outStride)
 {
   int inStride;
@@ -77,4 +86,3 @@ void TransImageGetter::cmCallback(int firstColour, int nColours,
   if (self->writer)
     self->writer->writeSetColourMapEntries(firstColour, nColours, cm);
 }
-
index 7942247a97d9b8821f8dbd06e18050f4e0360fd6..8fde743b1a7a6c391d27be81dcf2f047f40d3d7e 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -71,11 +72,15 @@ namespace rfb {
     // padding will be outStride-r.width() pixels).
     void getImage(void* outPtr, const Rect& r, int outStride=0);
 
+    rdr::U8 *getPixelsRW(const Rect &r, int *stride);
+
     // setPixelBuffer() changes the pixel buffer to be used.  The new pixel
     // buffer MUST have the same pixel format as the old one - if not you
     // should call init() instead.
     void setPixelBuffer(PixelBuffer* pb_) { pb = pb_; }
 
+    PixelBuffer *getPixelBuffer(void) { return pb; }
+
     // setOffset() sets an offset which is subtracted from the coordinates of
     // the rectangle given to getImage().
     void setOffset(const Point& offset_) { offset = offset_; }
index ef0dd9f55ddf33c5cf16446ce86a8f3fc39521a8..a83d79f3b87d29ffc6190626020d532a422a6d77 100644 (file)
@@ -69,7 +69,7 @@ ZRLEEncoder::~ZRLEEncoder()
     delete mos;
 }
 
-bool ZRLEEncoder::writeRect(const Rect& r, ImageGetter* ig, Rect* actual)
+bool ZRLEEncoder::writeRect(const Rect& r, TransImageGetter* ig, Rect* actual)
 {
   rdr::U8* imageBuf = writer->getImageBuf(64 * 64 * 4 + 4);
   mos->clear();
index 7768917d1fca34e21d00883ec4aa9ee7c79d0996..3a0f52a9697d15e4b73311bf265c1017f3fd99fc 100644 (file)
@@ -27,7 +27,7 @@ namespace rfb {
   class ZRLEEncoder : public Encoder {
   public:
     static Encoder* create(SMsgWriter* writer);
-    virtual bool writeRect(const Rect& r, ImageGetter* ig, Rect* actual);
+    virtual bool writeRect(const Rect& r, TransImageGetter* ig, Rect* actual);
     virtual ~ZRLEEncoder();
 
     // setMaxLen() sets the maximum size in bytes of any ZRLE rectangle.  This
index d4c8f6e35adb33b8e527538f5905beac9e1e71f0..9b2b29d1c7d878a6342793964d5e383a6b1ed835 100644 (file)
@@ -26,8 +26,6 @@
 // GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer
 //
 
-#include <rdr/OutStream.h>
-#include <rdr/ZlibOutStream.h>
 #include <assert.h>
 
 namespace rfb {
@@ -40,65 +38,21 @@ namespace rfb {
 #endif
 
 #define PIXEL_T rdr::CONCAT2E(U,BPP)
-#define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
-#define TIGHT_ENCODE CONCAT2E(tightEncode,BPP)
-#define SWAP_PIXEL CONCAT2E(SWAP,BPP)
+#define TIGHT_ENCODE TightEncoder::CONCAT2E(tightEncode,BPP)
 #define HASH_FUNCTION CONCAT2E(HASH_FUNC,BPP)
-#define PACK_PIXELS CONCAT2E(packPixels,BPP)
-#define ENCODE_SOLID_RECT CONCAT2E(encodeSolidRect,BPP)
-#define ENCODE_FULLCOLOR_RECT CONCAT2E(encodeFullColorRect,BPP)
-#define ENCODE_MONO_RECT CONCAT2E(encodeMonoRect,BPP)
-#define ENCODE_INDEXED_RECT CONCAT2E(encodeIndexedRect,BPP)
-#define ENCODE_JPEG_RECT CONCAT2E(encodeJpegRect,BPP)
-#define FILL_PALETTE CONCAT2E(fillPalette,BPP)
-#define CHECK_SOLID_TILE CONCAT2E(checkSolidTile,BPP)
+#define PACK_PIXELS TightEncoder::CONCAT2E(packPixels,BPP)
+#define ENCODE_SOLID_RECT TightEncoder::CONCAT2E(encodeSolidRect,BPP)
+#define ENCODE_FULLCOLOR_RECT TightEncoder::CONCAT2E(encodeFullColorRect,BPP)
+#define ENCODE_MONO_RECT TightEncoder::CONCAT2E(encodeMonoRect,BPP)
+#define ENCODE_INDEXED_RECT TightEncoder::CONCAT2E(encodeIndexedRect,BPP)
+#define ENCODE_JPEG_RECT TightEncoder::CONCAT2E(encodeJpegRect,BPP)
+#define FAST_FILL_PALETTE TightEncoder::CONCAT2E(fastFillPalette,BPP)
+#define FILL_PALETTE TightEncoder::CONCAT2E(fillPalette,BPP)
+#define CHECK_SOLID_TILE TightEncoder::CONCAT2E(checkSolidTile,BPP)
 
 #ifndef TIGHT_ONCE
 #define TIGHT_ONCE
 
-//
-// C-style structures to store palette entries and compression paramentes.
-// Such code probably should be converted into C++ classes.
-//
-
-struct TIGHT_COLOR_LIST {
-  TIGHT_COLOR_LIST *next;
-  int idx;
-  rdr::U32 rgb;
-};
-
-struct TIGHT_PALETTE_ENTRY {
-  TIGHT_COLOR_LIST *listNode;
-  int numPixels;
-};
-
-struct TIGHT_PALETTE {
-  TIGHT_PALETTE_ENTRY entry[256];
-  TIGHT_COLOR_LIST *hash[256];
-  TIGHT_COLOR_LIST list[256];
-};
-
-// FIXME: Is it really a good idea to use static variables for this?
-static bool s_pack24;             // use 24-bit packing for 32-bit pixels
-
-// FIXME: Make a separate class for palette operations.
-static int s_palMaxColors, s_palNumColors;
-static rdr::U32 s_monoBackground, s_monoForeground;
-static TIGHT_PALETTE s_palette;
-
-//
-// Swapping bytes in pixels.
-// FIXME: Use a sort of ImageGetter that does not convert pixel format?
-//
-
-#ifndef SWAP16
-#define SWAP16(n) ((((n) & 0xff) << 8) | (((n) >> 8) & 0xff))
-#endif
-#ifndef SWAP32
-#define SWAP32(n) (((n) >> 24) | (((n) & 0x00ff0000) >> 8) | \
-                   (((n) & 0x0000ff00) << 8) | ((n) << 24))
-#endif
-
 //
 // Functions to operate on palette structures.
 //
@@ -106,13 +60,13 @@ static TIGHT_PALETTE s_palette;
 #define HASH_FUNC16(rgb) ((int)(((rgb >> 8) + rgb) & 0xFF))
 #define HASH_FUNC32(rgb) ((int)(((rgb >> 16) + (rgb >> 8)) & 0xFF))
 
-static void paletteReset(void)
+void TightEncoder::paletteReset(void)
 {
-  s_palNumColors = 0;
-  memset(s_palette.hash, 0, 256 * sizeof(TIGHT_COLOR_LIST *));
+  palNumColors = 0;
+  memset(palette.hash, 0, 256 * sizeof(TIGHT_COLOR_LIST *));
 }
 
-static int paletteInsert(rdr::U32 rgb, int numPixels, int bpp)
+int TightEncoder::paletteInsert(rdr::U32 rgb, int numPixels, int bpp)
 {
   TIGHT_COLOR_LIST *pnode;
   TIGHT_COLOR_LIST *prev_pnode = NULL;
@@ -120,59 +74,59 @@ static int paletteInsert(rdr::U32 rgb, int numPixels, int bpp)
 
   hash_key = (bpp == 16) ? HASH_FUNC16(rgb) : HASH_FUNC32(rgb);
 
-  pnode = s_palette.hash[hash_key];
+  pnode = palette.hash[hash_key];
 
   while (pnode != NULL) {
     if (pnode->rgb == rgb) {
       // Such palette entry already exists.
       new_idx = idx = pnode->idx;
-      count = s_palette.entry[idx].numPixels + numPixels;
-      if (new_idx && s_palette.entry[new_idx-1].numPixels < count) {
+      count = palette.entry[idx].numPixels + numPixels;
+      if (new_idx && palette.entry[new_idx-1].numPixels < count) {
         do {
-          s_palette.entry[new_idx] = s_palette.entry[new_idx-1];
-          s_palette.entry[new_idx].listNode->idx = new_idx;
+          palette.entry[new_idx] = palette.entry[new_idx-1];
+          palette.entry[new_idx].listNode->idx = new_idx;
           new_idx--;
         }
         while (new_idx &&
-          s_palette.entry[new_idx-1].numPixels < count);
-        s_palette.entry[new_idx].listNode = pnode;
+          palette.entry[new_idx-1].numPixels < count);
+        palette.entry[new_idx].listNode = pnode;
         pnode->idx = new_idx;
       }
-      s_palette.entry[new_idx].numPixels = count;
-      return s_palNumColors;
+      palette.entry[new_idx].numPixels = count;
+      return palNumColors;
     }
     prev_pnode = pnode;
     pnode = pnode->next;
   }
 
   // Check if palette is full.
-  if ( s_palNumColors == 256 || s_palNumColors == s_palMaxColors ) {
-    s_palNumColors = 0;
+  if ( palNumColors == 256 || palNumColors == palMaxColors ) {
+    palNumColors = 0;
     return 0;
   }
 
   // Move palette entries with lesser pixel counts.
-  for ( idx = s_palNumColors;
-  idx > 0 && s_palette.entry[idx-1].numPixels < numPixels;
+  for ( idx = palNumColors;
+  idx > 0 && palette.entry[idx-1].numPixels < numPixels;
   idx-- ) {
-    s_palette.entry[idx] = s_palette.entry[idx-1];
-    s_palette.entry[idx].listNode->idx = idx;
+    palette.entry[idx] = palette.entry[idx-1];
+    palette.entry[idx].listNode->idx = idx;
   }
 
   // Add new palette entry into the freed slot.
-  pnode = &s_palette.list[s_palNumColors];
+  pnode = &palette.list[palNumColors];
   if (prev_pnode != NULL) {
     prev_pnode->next = pnode;
   } else {
-    s_palette.hash[hash_key] = pnode;
+    palette.hash[hash_key] = pnode;
   }
   pnode->next = NULL;
   pnode->idx = idx;
   pnode->rgb = rgb;
-  s_palette.entry[idx].listNode = pnode;
-  s_palette.entry[idx].numPixels = numPixels;
+  palette.entry[idx].listNode = pnode;
+  palette.entry[idx].numPixels = numPixels;
 
-  return (++s_palNumColors);
+  return (++palNumColors);
 }
 
 //
@@ -180,16 +134,16 @@ static int paletteInsert(rdr::U32 rgb, int numPixels, int bpp)
 // size is less than TIGHT_MIN_TO_COMPRESS bytes.
 //
 
-static void compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos,
-                         const void *buf, const PixelFormat& pf,
-                         unsigned int length, int zlibLevel)
+void TightEncoder::compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos,
+                                const void *buf, unsigned int length,
+                                int zlibLevel)
 {
   if (length < TIGHT_MIN_TO_COMPRESS) {
     os->writeBytes(buf, length);
   } else {
     // FIXME: Using a temporary MemOutStream may be not efficient.
     //        Maybe use the same static object used in the JPEG coder?
-    int maxBeforeSize = s_pconf->maxRectSize * (pf.bpp / 8);
+    int maxBeforeSize = pconf->maxRectSize * (clientpf.bpp / 8);
     int maxAfterSize = maxBeforeSize + (maxBeforeSize + 99) / 100 + 12;
     rdr::MemOutStream mem_os(maxAfterSize);
     zos->setUnderlying(&mem_os);
@@ -204,41 +158,25 @@ static void compressData(rdr::OutStream *os, rdr::ZlibOutStream *zos,
 
 #endif  // #ifndef TIGHT_ONCE
 
-static void ENCODE_SOLID_RECT     (rdr::OutStream *os,
-                                   PIXEL_T *buf, const PixelFormat& pf);
-static void ENCODE_FULLCOLOR_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
-                                   PIXEL_T *buf, const PixelFormat& pf, const Rect& r);
-static void ENCODE_MONO_RECT      (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
-                                   PIXEL_T *buf, const PixelFormat& pf, const Rect& r);
-#if (BPP != 8)
-static void ENCODE_INDEXED_RECT   (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
-                                   PIXEL_T *buf, const PixelFormat& pf, const Rect& r);
-static void ENCODE_JPEG_RECT      (rdr::OutStream *os, JpegCompressor& jc,
-                                   PIXEL_T *buf, const PixelFormat& pf, const Rect& r);
-#endif
-
-static void FILL_PALETTE (PIXEL_T *data, int count);
-
 //
 // Convert 32-bit color samples into 24-bit colors, in place.
 // Performs packing only when redMax, greenMax and blueMax are all 255.
 // Color components are assumed to be byte-aligned.
 //
 
-static inline unsigned int PACK_PIXELS (PIXEL_T *buf, unsigned int count,
-                                        const PixelFormat& pf)
+unsigned int PACK_PIXELS (PIXEL_T *buf, unsigned int count)
 {
 #if (BPP != 32)
   return count * sizeof(PIXEL_T);
 #else
-  if (!s_pack24)
+  if (!pack24)
     return count * sizeof(PIXEL_T);
 
   rdr::U32 pix;
   rdr::U8 *dst = (rdr::U8 *)buf;
   for (unsigned int i = 0; i < count; i++) {
     pix = *buf++;
-    pf.rgbFromBuffer(dst, (rdr::U8*)&pix, 1, NULL);
+    clientpf.rgbFromBuffer(dst, (rdr::U8*)&pix, 1, NULL);
     dst += 3;
   }
   return count * 3;
@@ -249,64 +187,67 @@ static inline unsigned int PACK_PIXELS (PIXEL_T *buf, unsigned int count,
 // Main function of the Tight encoder
 //
 
-void TIGHT_ENCODE (const Rect& r, rdr::OutStream *os,
-                  rdr::ZlibOutStream zos[4], JpegCompressor &jc, void* buf,
-                  ConnParams* cp
-#ifdef EXTRA_ARGS
-                  , EXTRA_ARGS,
-#endif
-                  bool forceSolid)
+void TIGHT_ENCODE (const Rect& r, rdr::OutStream *os, bool forceSolid)
 {
-  const PixelFormat& pf = cp->pf();
-  if(forceSolid) {
-    GET_IMAGE_INTO_BUF(Rect(r.tl.x, r.tl.y, r.tl.x + 1, r.tl.y + 1), buf);
-  }
-  else {
-    GET_IMAGE_INTO_BUF(r, buf);
-  }
-  PIXEL_T* pixels = (PIXEL_T*)buf;
+  int stride = r.width();
+  PIXEL_T *pixels = (PIXEL_T *)ig->getPixelsRW(r, &stride);
 
 #if (BPP == 32)
   // Check if it's necessary to pack 24-bit pixels, and
   // compute appropriate shift values if necessary.
-  s_pack24 = pf.is888();
+  pack24 = clientpf.is888();
 #endif
 
   if (forceSolid)
-    s_palNumColors = 1;
+    palNumColors = 1;
   else {
-    s_palMaxColors = r.area() / s_pconf->idxMaxColorsDivisor;
-    if (s_pjconf != NULL) s_palMaxColors = s_pconf->palMaxColorsWithJPEG;
-    if (s_palMaxColors < 2 && r.area() >= s_pconf->monoMinRectSize) {
-      s_palMaxColors = 2;
+    palMaxColors = r.area() / pconf->idxMaxColorsDivisor;
+    if (pjconf != NULL) palMaxColors = pconf->palMaxColorsWithJPEG;
+    if (palMaxColors < 2 && r.area() >= pconf->monoMinRectSize) {
+      palMaxColors = 2;
     }
 
-    FILL_PALETTE(pixels, r.area());
+    if (clientpf.equal(serverpf) && clientpf.bpp >= 16) {
+      // This is so we can avoid translating the pixels when compressing
+      // with JPEG, since it is unnecessary
+      FAST_FILL_PALETTE(r, pixels, stride);
+      if(palNumColors != 0 || pjconf == NULL) {
+        pixels = (PIXEL_T *)writer->getImageBuf(r.area());
+        stride = r.width();
+        ig->getImage(pixels, r);
+      }
+    }
+    else {
+      pixels = (PIXEL_T *)writer->getImageBuf(r.area());
+      stride = r.width();
+      ig->getImage(pixels, r);
+      FILL_PALETTE(pixels, r.area());
+    }
   }
 
-  switch (s_palNumColors) {
+  switch (palNumColors) {
   case 0:
     // Truecolor image
 #if (BPP != 8)
-    if (s_pjconf != NULL) {
-      ENCODE_JPEG_RECT(os, jc, pixels, pf, r);
+    if (pjconf != NULL) {
+      ENCODE_JPEG_RECT(os, pixels, stride, r);
       break;
     }
 #endif
-    ENCODE_FULLCOLOR_RECT(os, zos, pixels, pf, r);
+    ENCODE_FULLCOLOR_RECT(os, pixels, r);
     break;
   case 1:
     // Solid rectangle
-    ENCODE_SOLID_RECT(os, pixels, pf);
+    ENCODE_SOLID_RECT(os, pixels);
     break;
   case 2:
     // Two-color rectangle
-    ENCODE_MONO_RECT(os, zos, pixels, pf, r);
+    ENCODE_MONO_RECT(os, pixels, r);
     break;
 #if (BPP != 8)
   default:
     // Up to 256 different colors
-    ENCODE_INDEXED_RECT(os, zos, pixels, pf, r);
+    ENCODE_INDEXED_RECT(os, pixels, r);
 #endif
   }
 }
@@ -315,35 +256,33 @@ void TIGHT_ENCODE (const Rect& r, rdr::OutStream *os,
 // Subencoding implementations.
 //
 
-static void ENCODE_SOLID_RECT (rdr::OutStream *os, PIXEL_T *buf, const PixelFormat& pf)
+void ENCODE_SOLID_RECT (rdr::OutStream *os, PIXEL_T *buf)
 {
   os->writeU8(0x08 << 4);
 
-  int length = PACK_PIXELS(buf, 1, pf);
+  int length = PACK_PIXELS(buf, 1);
   os->writeBytes(buf, length);
 }
 
-static void ENCODE_FULLCOLOR_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
-                                   PIXEL_T *buf, const PixelFormat& pf, const Rect& r)
+void ENCODE_FULLCOLOR_RECT (rdr::OutStream *os, PIXEL_T *buf, const Rect& r)
 {
   const int streamId = 0;
   os->writeU8(streamId << 4);
 
-  int length = PACK_PIXELS(buf, r.area(), pf);
-  compressData(os, &zos[streamId], buf, pf, length, s_pconf->rawZlibLevel);
+  int length = PACK_PIXELS(buf, r.area());
+  compressData(os, &zos[streamId], buf, length, pconf->rawZlibLevel);
 }
 
-static void ENCODE_MONO_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
-                              PIXEL_T *buf, const PixelFormat& pf, const Rect& r)
+void ENCODE_MONO_RECT (rdr::OutStream *os, PIXEL_T *buf, const Rect& r)
 {
   const int streamId = 1;
   os->writeU8((streamId | 0x04) << 4);
   os->writeU8(0x01);
 
   // Write the palette
-  PIXEL_T pal[2] = { (PIXEL_T)s_monoBackground, (PIXEL_T)s_monoForeground };
+  PIXEL_T pal[2] = { (PIXEL_T)monoBackground, (PIXEL_T)monoForeground };
   os->writeU8(1);
-  os->writeBytes(pal, PACK_PIXELS(pal, 2, pf));
+  os->writeBytes(pal, PACK_PIXELS(pal, 2));
 
   // Encode the data in-place
   PIXEL_T *src = buf;
@@ -355,7 +294,7 @@ static void ENCODE_MONO_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
   int aligned_width;
   int x, y, bg_bits;
 
-  bg = (PIXEL_T) s_monoBackground;
+  bg = (PIXEL_T) monoBackground;
   aligned_width = w - w % 8;
 
   for (y = 0; y < h; y++) {
@@ -396,12 +335,11 @@ static void ENCODE_MONO_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
   // Write the data
   int length = (w + 7) / 8;
   length *= h;
-  compressData(os, &zos[streamId], buf, pf, length, s_pconf->monoZlibLevel);
+  compressData(os, &zos[streamId], buf, length, pconf->monoZlibLevel);
 }
 
 #if (BPP != 8)
-static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
-                                 PIXEL_T *buf, const PixelFormat& pf, const Rect& r)
+void ENCODE_INDEXED_RECT (rdr::OutStream *os, PIXEL_T *buf, const Rect& r)
 {
   const int streamId = 2;
   os->writeU8((streamId | 0x04) << 4);
@@ -410,10 +348,10 @@ static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
   // Write the palette
   {
     PIXEL_T pal[256];
-    for (int i = 0; i < s_palNumColors; i++)
-      pal[i] = (PIXEL_T)s_palette.entry[i].listNode->rgb;
-    os->writeU8((rdr::U8)(s_palNumColors - 1));
-    os->writeBytes(pal, PACK_PIXELS(pal, s_palNumColors, pf));
+    for (int i = 0; i < palNumColors; i++)
+      pal[i] = (PIXEL_T)palette.entry[i].listNode->rgb;
+    os->writeU8((rdr::U8)(palNumColors - 1));
+    os->writeBytes(pal, PACK_PIXELS(pal, palNumColors));
   }
 
   // Encode data in-place
@@ -429,7 +367,7 @@ static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
     while (count && *src == rgb) {
       rep++, src++, count--;
     }
-    pnode = s_palette.hash[HASH_FUNCTION(rgb)];
+    pnode = palette.hash[HASH_FUNCTION(rgb)];
     while (pnode != NULL) {
       if ((PIXEL_T)pnode->rgb == rgb) {
         *dst++ = (rdr::U8)pnode->idx;
@@ -444,7 +382,7 @@ static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
   }
 
   // Write the data
-  compressData(os, &zos[streamId], buf, pf, r.area(), s_pconf->idxZlibLevel);
+  compressData(os, &zos[streamId], buf, r.area(), pconf->idxZlibLevel);
 }
 #endif  // #if (BPP != 8)
 
@@ -453,13 +391,12 @@ static void ENCODE_INDEXED_RECT (rdr::OutStream *os, rdr::ZlibOutStream zos[4],
 //
 
 #if (BPP != 8)
-static void ENCODE_JPEG_RECT (rdr::OutStream *os, JpegCompressor& jc,
-                              PIXEL_T *buf, const PixelFormat& pf,
-                              const Rect& r)
+void ENCODE_JPEG_RECT (rdr::OutStream *os, PIXEL_T *buf, int stride,
+                       const Rect& r)
 {
   jc.clear();
-  jc.compress((rdr::U8 *)buf, r, pf, s_pjconf->jpegQuality,
-    s_pjconf->jpegSubSample);
+  jc.compress((rdr::U8 *)buf, stride * serverpf.bpp / 8, r, serverpf,
+    pjconf->jpegQuality, pjconf->jpegSubSample);
   os->writeU8(0x09 << 4);
   os->writeCompactLength(jc.length());
   os->writeBytes(jc.data(), jc.length());
@@ -471,21 +408,22 @@ static void ENCODE_JPEG_RECT (rdr::OutStream *os, JpegCompressor& jc,
 //
 
 #if (BPP == 8)
-static void FILL_PALETTE (PIXEL_T *data, int count)
+
+void FILL_PALETTE (PIXEL_T *data, int count)
 {
   PIXEL_T c0, c1;
   int i, n0, n1;
 
-  s_palNumColors = 0;
+  palNumColors = 0;
 
   c0 = data[0];
   for (i = 1; i < count && data[i] == c0; i++);
   if (i == count) {
-    s_palNumColors = 1;
+    palNumColors = 1;
     return;                       // Solid rectangle
   }
 
-  if (s_palMaxColors < 2)
+  if (palMaxColors < 2)
     return;
 
   n0 = i;
@@ -501,17 +439,23 @@ static void FILL_PALETTE (PIXEL_T *data, int count)
   }
   if (i == count) {
     if (n0 > n1) {
-      s_monoBackground = (rdr::U32)c0;
-      s_monoForeground = (rdr::U32)c1;
+      monoBackground = (rdr::U32)c0;
+      monoForeground = (rdr::U32)c1;
     } else {
-      s_monoBackground = (rdr::U32)c1;
-      s_monoForeground = (rdr::U32)c0;
+      monoBackground = (rdr::U32)c1;
+      monoForeground = (rdr::U32)c0;
     }
-    s_palNumColors = 2;           // Two colors
+    palNumColors = 2;           // Two colors
   }
 }
+
+void FAST_FILL_PALETTE (const Rect& r, PIXEL_T *data, int stride)
+{
+}
+
 #else   // (BPP != 8)
-static void FILL_PALETTE (PIXEL_T *data, int count)
+
+void FILL_PALETTE (PIXEL_T *data, int count)
 {
   PIXEL_T c0, c1, ci = 0;
   int i, n0, n1, ni;
@@ -519,12 +463,12 @@ static void FILL_PALETTE (PIXEL_T *data, int count)
   c0 = data[0];
   for (i = 1; i < count && data[i] == c0; i++);
   if (i >= count) {
-    s_palNumColors = 1;           // Solid rectangle
+    palNumColors = 1;           // Solid rectangle
     return;
   }
 
-  if (s_palMaxColors < 2) {
-    s_palNumColors = 0;           // Full-color format preferred
+  if (palMaxColors < 2) {
+    palNumColors = 0;           // Full-color format preferred
     return;
   }
 
@@ -542,13 +486,13 @@ static void FILL_PALETTE (PIXEL_T *data, int count)
   }
   if (i >= count) {
     if (n0 > n1) {
-      s_monoBackground = (rdr::U32)c0;
-      s_monoForeground = (rdr::U32)c1;
+      monoBackground = (rdr::U32)c0;
+      monoForeground = (rdr::U32)c1;
     } else {
-      s_monoBackground = (rdr::U32)c1;
-      s_monoForeground = (rdr::U32)c0;
+      monoBackground = (rdr::U32)c1;
+      monoForeground = (rdr::U32)c0;
     }
-    s_palNumColors = 2;           // Two colors
+    palNumColors = 2;           // Two colors
     return;
   }
 
@@ -569,32 +513,137 @@ static void FILL_PALETTE (PIXEL_T *data, int count)
   }
   paletteInsert (ci, (rdr::U32)ni, BPP);
 }
+
+void FAST_FILL_PALETTE (const Rect& r, PIXEL_T *data, int stride)
+{
+  PIXEL_T c0, c1, ci = 0, mask, c0t, c1t, cit;
+  int n0, n1, ni;
+  int w = r.width(), h = r.height();
+  PIXEL_T *rowptr, *colptr, *rowptr2, *colptr2, *dataend = &data[stride * h];
+  bool willTransform = ig->willTransform();
+
+  if (willTransform) {
+    mask = serverpf.redMax << serverpf.redShift;
+    mask |= serverpf.greenMax << serverpf.greenShift;
+    mask |= serverpf.blueMax << serverpf.blueShift;
+  }
+  else mask = ~0;
+
+  c0 = data[0] & mask;
+  n0 = 0;
+  for (rowptr = data; rowptr < dataend; rowptr += stride) {
+    for (colptr = rowptr; colptr < &rowptr[w]; colptr++) {
+      if (((*colptr) & mask) != c0)
+        goto soliddone;
+      n0++;
+    }
+  }
+
+  soliddone:
+  if (rowptr >= dataend) {
+    palNumColors = 1;           // Solid rectangle
+    return;
+  }
+  if (palMaxColors < 2) {
+    palNumColors = 0;           // Full-color format preferred
+    return;
+  }
+
+  c1 = *colptr & mask;
+  n1 = 0;
+  colptr++;
+  if (colptr >= &rowptr[w]) {
+    rowptr += stride;  colptr = rowptr;
+  }
+  colptr2 = colptr;
+  for (rowptr2 = rowptr; rowptr2 < dataend;) {
+    for (; colptr2 < &rowptr2[w]; colptr2++) {
+      ci = (*colptr2) & mask;
+      if (ci == c0) {
+        n0++;
+      } else if (ci == c1) {
+        n1++;
+      } else
+        goto monodone;
+    }
+    rowptr2 += stride;
+    colptr2 = rowptr2;
+  }
+
+  monodone:
+  if (willTransform) {
+    ig->translateRect(&c0, 1, Rect(0, 0, 1, 1), &c0t, 1, Point(0, 0));
+    ig->translateRect(&c1, 1, Rect(0, 0, 1, 1), &c1t, 1, Point(0, 0));
+  }
+  else {
+    c0t = c0;  c1t = c1;
+  }
+
+  if (colptr2 >= dataend) {
+    if (n0 > n1) {
+      monoBackground = (rdr::U32)c0t;
+      monoForeground = (rdr::U32)c1t;
+    } else {
+      monoBackground = (rdr::U32)c1t;
+      monoForeground = (rdr::U32)c0t;
+    }
+    palNumColors = 2;           // Two colors
+    return;
+  }
+
+  paletteReset();
+  paletteInsert (c0t, (rdr::U32)n0, BPP);
+  paletteInsert (c1t, (rdr::U32)n1, BPP);
+
+  ni = 1;
+  colptr2++;
+  if (colptr2 >= &rowptr2[w]) {
+    rowptr2 += stride;  colptr2 = rowptr2;
+  }
+  colptr = colptr2;
+  for (rowptr = rowptr2; rowptr < dataend;) {
+    for (; colptr < &rowptr[w]; colptr++) {
+      if (((*colptr) & mask) == ci) {
+        ni++;
+      } else {
+        if (willTransform)
+          ig->translateRect(&ci, 1, Rect(0, 0, 1, 1), &cit, 1, Point(0, 0));
+        else
+          cit = ci;
+        if (!paletteInsert (cit, (rdr::U32)ni, BPP))
+          return;
+        ci = (*colptr) & mask;
+        ni = 1;
+      }
+    }
+    rowptr += stride;
+    colptr = rowptr;
+  }
+  ig->translateRect(&ci, 1, Rect(0, 0, 1, 1), &cit, 1, Point(0, 0));
+  paletteInsert (cit, (rdr::U32)ni, BPP);
+}
+
 #endif  // #if (BPP == 8)
 
-bool CHECK_SOLID_TILE(Rect& r, ImageGetter* ig, SMsgWriter* writer,
-                      rdr::U32 *colorPtr, bool needSameColor)
+bool CHECK_SOLID_TILE(Rect& r, rdr::U32 *colorPtr, bool needSameColor)
 {
-  PIXEL_T *buf;
-  PIXEL_T colorValue;
+  PIXEL_T *buf, colorValue;
   int dx, dy;
-  Rect sr;
+  int w = r.width(), h = r.height();
 
-  buf = (PIXEL_T *)writer->getImageBuf(r.area());
-  sr.setXYWH(r.tl.x, r.tl.y, 1, 1);
-  GET_IMAGE_INTO_BUF(sr, buf);
+  int stride = w;
+  buf = (PIXEL_T *)ig->getPixelsRW(r, &stride);
 
   colorValue = *buf;
   if (needSameColor && (rdr::U32)colorValue != *colorPtr)
     return false;
 
-  for (dy = 0; dy < r.height(); dy++) {
-    Rect sr;
-    sr.setXYWH(r.tl.x, r.tl.y + dy, r.width(), 1);
-    GET_IMAGE_INTO_BUF(sr, buf);
-    for (dx = 0; dx < r.width(); dx++) {
+  for (dy = 0; dy < h; dy++) {
+    for (dx = 0; dx < w; dx++) {
       if (colorValue != buf[dx])
         return false;
     }
+    buf += stride;
   }
 
   *colorPtr = (rdr::U32)colorValue;
@@ -602,9 +651,7 @@ bool CHECK_SOLID_TILE(Rect& r, ImageGetter* ig, SMsgWriter* writer,
 }
 
 #undef PIXEL_T
-#undef WRITE_PIXEL
 #undef TIGHT_ENCODE
-#undef SWAP_PIXEL
 #undef HASH_FUNCTION
 #undef PACK_PIXELS
 #undef ENCODE_SOLID_RECT
@@ -612,6 +659,7 @@ bool CHECK_SOLID_TILE(Rect& r, ImageGetter* ig, SMsgWriter* writer,
 #undef ENCODE_MONO_RECT
 #undef ENCODE_INDEXED_RECT
 #undef ENCODE_JPEG_RECT
+#undef FAST_FILL_PALETTE
 #undef FILL_PALETTE
 #undef CHECK_SOLID_TILE
 }