From ffe09d68f578f6765ed73f3b2bf9d4ea37a0b66b Mon Sep 17 00:00:00 2001 From: DRC Date: Wed, 17 Aug 2011 02:27:59 +0000 Subject: [PATCH] Further optimizations to the Tight encoder to eliminate getImage() overhead. The encoder now directly accesses the framebuffer for solid rectangle computation, JPEG encoding, and color counting (if pixel translation is not required.) Also moved everything in tightEncode.h into the TightEncoder class to eliminate all of the static mess (this will be important later on if we decide to multi-thread the encoder.) git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4631 3789f03b-4d11-0410-bbf8-ca57d06f2519 --- common/rfb/Encoder.h | 4 +- common/rfb/HextileEncoder.cxx | 3 +- common/rfb/HextileEncoder.h | 2 +- common/rfb/JpegCompressor.cxx | 9 +- common/rfb/JpegCompressor.h | 2 +- common/rfb/PixelBuffer.h | 3 +- common/rfb/PixelFormat.cxx | 46 ++++ common/rfb/PixelFormat.h | 3 + common/rfb/PixelTransformer.cxx | 6 + common/rfb/PixelTransformer.h | 4 + common/rfb/RREEncoder.cxx | 2 +- common/rfb/RREEncoder.h | 2 +- common/rfb/RawEncoder.cxx | 2 +- common/rfb/RawEncoder.h | 2 +- common/rfb/SMsgWriter.cxx | 6 +- common/rfb/SMsgWriter.h | 6 +- common/rfb/TightEncoder.cxx | 95 ++++--- common/rfb/TightEncoder.h | 89 ++++++- common/rfb/TransImageGetter.cxx | 10 +- common/rfb/TransImageGetter.h | 5 + common/rfb/ZRLEEncoder.cxx | 2 +- common/rfb/ZRLEEncoder.h | 2 +- common/rfb/tightEncode.h | 428 ++++++++++++++++++-------------- 23 files changed, 460 insertions(+), 273 deletions(-) diff --git a/common/rfb/Encoder.h b/common/rfb/Encoder.h index 2a6e2f6b..893c0138 100644 --- a/common/rfb/Encoder.h +++ b/common/rfb/Encoder.h @@ -20,6 +20,7 @@ #include #include +#include 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); diff --git a/common/rfb/HextileEncoder.cxx b/common/rfb/HextileEncoder.cxx index ba71d56d..73f1f575 100644 --- a/common/rfb/HextileEncoder.cxx +++ b/common/rfb/HextileEncoder.cxx @@ -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(); diff --git a/common/rfb/HextileEncoder.h b/common/rfb/HextileEncoder.h index c78107a4..6b89643d 100644 --- a/common/rfb/HextileEncoder.h +++ b/common/rfb/HextileEncoder.h @@ -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); diff --git a/common/rfb/JpegCompressor.cxx b/common/rfb/JpegCompressor.cxx index e203560a..a55fee7e 100644 --- a/common/rfb/JpegCompressor.cxx +++ b/common/rfb/JpegCompressor.cxx @@ -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) diff --git a/common/rfb/JpegCompressor.h b/common/rfb/JpegCompressor.h index 5a9c2fd5..6860b415 100644 --- a/common/rfb/JpegCompressor.h +++ b/common/rfb/JpegCompressor.h @@ -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); diff --git a/common/rfb/PixelBuffer.h b/common/rfb/PixelBuffer.h index 4a13923c..fc35a7d7 100644 --- a/common/rfb/PixelBuffer.h +++ b/common/rfb/PixelBuffer.h @@ -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); } diff --git a/common/rfb/PixelFormat.cxx b/common/rfb/PixelFormat.cxx index 11c2d7ab..013cceb2 100644 --- a/common/rfb/PixelFormat.cxx +++ b/common/rfb/PixelFormat.cxx @@ -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 diff --git a/common/rfb/PixelFormat.h b/common/rfb/PixelFormat.h index c1de09a9..6566e38b 100644 --- a/common/rfb/PixelFormat.h +++ b/common/rfb/PixelFormat.h @@ -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); diff --git a/common/rfb/PixelTransformer.cxx b/common/rfb/PixelTransformer.cxx index ea43d9c7..c737f4d9 100644 --- a/common/rfb/PixelTransformer.cxx +++ b/common/rfb/PixelTransformer.cxx @@ -1,5 +1,6 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright 2011 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 @@ -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; +} diff --git a/common/rfb/PixelTransformer.h b/common/rfb/PixelTransformer.h index 54b05a5b..a368b63a 100644 --- a/common/rfb/PixelTransformer.h +++ b/common/rfb/PixelTransformer.h @@ -1,5 +1,6 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright 2011 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 @@ -20,6 +21,7 @@ #ifndef __RFB_PIXELTRANSFORMER_H__ #define __RFB_PIXELTRANSFORMER_H__ +#include #include #include @@ -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; diff --git a/common/rfb/RREEncoder.cxx b/common/rfb/RREEncoder.cxx index b000e9d3..1b86986f 100644 --- a/common/rfb/RREEncoder.cxx +++ b/common/rfb/RREEncoder.cxx @@ -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(); diff --git a/common/rfb/RREEncoder.h b/common/rfb/RREEncoder.h index 1281410d..6178d57f 100644 --- a/common/rfb/RREEncoder.h +++ b/common/rfb/RREEncoder.h @@ -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); diff --git a/common/rfb/RawEncoder.cxx b/common/rfb/RawEncoder.cxx index a2545b61..5612cb8d 100644 --- a/common/rfb/RawEncoder.cxx +++ b/common/rfb/RawEncoder.cxx @@ -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; diff --git a/common/rfb/RawEncoder.h b/common/rfb/RawEncoder.h index 1b9ad929..34dba0b5 100644 --- a/common/rfb/RawEncoder.h +++ b/common/rfb/RawEncoder.h @@ -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); diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx index 2262be09..f0a97c59 100644 --- a/common/rfb/SMsgWriter.cxx +++ b/common/rfb/SMsgWriter.cxx @@ -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 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); diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h index 007d7580..8112d010 100644 --- a/common/rfb/SMsgWriter.h +++ b/common/rfb/SMsgWriter.h @@ -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); diff --git a/common/rfb/TightEncoder.cxx b/common/rfb/TightEncoder.cxx index 52673a6d..fa7ee9a7 100644 --- a/common/rfb/TightEncoder.cxx +++ b/common/rfb/TightEncoder.cxx @@ -17,7 +17,6 @@ * USA. */ #include -#include #include #include #include @@ -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 #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); diff --git a/common/rfb/TightEncoder.h b/common/rfb/TightEncoder.h index 064a8343..ae9672c0 100644 --- a/common/rfb/TightEncoder.h +++ b/common/rfb/TightEncoder.h @@ -22,6 +22,7 @@ #include #include #include +#include #include // 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[]; diff --git a/common/rfb/TransImageGetter.cxx b/common/rfb/TransImageGetter.cxx index f4154554..e0c60a40 100644 --- a/common/rfb/TransImageGetter.cxx +++ b/common/rfb/TransImageGetter.cxx @@ -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); } - diff --git a/common/rfb/TransImageGetter.h b/common/rfb/TransImageGetter.h index 7942247a..8fde743b 100644 --- a/common/rfb/TransImageGetter.h +++ b/common/rfb/TransImageGetter.h @@ -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_; } diff --git a/common/rfb/ZRLEEncoder.cxx b/common/rfb/ZRLEEncoder.cxx index ef0dd9f5..a83d79f3 100644 --- a/common/rfb/ZRLEEncoder.cxx +++ b/common/rfb/ZRLEEncoder.cxx @@ -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(); diff --git a/common/rfb/ZRLEEncoder.h b/common/rfb/ZRLEEncoder.h index 7768917d..3a0f52a9 100644 --- a/common/rfb/ZRLEEncoder.h +++ b/common/rfb/ZRLEEncoder.h @@ -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 diff --git a/common/rfb/tightEncode.h b/common/rfb/tightEncode.h index d4c8f6e3..9b2b29d1 100644 --- a/common/rfb/tightEncode.h +++ b/common/rfb/tightEncode.h @@ -26,8 +26,6 @@ // GET_IMAGE_INTO_BUF - gets a rectangle of pixel data into a buffer // -#include -#include #include 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 } -- 2.39.5